现象
NSNumber *num = @111.11;
float f = num.floatValue;
NSLog(@"%f",f);
打印log,f值为111.110001
NSNumber *num = @11.11;
float f = num.floatValue;
NSLog(@"%f",f);
打印log,f值为111.110000
原因
十进制小数111.11表示成浮点数为
//双精度
0100000001011011110001110000101000111101011100001010001111010111
//单精度
01000010110111100011100001010010
- 双精度
符号位s: 0
指数位e: 10000000101
有效数f:1011110001110000101000111101011100001010001111010111
有效数的整数部分:101111
有效数的小数部分:0001110000101000111101011100001010001111010111 - 单精度
符号位s: 0
指数位e: 10000101
有效数f:10111100011100001010010
有效数的整数部分:101111
有效数的小数部分:00011100001010010
十进制小数11.11表示成浮点数为
//单精度
01000001001100011100001010001111
- 单精度
符号位s: 0
指数位e: 10000010
有效数f:01100011100001010001111
有效数的整数部分:011
有效数的小数部分:00011100001010001111
比较小数部分(0.11)
//双精度
00011100001010010 //单精度 111.11
00011100001010001111 //单精度 11.11
0001110000101000111101011100001010001111010111 //双精度 111.11
因为二进制小数只能准确表示以2的次方为分母的分数,所以十进制小数不能一一对应一个二进制小数,我们看到十进制小数0.11转换成二进制小数是一个无限小数。因为浮点数的有效位数是有限的,所以我们拿到的是近似等于0.11的二进制浮点数。
单精度浮点数的有效位数是23位
· 111.11可提供给小数部分的位数是17位
· 11.11可提供给小数部分的位数是20位双精度浮点数的有效位数是52位
· 我们借此看一看到0.11更长,更精确一点的二进制小数表示浮点数默认的舍入规则是向偶数舍入
· 首先做向上舍入和向下舍入,判断精度损失,选择精度损失最小的舍入方式.
· 如果精度损失是一样的,那么选择舍入后最低有效位为偶数的舍入方式.
0001110000101000111101011100001010001111010111 //46位
//舍入至20位
00011100001010001111 //等于十进制的0.109999656677246
//舍入至17位
00011100001010010 //等于十进制的0.110000610351563
浮点数的显示精确到小数点后6位,也就是我们看到的0.110000和0.110001
结论
浮点数能提供越多的有效位数,浮点数的值就越接近他所表示的值。