第一章(三) - 浮点数的精度问题
提示:个人学习总结,如有错误,敬请指正。
文章目录
- 第一章(三) - 浮点数的精度问题
- 一、double和float
- 1.原因
- 2.浮点数如何转换成二进制
- 3.哪些情况会碰到这类问题
- 4.解决办法
- 附录
一、double和float
1.原因
转换成二进制位数位数太长超过了存储位数,必须舍弃多余的位数,造成了精度损失。
计算机组成原理(定点数和浮点数边表示)
2.浮点数如何转换成二进制
浮点数的精度问题可不只是小数点的精度问题,随着数值越来越大,即使是整数也开始会有相同的问题,因为浮点数本身是一个 1.M * (2 ^ e) 公式形式得到的数字,当数字放大时,M的尾数的存储位数没有变化,能表达的位数有限,自然越来越难以准确表达,特别是数字的末尾部分越来越难以准确表达。
3.哪些情况会碰到这类问题
- 数值比较不相等
浮点数在运算时无法准确定位到某个值,比如要么比0.23小,要么比他大,这样就不能使用==来做检查而是使用>、<,如果要用等于,则必须使用一个很小的浮动区间,abs(X-Y) <0.00001,即X -Y >float.Epsilon。 - 数值计算不确定
浮点数由于位数限制无法得到一个精确的数值,而是一个被截断的值,在某些情况期望的结果是1,但算出来可能是0.9999999999。 - 设备不同,不同平台和架构会导致浮点数的精度不一致
4.解决办法
- 只计算一次,认定这个值为准确值,只用这个变量结果做判断,也省去了多次计算浪费的CPU。
- 改用int或long,把浮点数乘以10幂次得到更准确的整数,即把精度用整型表示,比如约定所有浮点数都乘以10000,1.5x10000=15000,用的时候再转回来。
- 定点数,即把整数位和小数位分开存
- decimal 并不好用(大部分游戏开发者的首选选择)
- 把整数和小数拆开来存储,用两个int整数分别表示整数部分和小数部分,或者用long长整型存储(前32位存储整数,后32位存储浮点数),long型存储会更好因为这样就确保定点数的内存就是连续的。这样无论整数还是小数部分都用整数表示,并封装在类中,继而我们需要重载(override)所有的基本计算和比较符号,包括+、-、*、/、==、!=、>、<、>=、<=、这些符号都需要重载,重载范围包括 float浮点数、double双精度、int整数、long长整数等。除了以上这些,为了能更好的融合定点数与外部数据的逻辑计算,我们还需要为此写一些额外的定点库,包括定点数坐标类,定点数Quaternion类等用于定点数的扩展。
- 字符串代替浮点数,但缺点是CPU和内存消耗大,只能做少量计算
- 最差的办法,提高期望值。
- 例子:如果 1.55f / 2f 有可能等于 0.7749999 而无法达到 0.775 的目标值时,我们不妨在计算前多加个0.01,使得 1.56f / 2f,这样就大概率保证超出 0.775 的结果目标了