2016-04-28 2 views
0

У меня есть два уравнения: x * x - D * y * y = 1 и x = sqrt(1 + D * y * y). Оба являются алгебраическими манипуляциями с другими.Арифметические проблемы с java longs

Учитывая D, мне нужно решить для наименьшего целочисленного значения x, так что y также является целым числом. Я прокручиваю возможные значения y, подключаю их во второе уравнение и проверяю, является ли x целым. Если это так, я возвращаю x.

У меня есть проблема, когда х, у, и D подключены к 1 уравнения, не равно 1.

Вот некоторые проблемные значения:

1. x=335159612 y=42912791 D=61 
2. x=372326272 y=35662389 D=109 

Интуиция является то, что Метод java Math.sqrt не вычисляет такое маленькое десятичное число, однако BigDecimal не имеет метода квадратного корня.

Является ли моя математика неправой? Если нет, что я могу сделать, чтобы точно рассчитать x и y?

Редактировать: Вот корень проблемы вместе с методом, который проверяет, является ли double натуральным числом.

public static void main(String[] args){ 
    long x = 335159612, D = 61, y = 42912791; 
    System.out.println(Math.sqrt(D * y * y + 2)); // 3.35159612E8 
    System.out.println(x * x - D * y * y); // 3 
} 

public static boolean isNatural(double d){ 
    return d == (int)d; 
} 
+3

Покажите нам код, который вы используете для проверки целого. –

+0

С одной стороны, 'sqrt (61 * 42912791 * 42912791)' [не является целым числом] (http://www.wolframalpha.com/input/?i=sqrt (61 + * + 42912791 + * + 42912791)) , Если вы храните результат sqrt в длинный, то, конечно, он будет выглядеть как целое число. –

+0

На самом деле покажите нам код, все это или столько, сколько необходимо, чтобы показать проблему. Например, если вы пытаетесь вычислить «42912791 * 42912791» в целых числах, результат будет переполняться. – EJP

ответ

1

Будьте осторожны с точностей в «двойной».

В соответствии с IEEE 754-1985 двойная точность обеспечивает 16 цифр (15,9 для абсолютной точности).

E.g. а) SQRT (112331965515990542) является

335159611.99999999701634694576505237017910 

который, когда превращается в двойной, дает 3.3515961199999999E8

б) SQRT (112331965515990543)

335159611.99999999850817347288252618840968 

который, когда превращается в двойной, дает 3.3515961199999999E8. Так, согласно определению IEEE 754-1985, эти значения равны. Очевидно, что любые дальнейшие логические/математические проверки будут, вообще говоря, неточными.

Чтобы преодолеть это ограничение, я рекомендую пакет BigMath от www.javasoft.ch

import ch.javasoft.math.BigMath; 
import java.math.BigDecimal; 

class Tester { 
    public static void main(String[] args) { 
     long D = 61L, y = 42912791L; 
     double a = Math.sqrt(D * y * y + 1); 
     double b = Math.sqrt(D * y * y + 2); 
     System.out.println(a); 
     System.out.println(b); 
     System.out.println(a == b); 

     BigDecimal bda = BigMath.sqrt(new BigDecimal(D * y * y + 1), 32); 
     BigDecimal bdb = BigMath.sqrt(new BigDecimal(D * y * y + 2), 32); 
     System.out.println(bda.toString()); 
     System.out.println(bdb.toString()); 
     System.out.println(bda.equals(bdb)); 
    } 
} 

Результат:

3.35159612E8 
3.35159612E8 
true 
335159611.99999999701634694576505237017910 
335159611.99999999850817347288252618840968 
false 

P.S. чтобы полностью разрушить вашу веру в стандартных Java математике попробовать это:

System.out.println(0.9200000000000002); 
System.out.println(0.9200000000000001); 

Вы увидите:

0.9200000000000002 
0.9200000000000002 
0

Если sqrt является проблемой, используйте вместо этого первое уравнение. Если x - целое число, x^2 также будет целым числом; если x не является целым числом, то x^2 также не будет целым числом, если вы используете BigDecimals с достаточным масштабом для вашей математики, а не удваиваете.

1

Этот вид диофантовых уравнений известен как уравнения Пелла.
Wiki.
Mathworld.

Обе ссылки содержат подсказки - как решить это уравнение с использованием непрерывных дробей.

Я думаю, что неплохо было бы применить некоторые математику вместо brutforce/

Смежные вопросы