我正在写一个程序来计算sin(x)
和x
在[0, 1]
中,使用泰勒级数,包括将它的一些项提高到一定的幂。由于我是C的新手,我决定编写自己的pow()
函数来练习。但后来我注意到我的程序不能正确计算正弦函数。经过检查,我发现在循环中取一个数的幂不能产生与简单的直接乘法相同的结果……
这是我的powr()
函数和结果的差异:
#include <stdio.h>
double powr(double base, int power)
{
if (power == 0) {
base = 1;
} else if (power > 0) {
for (int i = 1; i < power; i++) {
base *= base;
}
} else {
// power is negative.
}
printf("In loop number to a power of 3: %lfn", base);
double hard_coded = 0.99 * 0.99 * 0.99;
printf("Out of loop number to a power of 3: %lfn", hard_coded);
return base;
}
int main(void)
{
double num = 0.99;
double num_to_power = powr(num, 3);
return 0;
}
输出:
In loop number to a power of 3: 0.960596
Out of loop number to a power of 3: 0.970299
0.960596和0.970299看起来可能没有太大的不同,但是随着数值的减小,误差会变得更大。为什么会这样,我该如何解决它?
还我刚刚注意到,如果我取0.123
这样的小值,然后取6
的幂。我有一个类似0.000000
的输出。我知道这事太小了,没法出席。但是,我如何打印一个浮点数后面有超过6个点数?我试过long double
,也没有工作。
您的循环计算错误。base *= base;
行将在每次循环中,将'累计'值乘以修改的值在前一个循环中,而不是通过原始值(应该如此)。
您需要存储传递的base
值,并将保存的值用作每次循环的乘数:
double powr(double base, int power)
{
double saved = base;
if (power == 0) {
base = 1;
}
else if (power > 0) {
for (int i = 1; i < power; i++) {
base *= saved;
}
}
else {
// power is negative.
}
printf("In loop number to a power of 3: %lfn", base);
double hard_coded = 0.99 * 0.99 * 0.99;
printf("Out of loop number to a power of 3: %lfn", hard_coded);
return base;
}
两个输出值将相等:
In loop number to a power of 3: 0.970299
Out of loop number to a power of 3: 0.970299
首先,你的循环没有计算你需要的东西:
for (int i = 1; i < power; i++) {
base *= base;
}
如果你在计算:
- 第一次迭代
base *= base
将得到base=0.99*0.99=0.9801
- 第二次迭代
base *= base
将得到base=0.9801*09801=0.96059601
通过累积以前的结果,您正在计算base^(2^(exp-1))
。那就不足为奇了。对于求幂,像这样的简单循环将使它:
result = base;
for (int i = 1; i < power; i++) {
result *= base;
}
如果你想让它更快,有一个简单的快速求幂使用平方(https://en.wikipedia.org/wiki/Exponentiation_by_squaring)。
第二,硬编码的版本可以由编译器以任何其他方式计算,并且由于浮点计算对舍入错误非常敏感,因此结果可能不同。