c中浮点的精确表示

void main() { float a = 0.7; if (a < 0.7) printf("c"); else printf("c++"); } 

在上面的问题0.7中,将打印“c”,但是对于0.8,将打印“c ++”。 为什么?

以二进制forms表示任何浮点数如何?

在某些地方,提到内部0.7将存储为0.699997,但0.8存储为0.8000011。 为什么这样?

基本上用浮点数你会得到32位编码

 VALUE = SIGN * MANTISSA * 2 ^ (128 - EXPONENT) 32-bits = 1-bit 23-bits 8-bits 

并存储为

 MSB LSB [SIGN][EXPONENT][MANTISSA] 

因为你只得到23位,这就是你可以存储的“精度”。 如果您试图表示在基数2中无理(或重复)的分数,则位序列将在第23位“舍入”。

0.7 base 10是7/10,二进制是0b111 / 0b1010你得到:

 0.1011001100110011001100110011001100110011001100110011... etc 

由于这种情况重复,因此在固定精度下无法准确表示它。 同样适用于0.8,二进制是:

 0.1100110011001100110011001100110011001100110011001101... etc 

要查看这些数字的固定精度值是什么,您必须以比特数“切断它们”并进行数学运算。 唯一的技巧是你隐含的前导1并没有存储,所以你在技术上获得了额外的精度。 由于舍入,最后一位将是1或0,具体取决于截断位的值。

因此,0.7的值实际上是11,744,051 / 2 ^ 24(无舍入效应)= 0.699999988,而0.8的值实际上是13,421,773 / 2 ^ 24(向上舍入)= 0.800000012。

这里的所有都是它的 :)

对此有一个很好的参考是每个计算机科学家应该知道的浮点运算 。 如果需要,可以使用更高精度类型(例如double)或二进制编码十进制(BCD)库来获得更好的浮点精度。

内部代表是IEE754 。

您也可以使用此计算器将十进制转换为浮点数,我希望这有助于理解格式。

float s将按照IEEE 754:1位中的符号进行存储,8表示偏置指数,其余存储小数部分。

可以将数字表示为浮点数作为数字线上的点,相隔一段距离; 通常,小数部分将落在这些点之间,并且将使用最近的表示; 这会导致您描述的违反直觉的结果。

“每个计算机科学家应该了解浮点运算”应该详细回答所有问题。

如果你想知道C(以及几乎所有语言)中的float / double是如何呈现的,请参考标准的浮点运算(IEEE 754) http://en.wikipedia.org/wiki/IEEE_754-2008

 Using single-precision floats as an example, here is the bit layout: seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm meaning 31 0 bit # s = sign bit, e = exponent, m = mantissa 

查看浮点数如何在计算机中存储为二进制文件的另一个好资源是维基百科在IEEE-754上的页面。

C / C ++中的浮点数以IEEE-754标准格式表示。 互联网上有很多文章,它们比我在这里描述得更详细,如何用二进制表示一个浮点。 对IEEE-754的简单搜索应该可以解释这个谜团。

0.7是数字文字; 它的值是数学实数0.7,四舍五入到最接近的双精度值。

初始化浮点数a = 0.7后,a的值为0.7舍入为浮点数,即实数0.7,舍入到最接近的double值,四舍五入到最接近的浮点值。 除了一个巨大的巧合,你不会指望a等于0.7。

“if(a <0.7)”比较0.7舍入为double然后浮动,数字0.7舍入为double。 似乎在0.7的情况下,舍入产生较小的数字。 并且在0.8的相同实验中,将0.8舍入到浮点将产生大于0.8的数字。

无论你做什么,浮点比较都不可靠。 您应该使用阈值容忍比较/ epsilon浮点比较。

尝试IEEE-754浮点转换 ,看看你得到了什么。 🙂