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

JS除法转乘法魔数计算代码中循环结构的作用与实现原理

整数除法魔数实现差异疑问

我从Hacker's Delight的存档页面获取到如下JS实现代码,该代码接收除数(例如7)即可输出对应乘法运算使用的魔数,后续配合位移操作就能得到整数除法的计算结果。

我不熟悉汇编及相关数论原理,按照我的理解,魔数可以通过公式ceil(1/divisor * 1<<32)计算(64位运算场景下使用<<64,需要更大位宽的int类型支持):使用imul指令做整数乘法时,乘积高位和余数会分别存储在不同寄存器中,取我推导公式算出的魔数与被除数相乘后的高位寄存器值,就能得到正确的整数除法结果。我编写了如下C++测试代码验证了部分测试用例,运行结果均符合预期:

#include <cstdio>
#include <cassert>
int main(int argc, char *argv[])
{
    auto test_divisor = 7;
    auto test_value = 43;
    auto a = test_value*test_divisor;
    auto b = a-1; //One less test

    auto magic = (1ULL<<32)/test_divisor;
    if (((1ULL<<32)%test_divisor) != 0) {
        magic++; //Round up
    }
    auto answer1 = (a*magic) >> 32;
    auto answer2 = (b*magic) >> 32;
    assert(answer1 == test_value);
    assert(answer2 == test_value-1);
    printf("%lld %lld\n", answer1, answer2);
}

但取自Hacker's Delight的JS魔数计算实现却包含循环等额外逻辑,我有如下疑问:

  • 该循环的设计作用是什么?
  • 我的无循环实现存在什么疏漏?
  • 存在哪些测试用例会让我的实现计算错误,而该JS实现可以返回正确结果?

对应的JS与HTML代码如下:

var two31 = 0x80000000
var two32 = 0x100000000
function magic_signed(d) { with(Math) {
    if (d >= two31) d = d - two32// Treat large positive as short for negative.
    var ad = abs(d)
    var t = two31 + (d >>> 31)
    var anc = t - 1 - t%ad       // Absolute value of nc.
    var p = 31                   // Init p.
    var q1 = floor(two31/anc)    // Init q1 = 2**p/|nc|.
    var r1 = two31 - q1*anc      // Init r1 = rem(2**p, |nc|).
    var q2 = floor(two31/ad)     // Init q2 = 2**p/|d|.
    var r2 = two31 - q2*ad       // Init r2 = rem(2**p, |d|).
    do {
        p = p + 1;
        q1 = 2*q1;                // Update q1 = 2**p/|nc|.
        r1 = 2*r1;                // Update r1 = rem(2**p, |nc|.
        if (r1 >= anc) {          // (Must be an unsigned
            q1 = q1 + 1;           // comparison here).
            r1 = r1 - anc;}
        q2 = 2*q2;                // Update q2 = 2**p/|d|.
        r2 = 2*r2;                // Update r2 = rem(2**p, |d|.
        if (r2 >= ad) {           // (Must be an unsigned
            q2 = q2 + 1;           // comparison here).
            r2 = r2 - ad;}
        var delta = ad - r2;
    } while (q1 < delta || (q1 == delta && r1 == 0))

    var mag = q2 + 1
    if (d < 0) mag = two32 - mag // Magic number and
    shift = p - 32               // shift amount to return.
    return mag
}}

byId('subBtn').onclick = function (e) {
    e.preventDefault();
    inputVal = byId('value').value + 0;
    byId('result').innerText = "" + magic_signed(inputVal);
}

function byId(x) {
    return document.getElementById(x);
}
<h1>Hacker's Delight Magic Number</h1>
<form name="magic_number">Value:
    <input id="value">
    <button id='subBtn'>Calculate</button><br>
    <label id="result"></label>
</form>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 15:57:15