You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#与JavaScript位运算结果不一致问题(含Long库使用疑问)

C#与JavaScript位运算结果不一致的原因及解决方法

问题背景

C#原始代码

uint HASHTABLE = 1917507215;
for (uint i = 5; i != 0; i--)
{
    HASHTABLE = (HASHTABLE ^ ((HASHTABLE << 10 ^ HASHTABLE) << 9 ^ HASHTABLE) << 5) & 0x7fffffff ^ (((HASHTABLE << 7 ^ HASHTABLE) << 10 ^ HASHTABLE) << 9 ^ HASHTABLE) << 5;
    HASHTABLE = HASHTABLE >> 1 | (HASHTABLE & 1) << 0x1f;
}

C#循环结束后,HASHTABLE的结果为1871861428(0x6F9256B4)。

JavaScript尝试过程

  • 原生JS因仅支持32位有符号整数,运算结果为**-275622220**,与C#结果不符。
  • 改用Long库模拟无符号整数运算,代码如下:
hashTable = Long.fromValue(hashTable, true);
for (let i = 5; i != 0; i--) {
    hashTable = hashTable.xor(
        hashTable.shiftLeft(10).xor(hashTable).shiftLeft(9).xor(hashTable).shiftLeft(5)
      ).and(0x7fffffff).xor(
        hashTable.shiftLeft(7).xor(hashTable).shiftLeft(10).xor(hashTable).shiftLeft(9).xor(hashTable).shiftLeft(5)
    );
    hashTable = hashTable.shiftRight(1).or(hashTable.and(1).shiftLeft(0x1f));
}
hashTable = hashTable.toInt();

但结果为4019345076(0xEF9256B4),与C#结果的差异是第32位(最高有效位)被错误置位。

不一致原因

  1. 位宽差异:C#的uint是32位无符号整数,所有位运算会自动截断到32位;Long库默认处理64位整数,移位等操作不会自动截断,导致高位残留无效数据,干扰最终结果。
  2. 右移逻辑错误:C#中uint的>>是逻辑右移(高位补0),但Long库的shiftRight是算术右移(高位补符号位),这会导致循环右移步骤的高位计算错误。
  3. 中间结果未截断:原Long库代码中,移位、异或的中间结果没有强制保留低32位,64位的高位数据参与后续运算,最终导致第32位被错误置位。

解决方法

修改Long库代码,模拟C#的32位无符号整数运算逻辑,每一步运算后截断到32位,同时修正右移逻辑:

let hashTable = Long.fromValue(1917507215, true);
for (let i = 5; i !== 0; i--) {
    // 计算第一部分:(HASHTABLE ^ ((HASHTABLE <<10 ^ HASHTABLE) <<9 ^ HASHTABLE) <<5) & 0x7fffffff
    let part1 = hashTable.shiftLeft(10).xor(hashTable).and(0xFFFFFFFF)
                        .shiftLeft(9).xor(hashTable).and(0xFFFFFFFF)
                        .shiftLeft(5).and(0xFFFFFFFF);
    part1 = hashTable.xor(part1).and(0x7fffffff);
    
    // 计算第二部分:(((HASHTABLE <<7 ^ HASHTABLE) <<10 ^ HASHTABLE) <<9 ^ HASHTABLE) <<5
    let part2 = hashTable.shiftLeft(7).xor(hashTable).and(0xFFFFFFFF)
                        .shiftLeft(10).xor(hashTable).and(0xFFFFFFFF)
                        .shiftLeft(9).xor(hashTable).and(0xFFFFFFFF)
                        .shiftLeft(5).and(0xFFFFFFFF);
    
    hashTable = part1.xor(part2).and(0xFFFFFFFF);
    
    // 模拟C#无符号循环右移:HASHTABLE >>1 | (HASHTABLE &1) <<0x1f
    let lsb = hashTable.and(1);
    hashTable = hashTable.shiftRightUnsigned(1).or(lsb.shiftLeft(0x1f)).and(0xFFFFFFFF);
}
// 转换为32位无符号整数结果
const result = hashTable.toNumber();
console.log(result); // 输出1871861428,与C#结果一致

关键修改点:

  • 每一步运算后用.and(0xFFFFFFFF)截断到32位,避免64位高位数据干扰。
  • 用shiftRightUnsigned(1)替代shiftRight(1),模拟C#无符号整数的逻辑右移。
  • 将复杂运算拆分为part1和part2,便于分步截断和调试。

内容的提问来源于stack exchange,提问作者Wilhelm Sorban

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 09:31:14