【问题标题】:Power function in C gives the same output for large numbersC中的幂函数为大数提供相同的输出
【发布时间】:2017-02-02 15:47:40
【问题描述】:

problem statement 要求我找出 a^b 的最后一位数字。 约束条件是 0

我的代码对于 12^8 或 6^9 或类似的数字非常有效。 但是当我移动到大数区域时,比如 14^1234 或 17^148713,我总是得到 -8 的输出。

#include <stdio.h>
#include <math.h> 
int main() {
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int a;
        long long int b;
        double x, y, res;
        scanf("%d %lld", &a, &b);
        x=(double)a;
        y=(double)b;
        res = pow(x, y);
        int rem;
        rem = (int)res%10;
        printf("%d\n", rem);
    }
    return 0; }

这种奇怪的输出可能是什么原因?

除了将大数字存储在数组中之外,没有其他办法了吗(我猜是How to calculate 2 to the power 10000000)?

【问题讨论】:

  • 您需要一个更好的算法 - 多考虑底层数学,而不是仅仅尝试使用蛮力。
  • 对于您当前的解决方案,浮点数的精度远远受限。
  • 提示:阅读Modular exponentiation
  • 您应该检查系统上DBL_MAX 的值,这是在&lt;floats.h&gt; 中定义的常量。奇怪的是,它比您要处理的数字小很多数量级。
  • 至于 -8,一旦 res 变为无限,将其转换为 int 会产生 未定义的行为,如 What is the result of casting float +INF, -INF, and NAN to integer in C? 中所述。在我的机器上,演员表的结果是 0x80000000 或 -2,147,483,648。那个数字 mod 10 是 -8。

标签: c exponentiation


【解决方案1】:

int 最多可以保存 2^31 - 1 的值,所以你基本上有一个溢出(实际上它导致 Undefined Behaviour 与溢出的无符号类型相比)。

正如@PaulR 在 cmets 中对您的问题所指出的那样,总体思路是滥用模幂运算的某些属性。简而言之:您需要保持数字“足够小”以防止溢出并能够获得所需的结果。

我们可以使用以下属性:(a * b) % m == (a % m) * (b % m)。在代码中它可能如下所示:

const unsigned int m = 10;  // our modulus
while(t--)
{
    ...                     // read 'a' and 'b'

    unsigned int res = 1;   // last digit of a^b (e.g. res == (a^b % m))
    for (unsigned int i = 0; i < b; ++i)
    {
        res *= a;           // rising to power i
        res %= m;           // keep res small !
    }

    ...                     // you get desired result
}

注意:ab 声明为 unsigned int - 这足以满足您的限制,并且可以防止签名和未签名之间的不必要和不需要的转换。

【讨论】:

  • 好的,我明白了。非常感谢。还有一个问题:是否有任何方法可以提高效率。我在在线法官上收到 TLE 错误(超出时间限制):/
  • @KaranSingh 当b % 2^n == 0 时,您可以将b 除以2^n,然后使用上述循环进行迭代,最后执行res &lt;&lt; n - 有效地上升到2^n 的幂(小心,如​​果n 太大会成为问题,所以如果n 大于 30,则执行 res &lt;&lt; 30 然后 res %= m 然后 res &lt;&lt; n-30)
  • @KaranSingh 看看这个answer(来自您提到的链接),尤其是底部代码
【解决方案2】:

Integer Overflow为什么是负数,为什么值总是-8,比我聪明的人会回答那个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-15
    • 1970-01-01
    • 1970-01-01
    • 2020-06-06
    • 1970-01-01
    • 1970-01-01
    • 2015-09-27
    • 1970-01-01
    相关资源
    最近更新 更多