使C浮子精确?

时间:2013-07-18 21:04:02

标签: c floating-point

在C中,设置浮点数时

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

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

98.599998

但是当我更精确的时候,

float temp = 96.600000f;

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

6 个答案:

答案 0 :(得分:10)

  

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

如果您需要精确的十进制值,请使用其他数据类型。

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

例如,如果要表示基数3中的数字,则十进制是不精确的。没有十进制0.1的精确二进制表示,就像没有“三分之一”的精确十进制表示一样。

所有这一切都需要解决您的要求,并使用与之匹配的数据类型。对于精确的十进制值,您可能最好使用第三方库...或者保持一个您知道的整数按逻辑缩放100或10,000或其他任何值。

答案 1 :(得分:6)

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

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

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

要用二进制表示,你可以得到整数96:

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

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

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(二进制编码的十进制),用于金融系统以避免舍入错误
  • 使用固定数据类型,其中数字表示为整数的分数,并且仅在计算结束时转换为浮点数以显示结果。

答案 2 :(得分:4)

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

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

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

答案 3 :(得分:3)

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

您可以使用printf精确指示符(如"%.2f")来“舍入”显示的数字。

答案 4 :(得分:1)

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

答案 5 :(得分:0)

赠品是浮动

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

因此,当你得到四舍五入的错误时,不要使用相等。您可以采取措施将其最小化,但这需要一些讲座和教科书。

BTW - 请勿使用花车。更好地使用整数和计算美分/便士/...