在 C++ 中,该sqrt函数仅对double值进行操作。
如果我们使用整数(unsigned long long),我们可以确定
x == sqrt(x * x)
Run Code Online (Sandbox Code Playgroud)
对于任何积极的x地方x * x <= MAXIMUM_VALUE?
它取决于机器架构和编译器吗?
在 Java 中,Math.sqrt(x)采用双精度值。你说 xx * x在下面Integer.MAX_VALUE。每个整数都可以用 double 完美表示 -double在 java 中被明确定义为带有 52 位尾数的 iEEE-754 风格的 double;因此在 java 中 adouble可以完美地表示 -2^52 和 +2^52 之间的所有整数值,这很容易涵盖所有int值(因为在 java 上定义为有符号 32 位),但它不涵盖所有long值。(定义为有符号的 64 位;64 大于 52,所以不行)。
因此,x * x不损失精度时它结束了从得到转换int到double。然后,Math.sqrt()在这个数字上会给出一个结果,它也可以完美地表示为 a double(因为它是x,并且鉴于它x*x适合 an int,x也必须适合),因此,是的,这将始终适用于所有x。
但是,嘿,为什么不试一试,对吧?
public static void main(String[] args) {
int i = 1;
while (true) {
if (i * i < 0) break;
int j = (int) Math.sqrt(i * i);
if (i != j) System.out.println("Oh dear! " + i + " -> " + j);
i++;
}
System.out.println("Done at " + i);
}
> Done at 46341
Run Code Online (Sandbox Code Playgroud)
因此,通过彻底尝试这一切来证明这一点。
事实证明,没有这样的-任何long值,这样x * x仍然适用(因此,<2^63-1)具有如下性质x == (long) Math.sqrt(x * x);。这大概是因为 at x*x,该数字完全适合 long,即使并非所有这么大的整数都如此。证明:
long p = 2000000000L;
for (; true; p++) {
long pp = p * p;
if (pp < 0) break;
long q = (long) Math.sqrt(pp);
if (q != p) System.out.println("PROBLEM: " + p + " -> " + q);
}
System.out.println("Abort: " + p);
> Abort: 3037000500
Run Code Online (Sandbox Code Playgroud)
当然,如果存在任何不成立的数字,那么在这个高端范围内至少有一个。从 0 开始需要很长时间。
但是我们是否知道 sqrt 总是会返回一个完全平方的精确值,或者它可能有点不准确?
我们应该 - 它是 java。与 C 不同,几乎所有东西都是“明确定义的”,如果 JVM 无法产生指定的确切答案,则它不能合法地称自己为 JVM。Math.sqrt文档提供的余地不足以让任何答案准确x地成为合法实施,因此,是的,这是一个保证。
理论上,JVM 对浮点数有一些非常小的余地,这strictfp会禁用,但 [A] 更多的是使用 80 位寄存器来表示数字而不是 64,这不可能破坏这个假设,[B] 不久前出现了一个java标记问题,表明strictfp对任何硬件和任何 VM 版本都有任何影响,唯一可行的结果是 15 年前不可重现的事情。我非常有信心地说这将始终成立,无论硬件或 VM 版本如何。
| 归档时间: |
|
| 查看次数: |
237 次 |
| 最近记录: |