美文网首页
转浮点数丢失精度的问题

转浮点数丢失精度的问题

作者: cocoa | 来源:发表于2018-08-22 15:14 被阅读26次

现象

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

结论

浮点数能提供越多的有效位数,浮点数的值就越接近他所表示的值。

相关文章

网友评论

      本文标题:转浮点数丢失精度的问题

      本文链接:https://www.haomeiwen.com/subject/wmaeiftx.html