浮点数的坑
0.0 与 -0.0 不同
在浮点数中,double
类型的0.0
用0x0000000000000000
表示,-0.0
用0x8000000000000000
表示;float
类型的0.0
用0x00000000
表示,-0.0
用0x80000000
表示;
所以printf("%.1f", -0.0)
会输出-0.0
并不是0.0
。
1 | double d1 = 0.0; |
输出:
1 | d1 = 0.000000 (0x0000000000000000) |
0.1+0.2 == 0.3 输出 false
不是所有小数都可以用「完整」的二进制来表示的,比如十进制 0.1 在转换成二进制小数的时候,是一串无限循环的二进制数,计算机是无法表达无限循环的二进制数的,毕竟计算机的资源是有限。
因此,计算机只能用「近似值」来表示该二进制,那么意味着计算机存放的小数可能不是一个真实值。
现在基本都是用 IEEE 754 规范的「单精度浮点类型」或「双精度浮点类型」来存储小数的,根据精度的不同,近似值也会不同。
0.1
的二进制浮点数转换成十进制的结果是 0.100000001490116119384765625
0.2 的二进制浮点数转换成十进制的结果是 0.20000000298023223876953125
这两个结果相加就是 0.300000004470348358154296875
所以,你会看到在计算机中 0.1 + 0.2 并不等于完整的 0.3。
1 | double a = 0.1; |
输出:
1 | 0.1: 0.100000000000000005551115123126 |
输出数据与输入数据不一致
比如:单精度浮点赋值20.3,然后将该浮点打印输出,代码及打印结果如下,
1 | float a=20.3f; |
为什么结果与预期不一样,就是因为20.3并不在浮点的数据集合中,编译器会选择最接近20.3的一个数据,这个数据的编码为0x41a26666,转化为10进制为20.2999992。
解决办法:通过四舍五入,保证有效位以内的10进制有效数字,代码及打印结果如下所示:
1 | float a=20.3f; |
printf(“%.0f”, 4.5) 输出4 而 printf(“%.0f”, 5.5)输出6
printf输出浮点数时默认使用四舍六入五留双的数值修约法。
也就是说,