Java 奇数相乘如何在溢出中不丢失信息?

Java 奇数相乘如何在溢出中不丢失信息?,java,binary,hashcode,integer-overflow,Java,Binary,Hashcode,Integer Overflow,计算哈希代码的标准方法是乘以31。 布洛赫说: 选择值31是因为它是奇数素数。即使是 如果乘法运算溢出,信息就会丢失,就像 乘2等于移位 我不确定我是否理解这一点。如果乘法溢出值丢失,而不考虑偶数/奇数对吗? 在以下示例中,我不确定有什么区别: int number = 2000000000; System.out.println(Integer.toBinaryString(number)); number*=2; System.out.println(Integer.toBin

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

选择值31是因为它是奇数素数。即使是 如果乘法运算溢出,信息就会丢失,就像 乘2等于移位

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

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


偶数总是至少忘记最重要的一位。只有当乘数为奇数时,msb才会影响结果,因为只有向左移动0步,它才会立即消失。这也是信息丢失的意思,因为乘以2等于移位。在您的示例中,您不会遇到太多明显的问题,因为结果不会溢出,2000000000=0x77359400显然没有将顶部位设置为负数作为带符号整数,但这与此无关,符号位是一个普通位,它携带一位信息,将某些信息转换为它不会破坏信息,向后工作换档前是0x77359400还是0xF7359400不明确。我希望这是足够直观的理由

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

有一个逆invx的事实意味着你可以写number*x*invx=number,这样在第一次乘法中就不会丢失任何信息

作为一个具体示例,inv3=0xAAAB,因此:


1在您的解释中,MSB和符号位之间有什么区别吗?我不能完全肯定。2我没有得到0xF7359400部件。这是4147483648,对吗?@Jim 1不太对,只是MSB有时被解释为符号位。2 yes或-147483648如果您想将其解释为有符号整数,则无论以哪种方式将其写成十进制,都会模糊其与原始数字的关系,关键是从MSB中移出某些内容意味着它丢失了,因此原始MSB可能是0或1,因此与奇数相乘始终是一个0移位的步骤?@Jim yes,如果你用二进制写乘法,部分积数
int number = 2000000000;  
System.out.println(Integer.toBinaryString(number));  
number*=3;  
System.out.println(Integer.toBinaryString(number));  
1110111001101011001010000000000  
1100101101000001011110000000000  
2000000000 * 3 = 0x65a0bc00
0x65a0bc00 * 0xaaaaaaab = 2000000000