java longs的算术问题

时间:2016-04-28 01:00:02

标签: java math floating-point arithmetic-expressions

我有两个等式:x * x - D * y * y = 1x = sqrt(1 + D * y * y)。 两者都是另一方的代数操纵。

给定D,我需要求解x的最小整数值,以便y也是一个整数。我遍历可能的y值,将它们插入第二个等式并测试x是否为整数。如果是,我会返回x。

我遇到的问题是当x,y和D插入第一个等式时,它不等于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 :(得分:1)

这种丢番图方程被称为Pell方程 Wiki
Mathworld

这两个链接都包含线索 - 如何使用连续分数来解决这个等式。

我认为应用一些数学而不是brutforce /

会很好

答案 1 :(得分:1)

请注意双重'

中的精确度

根据IEEE 754-1985,双精度提供16位数字(159绝对精确)。

E.g。 a)SQRT(112331965515990542)

335159611.99999999701634694576505237017910

当转换为double时,给出3.3515961199999999E8

b)SQRT(112331965515990543)

335159611.99999999850817347288252618840968

当转换为double时,给出3.3515961199999999E8。 因此,根据IEEE 754-1985定义,这些值是相等的。 显然,任何进一步的逻辑/数学检查一般来说都是不准确的。

为克服此限制,我建议使用www.javasoft.ch

中的BigMath包
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

答案 2 :(得分:0)

如果问题是sqrt,请改用第一个等式。如果x是整数,则x ^ 2也将是整数;如果x不是整数,则x ^ 2也不是整数,只要你使用的BigDecimals具有足够的数学量级而不是双倍。