--this function isn't relevant, but I included it for completeness
function gcd(a, b)
local temp
while b > 0 do
temp = a % b
a = b
b = temp
end
return a
end
function extendedgcd(a, b)
if b == 0 then
return 1, 0, a
end
local x, y, d = extendedgcd(b, a % b)
--this assertion fails for a = 568784642688024576, b = 5
--left side gives 113756928537604915 (correct), while right side gives 113756928537604912 (wrong)
assert(a // b == math.floor(a / b))
--so here, I can't use math.floor
return y, x - a // b * y, d
end
function modularinverse(e, mod)
if gcd(e, mod) > 1 then
return nil
end
local x, _, _ = extendedgcd(e, mod)
if x < 0 then
x = x % mod
end
if x * e % mod ~= 1 then
error(string.format("Modular inverse (%d) doesn't produce 1 (e = %d, mod = %d)", x, e, mod))
end
return x
end
modularinverse(5, 568784642688024576)
对于a = 5
和b = 568784642688024576
,extendedgcd
中的断言失败。我不是FP精度方面的专家,但是两者之间相差3,因此我认为这里不存在舍入/精度误差。但是我可能错了。
通常我只使用//
,但是我不能,因为目标平台没有运行Lua 5.3,这是在添加操作符时开始的。
我想念什么?我如何使其与floor
一起使用,或者还有另一种方法?
还要注意:当我用Python重新编写它(用math.floor
和//
)时,发生了相同的问题。
答案 0 :(得分:3)
更精确的答案:
纸和铅笔将显示:
568784642688024576 / 5 = 113756928537604915.02
该商最精确的二进制表示形式是双精度数字:
0100001101111001010000100101010100101110010000111001001100110011
以小数表示的是:1.13756928537604912E17
(请注意... 912结尾)
现在,如果将二进制表示形式减一,就像这样:
0100001101111001010000100101010100101110010000111001001100110010
那么它等于:1.13756928537604896E17
(最后是... 896!)
如果要将原始二进制数加1,如下所示:
0100001101111001010000100101010100101110010000111001001100110100
然后等于:1.13756928537604928E17
(末尾... 928!)
因此,这些数字具有精确的双精度二进制表示形式:
113756928537604896
113756928537604912
(最接近实际商)
113756928537604928
可以使用在线转换器(例如here)验证以上内容。
因此,本课是:
整数除法将给出正确的答案(即商的整数部分)。地板浮点除法依赖于数字的二进制表示,这并不总是精确的。
超出了此答案的范围,但需要阅读以真的了解以下任何内容:
上面的二进制数字如何表示它们的十进制等效项?
/
和//
之间的算法区别是什么?
//
为什么能给我们上面想要的答案?答案 1 :(得分:-1)
卢阿的数字是双精度的,对不对?一旦达到2 ^ 52以上,整数表示中的差距就会越来越大。
568784642688024576大于2 ^ 58,因此您可能会遇到一些缺口。如果是这样,那么//看起来就好像正确地弥补了差距,而底线可能就没有。
如果代码要处理接近2 ^ 64的整数值很重要,那么可能值得寻找一个插件或可以让您使用64位整数的工具。或者,如果您需要处理更大的数字,则可能有一个库或一些用于处理非常大的数字的东西。