我有两个大的带符号的32位数字(java整数)相乘,这样它们就会溢出。实际上,我有一个数字和结果。我可以确定其他操作数是什么吗?
knownResult = unknownOperand * knownOperand;
为什么呢?我有一个字符串,后缀用fnv1a进行哈希处理。我知道结果哈希和后缀,我想看看确定原始字符串的哈希是多么容易。
这是fnv1a的核心:
hash ^= byte
hash *= PRIME
答案 0 :(得分:4)
这取决于。如果乘数是偶数,则必然至少丢失一位。所以我希望素数不是2。
如果它是奇数,那么你绝对可以反转它,只需乘以乘数的modular multiplicative inverse来撤消乘法。
有一种算法可以计算模块乘法逆模在Hacker's Delight中的2的幂。
例如,如果乘数为3
,那么您需要乘以0xaaaaaaab
来撤消(因为0xaaaaaaab * 3 = 1
)。对于0x01000193
,反之为0x359c449b
。
答案 1 :(得分:1)
你想要解决y = prime * x
的等式x
,你可以通过有限环模2 32 :x = y / prime
中的除法来实现。
从技术上讲,你可以通过将y
乘以素数2 32 的multiplicative inverse来实现,这可以通过extended Euclidean algorithm来计算。
答案 2 :(得分:0)
答案 3 :(得分:0)
这不是最快的方法,但很容易记住的是:
unsigned inv(unsigned x) {
unsigned xx = x * x;
while (xx != 1) {
x *= xx;
xx *= xx;
}
return x;
}
返回x**(2**n-1)
(如x*(x**2)*(x**4)*(x**8)*...
或x**(1+2+4+8+...)
)。正如循环退出条件所暗示的那样,x**(2**n)
足够大时n
为1,假设x
为奇数。
因此,x**(2**n-1)
等于x**(2**n)/x
等于1/x
等于将x
乘以得到值1(mod 2 ** n)的事物。然后你申请:
knownResult = unknownOperand * knownOperand
knownResult * inv(knownOperand) = unknownOperand * knownOperand * inv(knownOperand)
knownResult * inv(knownOperand) = unknownOperand * 1
或简单地说:
unknownOperand = knownResult * inv(knownOperand);
但是有更快的方法,如其他答案所示。这个很容易记住。
此外,强制性SO“使用库函数”答案:BN_mod_inverse()。