如果取一个数字,取其平方根,删除小数,然后将其提高到二次幂,结果应始终小于或等于原始数。
这似乎在python中都适用,直到你出于某种原因在99999999999999975425
上尝试它。
import math
def check(n):
assert math.pow(math.floor(math.sqrt(n)), 2) <= n
check(99999999999999975424) # No exception.
check(99999999999999975425) # Throws AssertionError.
看起来math.pow(math.floor(math.sqrt(99999999999999975425)), 2)
会返回1e+20
。
我认为这与我们在python中存储值的方式有关...与浮点运算相关的东西,但我不能具体说明这会如何影响这种情况。
答案 0 :(得分:21)
你的答案非常复杂。问题不在于sqrt
或pow
,问题是您使用的数字大于浮点数可以精确表示。标准IEEE 64位浮点运算不能表示超过52位的每个整数值(加一个符号位)。
尝试将输入转换为float
然后再转回:
>>> int(float(99999999999999975424))
99999999999999967232
>>> int(float(99999999999999975425))
99999999999999983616
正如您所看到的,可表示的值跳过了16384. math.sqrt
中的第一步是转换为float
(C double
),此时您的值增加了足以破坏最终结果。
简短版本:float
无法准确表示大整数。如果您需要更高的精确度,请使用decimal
。
答案 1 :(得分:8)
与Evan Rose(现已删除)的回答声明不同,这不是由于sqrt算法中的epsilon值。
大多数math
模块函数将其输入转换为float
,而math.sqrt
就是其中之一。
99999999999999975425
不能表示为浮点数。对于此输入,强制转换生成一个具有精确数值99999999999999983616的浮点数,repr
显示为9.999999999999998e+19
:
>>> float(99999999999999975425)
9.999999999999998e+19
>>> int(_)
99999999999999983616L
与此数字的平方根最接近的浮点数为10000000000.0
,这是math.sqrt
返回的内容。