【问题标题】:Differences between using variable and using direct number in C languageC语言中使用变量和使用直接数的区别
【发布时间】:2021-09-19 02:43:07
【问题描述】:

我有这样的程序

int a = 100;
float b = 1.05;
printf("%f\n", a * b);
printf("%f\n", 100 * 1.05);

它的输出如下所示:

104.999992
105.000000

我了解 `104.99992' 是由于浮点精度问题造成的。但是为什么使用直接数不会导致准确性的损失呢?

【问题讨论】:

标签: c floating-point precision


【解决方案1】:

a * b 使用 float 算术。 100 * 1.05 使用 double 算术。

您的 C 实现可能使用 IEEE-754 binary64 表示 double 和 binary32 表示 float

1.05 是一个 double 常量。源文本中的十进制数字 1.05 转换为最接近的可表示 double 值,即 4728779608739021•2-52 = 1.0500000000000000444089209850062616169452667236328125。

float b = 1.05; 将该值转换为float。转换的结果是最接近的可表示float 值,即 4728779393990656•2-52 = 4404019•2-22 = 1.0499999523162841796875。

bfloat 算术中乘以100 时,结果是最接近实数算术结果的可表示float 值。它是 13762559•2-17 = 104.99999237060546875。

当打印小数点后六位时,结果为“104.999992”。

100 * 1.05中,仅使用double算术;没有float 值。当double 1.05000000000000000444089209850062616169452667236328125 乘以 100 时,结果是最接近实数运算结果的 double。是105•20 = 105。当打印小数点后六位时,结果当然是“105.000000”。

总结:浮点运算一般存在舍入误差。在float 算术中,当打印多个数字时,它们很容易被看到。在这个使用 double 算术的示例中,舍入误差恰好抵消了——最接近 1.05 的 double 略高于 1.05,因此转换中的舍入向上舍入。然后,当它乘以 100 时,最接近实数运算结果的 double 略低于它,因此乘法中的舍入向下舍入。这些有效地取消了,产生了 105 个。

如果执行printf("%f\n", 100*1.05f);1.05f 将直接转换为float 而不是double,并且乘法将使用float 算术,1 和您将看到与 a * b 相同的结果。

脚注

1 C 标准允许使用额外的精度,但通常您会在这里看到相同的结果。

【讨论】:

    猜你喜欢
    • 2017-03-19
    • 1970-01-01
    • 2018-09-12
    • 2011-09-10
    • 1970-01-01
    • 2018-08-12
    • 2020-11-24
    • 1970-01-01
    • 2012-12-12
    相关资源
    最近更新 更多