这是您困惑的本质:
由于浮点表示精度,这可能类似于 122.99999999999999999999 或 123.000000000000000000001。
这是错误的。在符合 IEEE-754 的系统上,它总是正好是 123,这几乎是现代所有系统。浮点运算没有“随机误差”或“噪声”。它具有精确的、确定性的舍入,并且许多简单的计算(比如这个)根本不会产生任何舍入。
123
完全可以用浮点表示,所以也是123*123
(所有中等大小的整数也是如此)。123*123
因此,当您转换为浮点类型时,不会发生舍入错误。结果正好 15129
。
根据 IEEE-754 标准,平方根是正确的舍入运算。这意味着如果有一个确切的答案,则需要平方根函数来产生它。由于您正在取 的平方根,也就是, 这正是您从平方根函数得到的结果。不会发生舍入或近似。15129
123
现在,对于多大的整数,这将是正确的?
双精度可以精确表示最大为 2^53 的所有整数。因此,只要i*i
小于 2^53,您的计算中就不会发生舍入,因此结果将是准确的。这意味着对于所有i
小于94906265
,我们知道计算将是精确的。
但你尝试i
的比这更大!发生了什么?
对于i
您尝试过的最大的,i*i
仅略大于 2^53 (1.1102... * 2^53
实际上)。因为从整数到双精度的转换(或双精度乘法)也是正确的舍入运算,i*i
所以将是最接近 的精确平方的可表示值i
。在这种情况下,由于i*i
54 位宽,舍入将发生在最低位。因此我们知道:
i*i as a double = the exact value of i*i + rounding
rounding
要么在哪里-1,0, or 1
。如果四舍五入为零,则平方是精确的,所以平方根是精确的,所以我们已经知道你得到了正确的答案。让我们忽略这种情况。
所以现在我们正在研究 的平方根i*i +/- 1
。使用泰勒级数展开,这个平方根的无限精确(未四舍五入)值为:
i * (1 +/- 1/(2i^2) + O(1/i^4))
现在看看你之前是否没有做过任何浮点错误分析有点繁琐,但是如果你使用这个事实i^2 > 2^53
,你可以看到:
1/(2i^2) + O(1/i^4)
term 小于 2^-54,这意味着(由于平方根被正确舍入,因此它的舍入误差必须小于 2^54),sqrt 函数的舍入结果正好是i
.
事实证明(通过类似的分析),对于任何可精确表示的浮点数 x,sqrt(x*x) 恰好是 x(假设 的中间计算x*x
没有上溢或下溢),所以你唯一的方法这种类型的计算可能会遇到舍入是在其x
自身的表示中,这就是为什么您会看到它从2^53 + 1
(最小的不可表示的整数)开始。