为什么在循环中具有浮点的数字的乘法不像其外部那样精确?

发布于 2025-01-26 11:20:45 字数 1243 浏览 4 评论 0原文

我正在编写一个程序来计算x[0,1]中计算 ,使用泰勒系列,其中包括提高其中的某些特定权力的术语。由于我是C的新手,因此我决定仅以练习来编写自己的pow()功能。但是后来我注意到我的程序无法正确计算正弦功能。在检查时,我发现在循环中提高一个数字并没有产生与简单直接乘法相同的结果... v * v * v ...

这是我的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: %lf\n", base);
    double hard_coded = 0.99 * 0.99 * 0.99;
    printf("Out of loop number to a power of 3: %lf\n", 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个点数的浮点数?我尝试了长double,也没有起作用。

I was writing a program to calculate sin(x) with x in [0, 1], using Taylor series that include raising some of its terms to a certain power. Since I'm new to C, I decided to write my own pow() function just to practice. But then I noticed that my program doesn't calculate the sine function correctly. Upon an examination, I discovered that raising a number to a power in a loop doesn't produce the same result as simple straightforward multiplication ...v * v * v...

Here's my powr() function and difference in results:

#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: %lf\n", base);
    double hard_coded = 0.99 * 0.99 * 0.99;
    printf("Out of loop number to a power of 3: %lf\n", hard_coded); 

    return base;
}

int main(void)
{
    double num = 0.99;
    double num_to_power = powr(num, 3);
    return 0;
}

Output:

In loop number to a power of 3: 0.960596
Out of loop number to a power of 3: 0.970299

0.960596 and 0.970299 may not look that different, but with smaller values an error becomes even bigger.
Why is that and how can I solve it?

Also, I just noticed that if I take small values like 0.123 and raise them to a power of 6, for example. I have an output like 0.000000. I understand that it's just too small to show up. But how can I print an a floating-point number that has more than 6 after point numbers? I've tries long double, didn't work either.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

漫漫岁月 2025-02-02 11:20:46

您的循环计算是错误的。 base *= base;线将在每个循环上,将“累计”值乘以修改的值在上一个循环上,而不是通过< em>原始 value(应该)。

您需要存储传递的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: %lf\n", base);
    double hard_coded = 0.99 * 0.99 * 0.99;
    printf("Out of loop number to a power of 3: %lf\n", 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

Your loop calculation is wrong. The base *= base; line will, on each loop, multiply the 'accumulated' value by the value that has been modified on the previous loop, rather than by the original value (as it should).

You need to store the passed base value and use that saved value as the multiplier on each loop:

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: %lf\n", base);
    double hard_coded = 0.99 * 0.99 * 0.99;
    printf("Out of loop number to a power of 3: %lf\n", hard_coded);

    return base;
}

The two output vales will then be equivalent:

In loop number to a power of 3: 0.970299
Out of loop number to a power of 3: 0.970299
单身狗的梦 2025-02-02 11:20:46

首先,您的循环不会计算所需的内容:

for (int i = 1; i < power; i++) {
    base *= base;
}

在您的情况下,您正在计算:

  1. 第一个迭代base *= base将给出base = 0.99 *0.99 = 0.9801
  2. second Iteration <代码> base *= base 将给出base = 0.9801 *09801 = 0.96059601

通过累积先前的结果,随着时间的流逝,您正在计算base^(2^(exp-1)<(exp-1)< /代码>。那就不足为奇了。为了进行启动,这样的简单循环将使它成为:

result = base;
for (int i = 1; i < power; i++) {
    result *= base;
}

如果您想更快地使其使用平方,则存在一个简单的快速凸起( https://en.wikipedia.org/wiki/exponention_by_squaring )。

其次,硬编码版本可以由编译器以任何其他方式计算,并且由于浮点计算对于四舍五入的错误非常明智,因此结果可能是不同的。

First, your loop does not calculate what you need:

for (int i = 1; i < power; i++) {
    base *= base;
}

In you case you are calculating:

  1. first iteration base *= base will give base=0.99*0.99=0.9801
  2. second iteration base *= base will give base=0.9801*09801=0.96059601

By accumulating previous result over time you are calculating base^(2^(exp-1)). No surprise then. For exponentiation a simple loop like this will make it:

result = base;
for (int i = 1; i < power; i++) {
    result *= base;
}

There exists a simple fast exponentiation that use squaring if you want to make it faster (https://en.wikipedia.org/wiki/Exponentiation_by_squaring).

Second, the hard coded version can be computed by the compiler in any other way, and as floating point computation is very sensible to rounding errors, the result may be different.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文