【问题标题】:Arithmetic problems with java longsjava longs的算术问题
【发布时间】:2016-08-22 13:18:36
【问题描述】:

我有两个方程: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?

编辑:这是问题的根源以及测试双精度数是否为自然数的方法。

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;
}

【问题讨论】:

  • 向我们展示您用于测试整数的代码。
  • 一方面,sqrt(61 * 42912791 * 42912791)is not an integer。如果您将 sqrt 的结果存储到 long 中,那么它当然看起来像一个整数。
  • 事实上,向我们展示代码,所有代码,或展示问题所需的代码。例如,如果您尝试以整数计算 42912791 * 42912791,结果将溢出。

标签: java math floating-point arithmetic-expressions


【解决方案1】:

注意 'double' 中的精度。

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

例如 a) SQRT(112331965515990542) 是

335159611.99999999701634694576505237017910

当转换成双精度时,得到 3.3515961199999999E8

b) SQRT(112331965515990543)

335159611.99999999850817347288252618840968

当转换为双精度时,得到 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

附:要彻底毁掉你对标准 Java 数学的信心,试试这个:

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

你会看到:

0.9200000000000002
0.9200000000000002

【讨论】:

    【解决方案2】:

    这种丢番图方程被称为佩尔方程。
    Wiki.
    Mathworld

    两个链接都包含线索 - 如何使用连分数求解此方程。

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

    【讨论】:

      【解决方案3】:

      如果 sqrt 是问题所在,请改用第一个等式。如果 x 是整数,则 x^2 也将是整数;如果 x 不是整数,那么 x^2 也不会是整数,只要您使用的 BigDecimals 具有足够的数学规模而不是双精度数。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-17
        • 2012-04-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-03
        • 2011-10-01
        相关资源
        最近更新 更多