【问题标题】:Simple C Program dealing with decimals [duplicate]处理小数的简单C程序[重复]
【发布时间】:2012-04-09 07:07:49
【问题描述】:

可能重复:
strange output in comparision of float with float literal

所以程序只是读入一堆数字,然后通过除以输入的总数来找到它们的平均值。但是,最终结果最后会增加几个小数,我不知道为什么会这样。

对于这个给定的输入: 483、10、3051、188、200、0

输出应该是 786.4 但它是 786.400024。我究竟做错了什么?在此先感谢各位。

int main(int argc, char** argv)
{
    int averageOfNumbers = 0;

    printf("Enter the sequence of numbers:");
    int nextNumber;
    float numberCounter = 0;
    do
    {
            scanf("%d", &nextNumber);
            if(nextNumber > 0)
            {
                    numberCounter++;
                    averageOfNumbers += nextNumber;
            }
    } 
    while(nextNumber > 0);
    float finalAverage = (float) (averageOfNumbers/numberCounter);
    averageOfNumbers = averageOfNumbers/numberCounter;
    printf("Average of the numbers in the sequence is %f\n", finalAverage);

}

【问题讨论】:

标签: c floating-point decimal average


【解决方案1】:

浮点数提供了对实数的精确但不精确的近似值。 (精度取决于它们的大小:在您使用的浮点类型中有多少位可用的精度。)

IEEE 754 浮点(在许多计算机上使用的非常流行的表示)使用二进制。这意味着精确表示二进制分数,例如 1/2、1/4、1/8 及其组合:3/8、5/16 等(在可用精度位数的限制内)。不是基于 2 的幂的分数不能精确表示。

数字 1/10 或 0.1 没有精确的表示。当您将 0.1 输入机器时,它会被转换为一个具有许多接近 0.1 的二进制数字的值。当您使用 printf 或您拥有的其他内容打印回来时,您会再次得到 0.1,因为 printf 函数会将其四舍五入,因此看起来 0.1 正在被精确表示:0.1 进入机器,天哪,0.1 出来了。假设看到0.1 和实际值之间的差异需要 10 位小数的精度,但您只打印到 8 位。好吧,当然它会显示为0.1。您的浮点打印例程已经消除了错误!

C printf 中的%f 转换说明符将使用更多位数来表示较大的数字,因为它使用小数点后的固定位数,默认为六位。因此,例如 0.002 将打印为 0.002000。但是数字 123456 将打印为 123456.000000。数量级越大,打印的有效数字就越多。当您使用 %f 打印 786.4 时,您实际上是在要求 9 位小数的精度。 3 个用于 786 整数部分,然后是 6 个。

您正在使用float,它很可能是 32 位 IEEE 754 浮点数。这只有 24 位精度。 (1 位用于符号,7 位用于二进制指数,剩下 24 位。) 24 位仅相当于大约 7 个十进制数字的精度!

因此,您要求机器将 786.4(它的表示不准确,记住!)从仅适用于大约 7 个十进制有效数字的浮点表示中打印到 9 个有效数字。您要求再提供两位不存在的精度,因此得到两位错误数字。

因此,您可以做的是使用更广泛的类型,例如 double 和/或更改打印结果的方式。不要要求这么多有效数字。例如尝试%.3f(小数点后三位)。

顺便说一句,C 中的float 类型应该很少使用。您通常希望使用double 类型。 float 有它的用途,比如在大数组中节省空间。

【讨论】:

    【解决方案2】:

    浮点类型不能完全准确地表示所有数字 - 许多数字只能用浮点近似表示;这意味着,如果有足够多的有效数字,您最终会发现那些无法完全融入表示的数字的精度损失。

    使用 float 数据类型的问题在于它是浮点类型中最不准确的。 (C 和 C++ 中的默认浮点类型是 double - 这是你应该使用的类型;你应该避免使用 float 除非你有一些令人信服的理由来使用它除此以外)。在现代 32 位桌面平台上,对于某些近似数字,float 可能仅准确到大约 6-7 位有效数字,同一平台上的 double 可能准确对于相同的数字,大约 13-14 s.f(注意:这是有效数字,不是小数位!)。

    我强烈建议您花时间阅读浮点数的工作原理(将其输入谷歌,您会找到大量解释!);了解它们在内部的表示方式将有助于您成为更好的程序员

    【讨论】:

    • 了解浮点数将使您成为更好的数字分析师。如果你想成为一个更好的程序员,发誓在你的余生中不要使用浮点。我最近在 infoq 上观看了 Gerald Sussman 的一次演讲,他承认每当代码中有浮点数时他都会感到害怕。哇,正是我的想法。 :)
    • 谈话在这里:infoq.com/presentations/We-Really-Dont-Know-How-To-Compute。并且评论从0:11:00左右开始。他说,“......危险的浮点数”“没有什么比浮点数更让我感到恐惧了””数值分析:我所知道的最大的魔法”。哈哈!干杯。
    【解决方案3】:

    使用双精度可以解决您的问题。浮点数的准确性和精度是问题的根源。

    【讨论】:

    • 使用 double 可以将问题进一步扫除。如果将该值打印到 double 下更重要的数字,您将再次揭示结果在 double 中也没有精确表示的事实。
    猜你喜欢
    • 1970-01-01
    • 2016-03-21
    • 2023-03-30
    • 1970-01-01
    • 2015-11-01
    • 2013-05-14
    • 2015-03-22
    • 2018-09-01
    • 1970-01-01
    相关资源
    最近更新 更多