繁体   English   中英

使C浮点数精确吗?

[英]Making C floats precise?

在C语言中,设置浮点数后,

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

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

98.599998

但是当我说得更精确时,

float temp = 96.600000f;

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

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

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

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

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

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

这是以二进制形式表示十进制数字的基本限制。 二进制浮点数以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

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

添加尾随零将无济于事。

问题是32位浮点不能精确表示96.6周期。

这不是随机挑选数字来填补您遗漏的内容; 将其四舍五入为它可以表示的最接近的数字。

它依赖于平台,但是通常无法准确表示98.6之类的数字。

您可以做的是使用诸如"%.2f"类的printf精度说明符来“舍入”所显示的数字。

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

赠与是float一词。

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

因此,在出现舍入错误时,请不要使用相等性。 您可以采取措施将其最小化,但这需要一些讲座和一本教科书。

顺便说一句-不要用浮子赚钱。 更好地使用整数并以美分/便士/ ...来计算...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM