main()
{
float f=123.456;
printf("f=%f/n",f);
}
如果不运行上面的代码,让我们来直接判断,输出的结果会是什么?
而在你运行程序之后,结果却很让人诧异:123.456001。为什么会是123.456001?有六位小数可以理解,最后那个1是为何?有很多人解释说最后那个1是乱码,随机的。嘿嘿~~其实无论你运行它多少次,最后始终都跟着一个1。这最后的那个1不是乱码,更不是随机的。
在数学中,表示一个浮点数需要三要素:尾数(Mantissa)、指数(Exponent,又称为阶码)和基数(Base)。任意一个浮点数N可以表示成下列形式:N = M × BE,例如N(10) =1.234×10-6, N(2)= -0.001011×2011等。
M和E决定了浮点数的精度(precision),E指明小数点在B进制数据中的位置,因而E和B决定了浮点数的表示范围(range),浮点数的符号(Sign)是单独考虑,表示为:
符号位(S) | 阶码(E) | 尾数(M) |
为便于软件的移植,浮点数的表示格式应该有统一标准。1985年IEEE(Institute of Electrical and Electronics Engineers)提出了IEEE754标准。该标准规定基数为2,阶码E用移码表示,尾数M用原码表示,根据原码的规格化方法,最高数字位总是1,该标准将这个1缺省存储,使得尾数的表示精度多了一位。实数的IEEE754标准的浮点数格式为:
类型 | 存储位数 | 总位数 | 偏移值
(offset)
| ||
数符(S) | 阶码(E) | 尾数(M) | |||
短实数(float) | 1 | 8 | 23 | 32 | 127 |
长实数(double) | 1 | 11 | 52 | 64 | 1023 |
说明:
1) 约定小数点左边隐含有一位1,实际上使尾数的有效位数为24位,即尾数为1.M
2) 偏移值 = 2 ^ (尾数位数 - 1) – 1。必须从指数中减去偏移值,才能确定有符号指数的实际值。
3) 讨论float型:
E = 0, M = 0 , 若 S = 0, 则N = 0; S = 1, 则 N = -0。-0可以表示一个很小的数,小到在单精度格式中不能
用数字和指数来表示。尽管如此,它们然小于0。
E = 0, M ≠ 0, 则数是有效的,但不是规格化数, N = (-1) ^ S × 2 ^ ( - 127) × (0.M)
E = 255, M = 0, 则数为正或负无穷大, 这取决于S.
E = 255, M ≠ 0, 则N不是一个数, 表示为NaN.
E = 1 ~ 254, 则N = (-1) ^ S × 2 ^ (E - 127) × (1.M), 为规格化数.
4) 具体可以参见<编码的奥秘>一书。
回到前面的问题,语句float f=123.456f; 经编译后生成的汇编语句为:
00401028 mov dword ptr [ebp-4],42F6E979h
十六进制值42F6E979h由何而来?
N (10) = 123.456,
换算成二进制表示:
N (2) = 1111011. 01110100101111001
= 1. 11101101110100101111001(...) * 2^6
那么E – 127 = 6; E = 127 + 6 = 133(10) = 10000101(2)
M = 111 0110 1110 1001 0111 1001 (省略了最高数字位1, 共23bit)
组合起来就是:
S E M
0 10000101 111 0110 1110 1001 0111 1001
4bit一间隔:
0100 0010 1111 0110 1110 1001 0111 1001
4 2 F 6 E 9 7 9
再由42F6E979h还原为float型
取出十六进制数42F6E979h, 化为二进制为
0*100 0010 1*111 0110 1110 1001 0111 1001(*为区分点)
s=0, E=133, M=(1/2+1/4+1/8+1/32+1/64+1/256+1/512+...)=0.92900002002716064453125
N=1*64*(1+0.92900002002716064453125)=123.45600128173828125
哈哈...
大功告成,与输出的结果吻合.
如果真要结果的话,可以这样:
printf("f=%0.3f/n",f);
以上环境为Window XP Professional + SP2, Intel P4, VC6.0
其实,上面的内容都是大学所学的东西,《体系结构》课程就讲这个。可惜这门课开在大四上学期,我一直忙于找工作,课都没有好好上,惭愧~~~