float转int注意事项

最近遇到一个低级错误,哈哈,都不好意思讲出来,会犯这种低级错误。写此博客,记录我的低级错误,以防下次再犯。

问题是这样的,我有一些float类型的数据,我需要将这这些浮点型数据放大到整数,然后转换成int类型数据,比如float a=5.1 * 10就得到整数51,然后将浮点型数据51赋值给一个int型数据:int b=static_cast<int>(a),我满以为b的结果就是51,然而事实给了我一记耳光,结果居然是50!我觉得很奇怪,这明明没问题啊,不用电脑一眼就看出来就是51,怎么会变成50?当我将a=5.2*10转换成int时结果又变成51,而5.5*10转换成int时结果又是对的,即55,这就更奇怪了。

后来查阅float类型数据的表示方法,才恍然大悟,原来float类型数据在计算机中是不能用二进制精确表示的,计算机在计算浮点型数据的时候常常是不精确的。以上面的情况为例,浮点型数据5.1是由整数部分和小数部分组成,整数部分的二进制为101,二进制可以精确的表示;小数部分的表示如下:

0.1*2=0.2 取0
0.2*2=0.4 取0
0.4*2=0.8 取0
0.8*2=1.6 取1
0.6*2=1.2 取1
...

5.1=101.0001100110011001100110011...(计算过程可以查阅浮点数的二进制表示,https://www.cnblogs.com/hoip/articles/4555375.html

可以看到小数部分是无限循环的,只有当小数部分为0.5是这个循环才结束,这就是为什么计算机无法精确表示浮点数的原因,也是为什么5.5*10转换成int没有出错的原因。将101.0001100110011001100110011小数点左移到第一个有效数字之后得到1.010001100110011001100110011...,从小数点后第一位开始数23位填充到float的尾数部分就得到float的尾数部分:01000110011001100110011,可见在这一步骤中又发生了一次不精确的取舍,小数点超出23位的部分舍去了,又损失了一次精度。上一步中移动了2位小数,因此指数部分为2+127=129,8位二进制为10000001,由于5.1是正数,因此符号位为0,所以5.1的二进制表示为:

0 10000001 01000110011001100110011

如果将上述二进制浮点数据转换成十进制,首先最高位为0,表示正数,取前8位:10000001=129,减去127为2,取前2位尾数部分01,首位添加1得到:101,即整数部分为101=5,23位尾数去掉已取走的2位得到小数部分:000110011001100110011=1/2*0+1/4*0+1/8*0+1/16*1+1/32*1+...=5.0999(保留4位小数),可见浮点数5.1在计算机中并不是存储的是5.1,而是一个无限接近5.1的数据,有可能是5.099999904...,也有可能是5.10002136...等。

至此提出的问题已经很清晰了,5.1*10的结果有可能是50.99999904,而在static_cast转int的时候,计算机是直接取整数部分,舍弃小数部分,因此结果就变成了50,而不是51。所以解决的方法就是四舍五入,或者是float数据加0.5再转换成int.即static_cast<int>(5.1*10+0.5)=51.

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值