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

JS/TS大整数位运算移植MySQL:移位结果不符的解决需求

解决MySQL与JS/TS位移运算结果不一致的问题

为啥结果不匹配?

JavaScript/TypeScript的位移操作是基于32位有符号整数处理的:执行位移前会自动把数值截断为32位有符号整数,位移后溢出的高位直接丢弃;而MySQL的BIGINT是64位整数,负数位移会按无符号规则计算,导致结果完全偏离。

拿你提到的-1816598198 << 8举例:

  • JS/TS中,-1816598198本身就是32位有符号数,左移8位后高位溢出被丢弃,最终得到-1192670720。
  • MySQL中,这个值作为64位有符号数左移8位,结果变成超大无符号数18446743608660412928,和JS逻辑完全不符。

单语句修改方案

要让MySQL模拟JS/TS的32位有符号位移逻辑,需要手动截断并转换:

  1. 位移后用& 0xFFFFFFFF保留低32位(丢弃高位溢出部分)。
  2. 用CAST(... AS SIGNED)将截断后的32位无符号值转为有符号整数。

修改后的示例语句:

SELECT CAST((-1816598198 << 8) & 0xFFFFFFFF AS SIGNED);

执行后返回-1192670720,与JS/TS结果完全一致。

完整移植你的getBuildId函数

除了位移操作,还要注意两个细节:

  • JS的>>>是无符号右移,MySQL的>>是有符号右移,需要先把值转为32位无符号再右移。
  • MySQL的SUBSTRING起始索引是1,原代码从0开始会跳过第一个字符,需要修正。

修改后的完整MySQL函数:

CREATE DEFINER=`stev`@`%` FUNCTION `getBuildId`(gPsyonixBuildId VARCHAR(256)) RETURNS bigint
    DETERMINISTIC
BEGIN
    DECLARE characterCode INT;
    DECLARE characterIndex INT DEFAULT 0;
    DECLARE gPsyonixBuildIdLength INT DEFAULT CHAR_LENGTH(gPsyonixBuildId);
    DECLARE result BIGINT DEFAULT -1;
    DECLARE temp32 BIGINT; -- 存储32位截断后的值,对齐JS逻辑

    WHILE characterIndex < gPsyonixBuildIdLength DO
        -- 修正SUBSTRING索引:MySQL起始索引为1
        SET characterCode = ASCII(SUBSTRING(gPsyonixBuildId, characterIndex + 1, 1));
        
        -- 处理第一个Lookup:模拟JS的(result >>>24) ^ (charCode &0xff)
        SET temp32 = result & 0xFFFFFFFF; -- 转为32位无符号值
        SELECT CAST(`value` ^ CAST((temp32 << 8) & 0xFFFFFFFF AS SIGNED) AS SIGNED) 
        INTO result 
        FROM `build_id_lookup` 
        WHERE `index` = (temp32 >> 24) & 0xff ^ (characterCode & 0xff);
        
        -- 处理第二个Lookup
        SET temp32 = result & 0xFFFFFFFF;
        SELECT CAST(`value` ^ CAST((temp32 << 8) & 0xFFFFFFFF AS SIGNED) AS SIGNED) 
        INTO result 
        FROM `build_id_lookup` 
        WHERE `index` = (temp32 >> 24) & 0xff ^ ((characterCode >> 8) & 0xff);
        
        SET characterIndex = characterIndex + 1;
    END WHILE;

    -- 模拟JS的~result:JS是32位取反,等价于-(x+1),需先截断为32位
    SET temp32 = result & 0xFFFFFFFF;
    RETURN -(temp32 + 1);
END

关键改动说明:

  1. 索引修复:将SUBSTRING的起始索引从characterIndex改为characterIndex + 1,避免跳过第一个字符。
  2. 32位截断:每次位移和右移前,用& 0xFFFFFFFF将值转为32位无符号,对齐JS的整数处理逻辑。
  3. 位移修正:位移后先截断再转有符号,确保结果和JS一致。
  4. 按位取反模拟:JS的~result是32位取反,不能直接用MySQL的~(64位取反),改用-(temp32 + 1)模拟。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 06:55:14