本文由ruby-china的一篇帖子“由小数的精度问题引出设计问题”引出,帖子也是我发的,在查看回复的时候学到了不少内容,有了一点感悟,所以就想总结一下。
首先声明本文选用的编程语言为ruby,运行环境是ubuntu。
在编写财务,电子商务之类应用的时候,经常会碰到小数,小数乘、除、加、减的场景。
大多数语言表示小数,都有单精度float,双精度double,还有一个更加精确的decimal,无论是哪一种,都统称为浮点数。
浮点数是一个近似的数值,不是精确的数值。至于为什么不精确,这个涉及到操作系统的底层,和二进制的保存有关。关于浮点数,以及浮点数计算产生精度损失的内容可以参看下面几篇文章。
浮点数
定点数与浮点数的区别
避免对C#中float,double,decimal的错误理解
浮点数操作精度损失
浮点数的比较
浮点数的四则运算都会有精度损失问题,会导致浮点数的逻辑运算结果超出日常生活的认识。
常见问题:
irb(main):005:0> 1.3-1.0 == 0.3 => false
颠覆了我们生活中的常识,因为在计算机中1.3-1.0的结果是 0.30000000000000004。
还有就是d * g / g 不一定等于d, d / g * g也不一定等于d。
这就造成,在很多时候,不能使用==来直接比较两个浮点数,因为浮点数不是精确数值,而是一个近似值。
怎么办呢?
既然是近似值,就是说他们两个非常接近,差距也就是0.00000000001之类的,反正很小。我们可以利用这个特性,写一个我们的两个浮点数比较的函数。只要我们确认两个浮点数之间的差距小到一个我们可以接受的值,就认为这两个浮点数是相等的。比如我们定义只要小于0.000000001,就算这两个浮点数是相等的,就可以写出下面的代码。
module FloatEqual def equal(b) return self==b || (self-b).abs < 0.000000001 end end (1.3-1.0).extend(FloatEqual).equal(0.3) # true
还有一个就是Saito在帖子中提到的一个方案,整数比较法。什么是整数比较法呢?就是将比较的双方都换算成整数,准确的说,就是双方都放大10倍,或者100倍,或者1000倍,反正就是放大同样的倍数,保证双方都是整数,这时候再来计算,再来比较。
为什么呢?因为整数的保存不存在精度损失问题,整数的四则运算不存在精度损失问题,所以计算结果的比较就可以是正确的,可以直接用==来比较了,
(1.3*10 - 1.0*10) == 0.3*10 # true
在ruby中还可以使用BigDecimal来比较浮点数,或者进行浮点数的四则运算,也可以避免精度损失导致的问题。
BigDecimal.new("1.3")-BigDecimal.new("1")==BigDecimal.new("0.3") # true
以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索问题
, bigdecimal
, 浮点数
, 浮点数运算
, 精度
, 整数
, 小数
, 运算放大
, double精度问题
, 浮点数的问题
, 计算精度
, #浮点数
, 一个
点数
浮点数精度问题、浮点数计算精度问题、js浮点数精度问题、java 浮点数精度问题、双精度浮点数,以便于您获取更多的相关知识。