【问题标题】:Unsigned Long Int overflow when calculating pow计算 pow 时 Unsigned Long Int 溢出
【发布时间】:2018-10-20 18:41:04
【问题描述】:

我正在尝试制作一个快速计算 x^y mod z 的函数。它在计算 2^63 mod 3 之类的东西时效果很好,但在 2^64 mod 3 和更高的指数时,它只返回 0。

我怀疑某处有溢出,但我无法确定。我已经在进行计算(* 和 mod)的地方尝试了显式转换,我还设置了我的存储变量(resPowcurPowunsigned long long int(建议 here)但这没有帮助很多。

typedef unsigned long int lint;

lint fastpow(lint nBase, lint nExp, lint nMod) { 
    int lastTrueBit = 0;
    unsigned long long int resPow = 1ULL;

    unsigned long long int curPow = nBase;
    for (int i = 0; i < 32; i++) {
        int currentBit = getBit(nExp, i);

        if (currentBit == 1) {
            for (lint j = 0; j < i - lastTrueBit; j++) {
                curPow = curPow * curPow;
            }
            resPow =resPow * curPow;
            lastTrueBit = i;
        }
    }
    return resPow % nMod;
}

【问题讨论】:

  • 为什么最后只做% nMod?这违背了整个目的。
  • 你可以用unsigned计算2^64 mod 3 char

标签: c multiplication exponential unsigned-long-long-int


【解决方案1】:

我怀疑某处溢出,

是的,curPow * curPowresPow * curPow 都可能在数学上溢出。

这里包含溢出的常用方法是对中间产品执行mod

        // curPow = curPow * curPow;
        curPow = (curPow * curPow) % nMod;
    // resPow =resPow * curPow;
    resPow = (resPow * curPow) % nMod;

nMod &lt; ULLONG_MAX/(nMod - 1) 就足够了。 (mod 值是unsigned long long 精度的一半)。否则需要采取更极端的措施,如:Modular exponentiation without range restriction


小事

for(int i = 0; i &lt; 32; i++) 假定 lint/unsigned long 是 32 位。可移植代码将避免那个幻数unsigned long 在各种平台上都是 64 位的。

LL 这里不需要。 U 仍然有助于消除各种编译器警告。

// unsigned long long int resPow = 1ULL;
unsigned long long int resPow = 1U;

【讨论】:

    猜你喜欢
    • 2016-07-29
    • 1970-01-01
    • 2012-01-27
    • 1970-01-01
    • 1970-01-01
    • 2016-12-20
    • 2013-08-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多