【问题标题】:How is multiplying by odd does not lose information in overflow?乘以奇数如何不会在溢出中丢失信息?
【发布时间】:2017-04-28 11:58:39
【问题描述】:

计算哈希码的标准方法是乘以 31。
布洛赫说:

选择值 31 是因为它是一个奇数素数。如果它是什 并且乘法溢出,信息将丢失,因为 乘以 2 与移位相同

我不确定我是否理解这一点。如果乘法溢出值丢失,无论偶数/奇数对吗?
在以下示例中,我不确定有什么区别:

int number = 2000000000;  
System.out.println(Integer.toBinaryString(number));  
number*=2;   
System.out.println(Integer.toBinaryString(number));    
1110111001101011001010000000000  
11101110011010110010100000000000  

和

int number = 2000000000;  
System.out.println(Integer.toBinaryString(number));  
number*=3;  
System.out.println(Integer.toBinaryString(number));  
1110111001101011001010000000000  
1100101101000001011110000000000  

【问题讨论】:

    标签: java binary hashcode integer-overflow


    【解决方案1】:

    偶数总是忘记至少最重要的位。 msb 仅在乘数为奇数时才会影响结果,因为只有左移 0 步时它不会立即消失。这也是“信息会丢失,因为乘以 2 与移位相同”的意思。在您的示例中,您不会遇到太多明显的麻烦,因为结果不会溢出, 2000000000 = 0x77359400 显然没有设置最高位(它作为有符号整数包装为负数,但这无关紧要,符号位是正常位携带一些信息,将某些东西移入其中不会破坏信息),向后工作,无论是移位前的 0x77359400 还是 0xF7359400,都是模棱两可的。我希望这是足够的“直观理由”。

    只有奇数乘数才能保存所有信息的真正证据是,正是奇数具有乘法逆元以 2 的幂为模。 x 有一个乘法逆模 m 当且仅当 gcd(x, m) == 1,假设 m 为 2k,该条件仅适用于奇数:它不能适用于偶数,因为它们有2 的共同因数,由于奇数没有 2 的因数,而 2k只有 有 2 的因数,所以它们从不共享任何因数。

    存在一个逆 inv(x) 的事实意味着您可以编写 number * x * inv(x) = number,因此在第一次乘法中不会丢失任何信息。

    作为一个具体的例子,inv(3) = 0xaaaaaaab 所以:

    2000000000 * 3 = 0x65a0bc00
    0x65a0bc00 * 0xaaaaaaab = 2000000000
    

    【讨论】:

    • 1) 你的解释中MSB和符号位有什么区别吗?我不完全确定。 2) 我没有得到0xF7359400 部分。那是 4147483648 对吗?
    • @Jim 1) 不是真的,只是 MSB 有时被解释为符号位。 2) yes 或 -147483648 如果你想将它解释为一个有符号整数,无论​​哪种方式用十进制写它都会掩盖它与原始数字的关系,关键是移动 MSB 的 out 意味着它丢失了,所以原来的 MSB 可能是 0 或 1
    • 所以乘以一个奇数总是一个移位0步?
    • @Jim 是的,如果你把乘法写成二进制,部分乘积 number << 0 将被包括在内,因为乘数的 LSB 已设置
    猜你喜欢
    • 2012-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-29
    • 1970-01-01
    相关资源
    最近更新 更多