java 多头的算术题
Arithmetic problems with java longs
我有两个等式:x * x - D * y * y = 1
和 x = sqrt(1 + D * y * y)
。
两者都是对方的代数运算。
给定 D,我需要求解 x 的最小整数值,使 y 也是整数。我遍历可能的 y 值,将它们代入第二个等式并测试 x 是否为整数。如果是,我return 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,请改用第一个等式。如果 x 是整数,则 x^2 也将是整数;如果 x 不是整数,那么 x^2 也不会是整数,只要您使用的 BigDecimals 具有足够的数学尺度而不是双倍数。
这种丢番图方程称为佩尔方程。
Wiki.
Mathworld.
两个链接都包含线索 - 如何使用连分数求解这个方程。
我认为应用一些数学而不是蛮力会很好/
注意 'double' 中的精度。
根据 IEEE 754-1985,双精度提供 16 位数字(绝对精确为 15,9)。
例如
a) SQRT(112331965515990542) 是
335159611.99999999701634694576505237017910
其中,当转换为 double 时,给出 3.3515961199999999E8
b) SQRT(112331965515990543)
335159611.99999999850817347288252618840968
其中,当转换为 double 时,给出 3.3515961199999999E8。
因此,根据 IEEE 754-1985 定义,这些值是相等的。
显然,任何进一步的 logical/mathematical 检查一般来说都是不准确的。
为了克服这个限制,我推荐来自 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
我有两个等式:x * x - D * y * y = 1
和 x = sqrt(1 + D * y * y)
。
两者都是对方的代数运算。
给定 D,我需要求解 x 的最小整数值,使 y 也是整数。我遍历可能的 y 值,将它们代入第二个等式并测试 x 是否为整数。如果是,我return 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,请改用第一个等式。如果 x 是整数,则 x^2 也将是整数;如果 x 不是整数,那么 x^2 也不会是整数,只要您使用的 BigDecimals 具有足够的数学尺度而不是双倍数。
这种丢番图方程称为佩尔方程。
Wiki.
Mathworld.
两个链接都包含线索 - 如何使用连分数求解这个方程。
我认为应用一些数学而不是蛮力会很好/
注意 'double' 中的精度。
根据 IEEE 754-1985,双精度提供 16 位数字(绝对精确为 15,9)。
例如 a) SQRT(112331965515990542) 是
335159611.99999999701634694576505237017910
其中,当转换为 double 时,给出 3.3515961199999999E8
b) SQRT(112331965515990543)
335159611.99999999850817347288252618840968
其中,当转换为 double 时,给出 3.3515961199999999E8。 因此,根据 IEEE 754-1985 定义,这些值是相等的。 显然,任何进一步的 logical/mathematical 检查一般来说都是不准确的。
为了克服这个限制,我推荐来自 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