1

在 C 中,当设置一个浮点数时,

int main(int argc, char *argv[]) {
    float temp = 98.6f;
    printf("%f\n", temp);
    return 0;
}

它似乎总是会出现某种舍入错误,

98.599998

但是当我把它变得更精确时,

float temp = 96.600000f;

它仍然打印一个不同的数字。这应该如何解决?

4

6 回答 6

10

它仍然打印一个不同的数字。这应该如何解决?

如果您想要精确的十进制值,请使用不同的数据类型。

二进制浮点数精确的——只是它们是精确的二进制值。

例如,如果您想以 3 为基数表示数字,那么十进制也是不精确的。十进制 0.1 没有精确的二进制表示,就像“三分之一”没有精确的十进制表示一样。

只需弄清楚您的需求是什么,并使用与它们匹配的数据类型。对于精确的十进制值,您最好使用第三方库......或者保留一个您知道在逻辑上按 100 或 10,000 或其他值缩放的整数。

于 2013-07-18T21:06:16.880 回答
6

这是以二进制形式表示十进制数的基本限制。二进制浮点数以 2 的幂表示,而十进制数以 10 的幂表示,Cfloat根本无法准确表示所有十进制数。

您的示例编号 96.1 可以写为:

96.1 = 9*10^1 + 9*10^0 + 1*10^-1

为了用二进制表示,你可以得到整数 96 就好了:

96 = 1*2^6 + 1*2^5

但在基数 2 中表示 0.1 是有问题的。二进制中前几个小数位的位值是:

2^-1 = 0.5
2^-2 = 0.25
2^-3 = 0.125
2^-4 = 0.0625
2^-5 = 0.03125
2^-6 = 0.015625
2^-7 = 0.0078125
2^-8 = 0.00390625
2^-9 = 0.001953125
... and so on

因此,不知何故,您需要使用这些位置值的组合来加起来近似为十进制的 0.1。因此,您必须从 b0.0001 (d0.0625) 开始,因为它是小于 d0.1 的第一个位置,并添加更多的较小位置值以越来越接近 0.1。例如:

b0.001      = d0.125      // too high, try lower
b0.0001     = d0.0625     // too low, so add smaller places
b0.00011    = d0.09375    // good, closer... rounding error is 0.0625
b0.000111   = d0.109375   // oops, a little high
b0.00011001 = d0.09765625 // getting better - how close do you need?
...

等等 - 你明白了。因此,由于基本表示,二进制值只能近似小数。

有很多关于浮点舍入误差和表示限制的文章。绝对值得对这个主题进行一些背景阅读。

有几种方法可以解决这个问题:

  • 使用float但注意限制并仔细设计算法以最小化舍入误差
  • 使用精确的十进制表示,例如 BCD(二进制编码的十进制),在金融系统中用于避免舍入错误
  • 使用固定数据类型,其中数字表示为整数的分数,并且仅在计算结束时转换为浮点数以显示结果。
于 2013-07-18T21:12:41.217 回答
4

添加尾随零永远不会有所作为。

问题是 32 位浮点数不能精确表达96.6, 句号。

它不是随机选择数字来填充您遗漏的内容;它将它四舍五入到它可以表达的最接近的数字。

于 2013-07-18T21:05:52.380 回答
3

它取决于平台,但通常不能准确表示像 98.6 这样的数字。

您可以做的是使用printf精度说明符"%.2f",例如“四舍五入”显示的数字。

于 2013-07-18T21:06:20.890 回答
1

没有简单的答案。它与浮点数在内存中的表示方式有关,但我们倾向于认为它们可以表示所有实数。他们不能。如果您想精确地使用浮点数,请考虑小于或大于范围,而不是试图将它们等同起来。在您的示例中,尝试 %f2.1 (或类似的)在小数点右侧打印出少量数字。

于 2013-07-18T21:09:16.443 回答
0

赠品是浮动这个词。

它由尾数和指数组成。该值是它可以在有限的位数中实现的最佳表示(以 pi 为例)。

所以不要使用相等,因为你会得到舍入错误。您可以采取措施将它们最小化,但这需要一些讲座和一本教科书。

顺便说一句 - 不要用花车赚钱。更好地使用整数并以美分/便士/...

于 2013-07-18T21:10:28.997 回答