Java脚本的异或结果不同于 Java
JavaScript's xor result different than the one of Java
解决方案
我的内部转换逻辑有一个错误。
原始问题
我需要在Java和Java脚本中实现一个算法,而Java实现和计算结果是参考。但是,当对 "negative" 值调用 XOR 运算符时(我知道 Java 和 Java 脚本使用 2 的补码)导致 Java 的结果为正,而 Java 脚本结果是否定的,如下面的输出所示:
Java output:
hash A: 16777619
hash B: 637696617
hash A: 637696613
hash B: 988196095
hash A: 988196062
hash B: -1759370886
hash A: 1759370917 <-- here the JavaScript implementation behaves different
hash B: -1169850945
JavaScript output:
hash A: 16777619
hash B: 637696617
hash A: 637696613
hash B: 988196095
hash A: 988196062
hash B: -1759370886
hash A: -1759370843 <-- this result should be equal to the Java result
hash B: -1883572545
下面是Java源代码:
private static final int FNV_PRIME = 0x1000193;
private static final int FNV_COMPRESS = 0xFFFF;
...
public long getHash(int inputNumber)
{
int hash = FNVCalculator.FNV_PRIME;
ByteBuffer intToByteArrayConverter = ByteBuffer.allocate(4);
intToByteArrayConverter.putInt(inputNumber);
byte[] inputValues = intToByteArrayConverter.array();
// inputValues.length is always equal to 4
for (byte processCounter = (byte) 0; processCounter < inputValues.length; processCounter++)
{
hash ^= inputValues[processCounter];
System.out.println("hash A: " + hash);
hash *= FNV_PRIME;
System.out.println("hash B: " + hash);
}
return (hash & FNVCalculator.FNV_COMPRESS);
}
以下片段显示了 Java脚本代码:
var Constants =
{
FNV_PRIME: parseInt("1000193", 16),
FNV_COMPRESS: parseInt("FFFF", 16),
BYTE_ARRAY_LENGTH: 4,
...
};
Object.freeze(Constants);
var hash = Constants.FNV_PRIME;
for (var counter = 0; counter < Constants.BYTE_ARRAY_LENGTH; counter++)
{
hash ^= inputNumberArray[counter];
console.log("hash A: " + hash);
// mutltiply the hash with the 32 bit FNV prime number: 2^24 + 2^8 + 0x93
// source: https://github.com/wiedi/node-fnv/blob/master/fnv.js
hash += ((hash << 24) + (hash << 8) + (hash << 7) + (hash << 4) + (hash << 1));
hash |= 0;
console.log("hash B: " + hash);
}
return (hash & Constants.FNV_COMPRESS);
带数字的数组在Java和Java脚本版本中是相等的,如下所示(所有数字均为十进制数):
Java version:
inputValues[0]: 0
inputValues[1]: 12
inputValues[2]: 33
inputValues[3]: -33
JavaScript version:
inputNumberArray[0]: 0
inputNumberArray[1]: 12
inputNumberArray[2]: 33
inputNumberArray[3]: -33
我已经尝试用整数数组替换字节数组,但没有帮助。我正在使用 WebKit 的 JavaScriptCore 引擎。
看到这些值,我怀疑 Java 是将 223 转换为一系列字节时的符号扩展,而 Javascript 不是。 223 = 0xDF = 0xFFFFFFDF 符号扩展时....
在Java和JavaScript之间移植时要注意的事项。
移位运算符仅对 Java脚本中的 32 位值进行运算。
Java脚本在内部将 所有 数字表示为 64 位浮点数,而不像 Java 那样区分浮点数和整数。更重要的是,JavaScript 没有 int 或 float 大小,例如没有 byte、int 或 long 类型。
由于上述陈述和语言表示数字的方式不同,始终存在脱钩的风险。
解决方案
我的内部转换逻辑有一个错误。
原始问题
我需要在Java和Java脚本中实现一个算法,而Java实现和计算结果是参考。但是,当对 "negative" 值调用 XOR 运算符时(我知道 Java 和 Java 脚本使用 2 的补码)导致 Java 的结果为正,而 Java 脚本结果是否定的,如下面的输出所示:
Java output:
hash A: 16777619
hash B: 637696617
hash A: 637696613
hash B: 988196095
hash A: 988196062
hash B: -1759370886
hash A: 1759370917 <-- here the JavaScript implementation behaves different
hash B: -1169850945
JavaScript output:
hash A: 16777619
hash B: 637696617
hash A: 637696613
hash B: 988196095
hash A: 988196062
hash B: -1759370886
hash A: -1759370843 <-- this result should be equal to the Java result
hash B: -1883572545
下面是Java源代码:
private static final int FNV_PRIME = 0x1000193;
private static final int FNV_COMPRESS = 0xFFFF;
...
public long getHash(int inputNumber)
{
int hash = FNVCalculator.FNV_PRIME;
ByteBuffer intToByteArrayConverter = ByteBuffer.allocate(4);
intToByteArrayConverter.putInt(inputNumber);
byte[] inputValues = intToByteArrayConverter.array();
// inputValues.length is always equal to 4
for (byte processCounter = (byte) 0; processCounter < inputValues.length; processCounter++)
{
hash ^= inputValues[processCounter];
System.out.println("hash A: " + hash);
hash *= FNV_PRIME;
System.out.println("hash B: " + hash);
}
return (hash & FNVCalculator.FNV_COMPRESS);
}
以下片段显示了 Java脚本代码:
var Constants =
{
FNV_PRIME: parseInt("1000193", 16),
FNV_COMPRESS: parseInt("FFFF", 16),
BYTE_ARRAY_LENGTH: 4,
...
};
Object.freeze(Constants);
var hash = Constants.FNV_PRIME;
for (var counter = 0; counter < Constants.BYTE_ARRAY_LENGTH; counter++)
{
hash ^= inputNumberArray[counter];
console.log("hash A: " + hash);
// mutltiply the hash with the 32 bit FNV prime number: 2^24 + 2^8 + 0x93
// source: https://github.com/wiedi/node-fnv/blob/master/fnv.js
hash += ((hash << 24) + (hash << 8) + (hash << 7) + (hash << 4) + (hash << 1));
hash |= 0;
console.log("hash B: " + hash);
}
return (hash & Constants.FNV_COMPRESS);
带数字的数组在Java和Java脚本版本中是相等的,如下所示(所有数字均为十进制数):
Java version:
inputValues[0]: 0
inputValues[1]: 12
inputValues[2]: 33
inputValues[3]: -33
JavaScript version:
inputNumberArray[0]: 0
inputNumberArray[1]: 12
inputNumberArray[2]: 33
inputNumberArray[3]: -33
我已经尝试用整数数组替换字节数组,但没有帮助。我正在使用 WebKit 的 JavaScriptCore 引擎。
看到这些值,我怀疑 Java 是将 223 转换为一系列字节时的符号扩展,而 Javascript 不是。 223 = 0xDF = 0xFFFFFFDF 符号扩展时....
在Java和JavaScript之间移植时要注意的事项。
移位运算符仅对 Java脚本中的 32 位值进行运算。 Java脚本在内部将 所有 数字表示为 64 位浮点数,而不像 Java 那样区分浮点数和整数。更重要的是,JavaScript 没有 int 或 float 大小,例如没有 byte、int 或 long 类型。
由于上述陈述和语言表示数字的方式不同,始终存在脱钩的风险。