Modular Exponentiation不适用于C中的大数字

时间:2015-04-11 07:33:21

标签: c

我不知道为什么它大量使用不好,因为我已经最大限度地使用了unsigned long long。请帮我。或者,如果此代码完全混乱,请建议更好,更有效的算法。这是一项功课,我们只允许使用#include <stdio.h>#include <stdlib.h>。我希望你能帮助我。

unsigned long long modularexp(unsigned long long a,unsigned long long b,unsigned long long mod)
{
    //a^b % mod
    unsigned long long product,pseq;
    product=1;
    pseq=a%mod;
    while(b>0)
    {
        if(b&1)
            product=(product*pseq)%mod;
        pseq=(pseq*pseq)%mod;
        b>>=1;
    }
    return product;
}

2 个答案:

答案 0 :(得分:4)

您的代码本身很好,但只有当模数小于2 ^ 32时才能可靠地工作。在您的情况下,模数超过2 ^ 32和以下:

a * b < ulong.max 

不一定正确,即使a < modb < mod

您可以通过向所有乘法添加溢出检查来解决此问题。如果乘法a * b溢出,请细分a = a1 + a2并计算a1 * b + a2 * b

下面的代码通过引入模块化乘法的附加功能来实现这一目的。

#include <stdio.h>

typedef unsigned long long ulong;

#define ULONG_MAX ((ulong) -1)

ulong modmul(ulong a, ulong b, ulong mod)
{
    if (a == 0) return 0;

    if (ULONG_MAX / a > b) {
        return (a * b) % mod;
    } else {
        ulong a1 = a / 2;
        ulong a2 = a - a1;

        return (modmul(a1, b, mod) + modmul(a2, b, mod)) % mod;
    }  
}

ulong modexp(ulong a, ulong b, ulong mod)
{
    ulong product = 1;

    a = a % mod;

    while (b > 0) {
        if (b & 1) {
            product = modmul(product, a, mod);
        }
        a = modmul(a, a, mod);
        b >>= 1;
    }

    return product;
}

int main()
{
    ulong a = modexp(1727, 62483, 7491569251LL);
    ulong expect = 5500747491LL;

    printf("%llu\n%llu\n", a, expect);

    return 0;
}

答案 1 :(得分:0)

这是一个测试程序,显示溢出发生的位置:

#include <stdio.h>
#include <stdlib.h>

static
unsigned long long modularexp(unsigned long long a,
                              unsigned long long b,
                              unsigned long long mod)
{
    unsigned long long product, pseq;
    product = 1;
    pseq = a % mod;
    while (b > 0) {
        if (b & 1) {
            if (pseq != 0 && product * pseq / pseq != product) {
                printf("multiplication overflow at b=%llu:"
                       " product=%llu, pseq=%llu\n",
                       b, product, pseq);
            }
            product = (product * pseq) % mod;
        }
        if (pseq != 0 && pseq * pseq / pseq != pseq) {
            printf("multiplication overflow at b=%llu:"
                   " pseq=%llu\n",
                   b, pseq);
        }
        pseq = (pseq * pseq) % mod;
        b >>= 1;
    }
    return product;
}

int main(int argc, char *argv[]) {
    unsigned long long a, b, mod, res;
    if (argc > 3) {
        a = strtoull(argv[1], NULL, 0);
        b = strtoull(argv[2], NULL, 0);
        mod = strtoull(argv[3], NULL, 0);
        res = modularexp(a, b, mod);
        printf("%llu ** %llu %% %llu = %llu\n", a, b, mod, res);
    }
}

使用您的值运行它会产生以下结果:

~/dev/stackoverflow > ./t47 1727 62483 7491569251
multiplication overflow at b=3905: product=5150827583, pseq=5846688665
multiplication overflow at b=3905: pseq=5846688665
multiplication overflow at b=488: pseq=6744552923
multiplication overflow at b=244: pseq=4362729489
multiplication overflow at b=61: pseq=6056813204
multiplication overflow at b=30: pseq=6747710262
multiplication overflow at b=15: pseq=5762416609
multiplication overflow at b=7: pseq=5992947929
multiplication overflow at b=3: pseq=6028562833
multiplication overflow at b=1: product=7015761607, pseq=7047166445
multiplication overflow at b=1: pseq=7047166445
1727 ** 62483 % 7491569251 = 4674220559

您必须使用M Oehm提供的功能保护计算。