输出是 nan 而它不应该是

Output is nan while it shouldn't be

我需要计算以下内容:

S= 1- x^2 / 2! + x^4 / 4! - x^6 / 6! + ... + (-1)^n * x^2n / (2n)!

Where n is between 1 and 100, and x is a double.

我有以下代码:

unsigned int factorial (unsigned int n)
{
    if (n == 0)
        return 1;
    return n * factorial(n - 1);
}

double exFive(int n, double x)
{
    double s = 1;

    for (int i = 1; i <= n; ++i)
    {
        int j = 2 * i; 
        s = s + pow(-1, i) * pow(x, 2*i) / factorial(j); //problem is here I guess
    }

    return s;
}

void fiveIO()
{
    int n = 1;
    double x;
   
    cout << "Input n: ";
    cin >> n;
    while ((n < 1) || (n > 100))
    {
        cout << "Wrong number, input again: ";
        cin >> n;
    } 

    cout << "Input: ";
    cin >> x;

    cout << "Result is " << fixed << setprecision(2) << exFive(n, x);
}

它有效,但结果是 nan,其中 n 高于 ~15.. 但我不知道为什么。 我假设它是 FiveX 函数。

因此,例如,n = 3, x = 5 输出 -7.16(这是正确的),但是 n = 50, x = 5 输出“nan”..是因为输出太大了数字?但是那我该怎么办呢?

避免 int factorial(j) .

中的溢出(未定义行为 (UB))

通过根据其先验值计算 term 来改进循环计算。

//for (int i = 1; i <= n; ++i) {
//    int j = 2 * i; 
//    s = s + pow(-1, i) * pow(x, 2*i) / factorial(j); //problem is here I guess
//}

// Something like
double xx = x*x;
double term = 1.0;
for (int i = 1; i <= n; ++i) {
    int j = 2 * i; 
    term *= -xx / ((j-1)*j);
    s += term;
}

一种更高级的方法会反向计算总和以最大限度地减少计算错误,但很大程度上取决于 x 的允许范围,不受 OP 的限制。

对于公式:

S= 1- x^2 / 2! + x^4 / 4! - x^6 / 6! + ... + (-1)^n * x^2n / (2n)!

我认为这个实现的规模稍微好一些,因为它避免了一次乘以所有东西。

double exFive(int n, double x)
{
    double s = 1;

    bool subtract = true;

    for (int i = 1; i <= n; i++)
    {
        double inner = 1;
        int n2 = i * 2;
        for (int j = 1; j <= n2; j++)
        {
            inner *= (x / j);
        }

        if (subtract)
        {
            s = s - inner;
        }
        else
        {
            subtract = s + inner;
        }
        subtract = !subtract;
    }
    return s;
}

样本运行:

Input n: 100
Input: 94
Result is -4417.00

上面的实现,当它需要计算时说(x^n)/(n!)。而不是计算

T  = (x*x*x*x....*x*x*x) / (1*2*3*4*5*6*....*(N-1)*N)`

在上面的表达式中,当尝试使用 powfactorial 函数进行计算时,分子和分母都会溢出。因此,它将计算为:

T = (x/1) * (x/2) * (x/3) * (x/4) * (x/5) * (x/6)

这避免了使用阶乘和 pow 函数。并且由于外层循环的每次迭代都是交替进行减法或加法运算,因此溢出的机会仍然较小。