我用 C 编写了一个程序,它接受两个输入 x 和 n,并将 x 提高到 n 的次方。 10^10 不起作用,发生了什么?

I've made a program in C that takes two inputs, x and n, and raises x to the power of n. 10^10 doesn't work, what happened?

我用 C 编写了一个程序,它接受两个输入 x 和 n,并将 x 提高到 n 的次方。 10^10 不起作用,发生了什么事?

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

float isEven(int n)
{
    return n % 2 == 0;
}

float isOdd(int n)
{
    return !isEven(n);
}

float power(int x, int n)
{
    // base case
    if (n == 0)
    {
        return 1;
    }
    // recursive case: n is negative
    else if (n < 0)
    {
        return (1 / power(x, -n));
    }
    // recursive case: n is odd
    else if (isOdd(n))
    {
        return x * power(x, n-1);
    }
    // recursive case: n is positive and even
    else if (isEven(n))
    {
        int y = power(x, n/2);
        return y * y;
    }
    
    return true;
}

int displayPower(int x, int n)
{
    printf("%d to the %d is %f", x, n, power(x, n));
    return true;
}

int main(void)
{
    int x = 0;
    printf("What will be the base number?");
    scanf("%d", &x);
    
    int n = 0;
    printf("What will be the exponent?");
    scanf("%d", &n);
    
    displayPower(x, n);
}

例如,这是一对有效的输入:

./exponentRecursion 
What will be the base number?10
What will be the exponent?9
10 to the 9 is 1000000000.000000

但这就是我用 10^10 得到的结果:

./exponentRecursion 
What will be the base number?10
What will be the exponent?10
10 to the 10 is 1410065408.000000

为什么要写这么奇怪的数字?

顺便说一句,10^11 returns 141006540​​80.000000,正好是上面的十倍。

也许我使用的数据类型有一些“限制”?我不确定。

A float 只有大约 7 位小数的精度。任何比这个数字多的数字都只是一个近似值。

如果您切换到 double,您将获得大约 16 位精度。

当您开始使用 C 中的 基本 数据类型处理大数时,您可能 运行 会遇到麻烦。

整数类型的取值范围有限(例如 4x109 对于 32 位无符号整数)。浮点类型有更大的范围(虽然不是无限的)但精度有限。例如,IEEE754 双精度可以在 +/-10308

范围内为您提供大约 16 位十进制数字的精度

要恢复这两个 这些方面,您需要使用某种 bignum 库,例如 MPIR

您的变量 x 是 int 类型。最常见的内部表示是 32 位。这是一个带符号的二进制数,因此只有 31 位可用于表示大小,通常的最大正整数值为 2^31 - 1 = 2,147,483,647。任何更大的东西都会溢出,给出更小的幅度并且可能是负号。

为了更大的范围,可以把x的类型改成long long(通常是64位——大约18位)或者double(通常是64位,精度为51位)大约 15 位数字)。

(警告:许多实现对 intlong 使用相同的表示,因此使用 long 可能不会有所改进。)

如果您在 C 程序中混合使用不同的数据类型,则编译器会执行多个隐式转换。由于编译器的工作方式有严格的规则,因此人们可以准确地弄清楚你的程序会发生什么以及为什么。

由于我不知道所有这些转换规则,我做了以下操作:估计最大结果所需的最大精度。然后将过程中的每个变量和函数显式转换为这种精度,即使这不是必需的。通常这会像解决方法一样工作。