输出是 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)`
在上面的表达式中,当尝试使用 pow
或 factorial
函数进行计算时,分子和分母都会溢出。因此,它将计算为:
T = (x/1) * (x/2) * (x/3) * (x/4) * (x/5) * (x/6)
这避免了使用阶乘和 pow 函数。并且由于外层循环的每次迭代都是交替进行减法或加法运算,因此溢出的机会仍然较小。
我需要计算以下内容:
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)
通过根据其先验值计算 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)`
在上面的表达式中,当尝试使用 pow
或 factorial
函数进行计算时,分子和分母都会溢出。因此,它将计算为:
T = (x/1) * (x/2) * (x/3) * (x/4) * (x/5) * (x/6)
这避免了使用阶乘和 pow 函数。并且由于外层循环的每次迭代都是交替进行减法或加法运算,因此溢出的机会仍然较小。