为什么在Java和JavaScript中进行相同的位运算计算会得出不同的结果?

3

问题:

我需要计算一个类似于以下16进制代码的CRC16

08010000016B40D8EA30010000000000000000000000000000000105021503010101425E0F01F10000601A014E000000000000000001

我有一个在JavaScript中运行的有效解决方案。由于新要求,我必须将此代码翻译成Java

期望的结果:

对于上述十六进制字符串:0000C7CF ( 51151 )

我的方法:

我有以下工作的JavaScript代码,我正在尝试将其翻译为Java

var hex = "08010000016B40D8EA30010000000000000000000000000000000105021503010101425E0F01F10000601A014E000000000000000001";

var str = '';
for (var i = 0; i < hex.length; i += 2){ 
  str += String.fromCharCode( parseInt(hex.substr(i, 2), 16) );
}

var crc = 0x0000;
var poly = 0xA001;

for (var pos = 0; pos < str.length; pos++) {
  crc ^= str.charCodeAt(pos);
  for (var i = 8; i !== 0; i--) {
    if ((crc & 0x0001) !== 0) {
      crc >>= 1;
      crc ^= poly;
    } else
      crc >>= 1;
  }
}
console.log( crc ); // 51151
console.log( crc.toString(16) ); // c7cf

我目前在Java中的实现如下:

String hex = "08010000016B40D8EA30010000000000000000000000000000000105021503010101425E0F01F10000601A014E000000000000000001";
byte[] arr = Hex.decodeHex( hex );
long polynomial = 0xA001;
long crc = 0x0000;
for (byte b : arr) {
    crc ^= b;
    for (int i = 8; i != 0; i--) {
        if ((crc & 0x01) != 0) {
            crc >>= 1;
            crc ^= polynomial;
        } else {
            crc >>= 1;
        }
    }
}
System.out.println( crc ); // -37776

正如您所看到的,翻译后的Java代码并没有计算出期望的结果。

问题:

为什么这段代码在JavaJavaScript中会产生不同的结果?


你的JS版本使用了 if ((crc & 0x0001) !== 0) {,而你的Java版本使用了 if ((crc & 0x01) != 0) {(在for循环内的第一行),这可能会导致问题。所有其他值都相似,所以我想这个也应该是相似的吧? - Fabian S.
1
在Java中的!=相当于Javascript中的!== - Lapskaus
我想指出你在二进制与运算中使用的数字是不同的(crc&0x0001crc&0x01),而不是运算符。 - Fabian S.
1
0x010x0001不都是1吗?无论是0x010x0001还是仅仅的1,结果都是相同的(在Java和JS中)。 - Lapskaus
你知道输出何时变得不同吗?如果不知道,可以尝试在每次迭代时输出它,然后检查 JS 和 Java 版本在哪个迭代中不相等(例如,可以使用 git 或在线 diff 工具进行比较)。 - A_A
1个回答

6
将以下行从: 更改为: 在Java中,byte的范围是-128到127,因此您需要将其设置为无符号。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接