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

Java中高效计算63位无符号long型(a*b)/c的最优方案

高效计算无符号63位long的(a*b)/c(避免乘法溢出)

因为常规long乘法会溢出,且要求无内存分配、时钟周期最少,以下是两种纯原生long运算的实现方案,完全避免BigInteger的开销:

方案一:数学拆分法(最优性能,无循环)

利用128位乘积的拆分公式,结合Java 8+的无符号运算API实现,所有操作均为单次运算,无循环,性能最优。

public static long unsignedMultiplyDivide(long a, long b, long c) {
    // 输入校验:确保是63位无符号数(符号位为0)且除数非0
    assert a >= 0 && b >= 0 && c >= 0 : "Inputs must be 63-bit unsigned values";
    assert c != 0 : "Divisor cannot be zero";

    // 获取a*b的高64位(对应无符号乘积的高64位)
    long productHigh = Long.multiplyHigh(a, b);
    // 获取a*b的低64位(溢出后的结果,作为无符号数处理)
    long productLow = a * b;

    // 预计算2^64除以c的商和余数(通过2^63推导,避免直接处理2^64)
    long pow63DivC = Long.divideUnsigned(1L << 63, c);
    long pow63ModC = Long.remainderUnsigned(1L << 63, c);
    long pow64DivC = Long.multiplyUnsigned(pow63DivC, 2);
    long pow64ModC = Long.multiplyUnsigned(pow63ModC, 2);
    // 调整余数确保小于c
    if (Long.compareUnsigned(pow64ModC, c) >= 0) {
        pow64ModC = Long.subtractUnsigned(pow64ModC, c);
        pow64DivC = Long.addUnsigned(pow64DivC, 1);
    }

    // 拆分计算:(high*2^64 + low)/c = high*(2^64/c) + (high*(2^64%c) + low)/c
    long part1 = Long.multiplyUnsigned(productHigh, pow64DivC);
    long temp = Long.multiplyUnsigned(productHigh, pow64ModC);
    temp = Long.addUnsigned(temp, productLow);
    long part2 = Long.divideUnsigned(temp, c);

    return Long.addUnsigned(part1, part2);
}

关键说明:

  • Long.multiplyHigh(a,b)直接获取a*b的高64位,无需额外计算;
  • 所有运算均使用Java的无符号API(divideUnsigned、addUnsigned等),确保对63位无符号数的正确处理;
  • 预计算264的商和余数时,通过263推导避免溢出问题;
  • 完全无内存分配,所有操作均为CPU原生指令,时钟周期最少。

方案二:手动模拟除法(直观易理解)

模拟128位无符号数的除法过程,逐位计算商,适合需要直观逻辑的场景。

public static long unsignedMultiplyDivide(long a, long b, long c) {
    assert a >= 0 && b >= 0 && c >= 0 : "Inputs must be 63-bit unsigned values";
    assert c != 0 : "Divisor cannot be zero";

    long productHigh = Long.multiplyHigh(a, b);
    long productLow = a * b;

    // 题目保证结果为63位,因此productHigh < c(否则乘积 >=c*2^64,结果超过63位)
    long remainder = productHigh;
    long quotient = 0;

    // 逐位处理低64位的每一位(从最高位到最低位)
    for (int i = 63; i >= 0; i--) {
        // 余数左移1位,准备接收下一位
        remainder = Long.remainderUnsigned(remainder << 1, c);
        // 如果当前productLow的位为1,加到余数中
        if ((productLow & (1L << i)) != 0) {
            remainder = Long.addUnsigned(remainder, 1);
        }
        // 余数 >=c时,减c并设置商的对应位
        if (Long.compareUnsigned(remainder, c) >= 0) {
            remainder = Long.subtractUnsigned(remainder, c);
            quotient |= 1L << i;
        }
    }

    return quotient;
}

关键说明:

  • 模拟手动除法逻辑,逐位构建商;
  • 循环64次,每次仅需简单的位运算和无符号比较,性能接近方案一;
  • 同样无内存分配,适合对代码可读性要求较高的场景。

验证方法

可以用BigInteger实现作为基准验证正确性:

public static long bigIntegerVersion(long a, long b, long c) {
    BigInteger bigA = BigInteger.valueOf(a);
    BigInteger bigB = BigInteger.valueOf(b);
    BigInteger bigC = BigInteger.valueOf(c);
    return bigA.multiply(bigB).divide(bigC).longValue();
}

对于任意符合条件的a、b、c,两种方案的结果均与BigInteger实现一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 02:45:54