2012-05-28 56 views
5

早上好,红宝石浮点数学 - 总结精度问题计算

我有一些浮点数学问题,并已完全失去了“.to_f”的,“* 100” 's和“.0”!

我希望有人能够帮助我解决我的具体问题,并解释为什么他们的解决方案能够工作,以便我下次明白这一点。

我的程序需要做两件事情:

  1. 总和小数的名单,确定它们是否归纳为准确的1.0
  2. 确定和数量的总和1.0之间的差异 - 设定的值变量的精确差异,使总和等于1.0。

例如:

  1. [0.28,0.55,0.17] - >的总和应为1.0,但是我不断收到1.xxxxxx。我在执行下面的时尚之和:

    sum = array.inject(0.0){|sum,x| sum+ (x*100)}/100 
    
  2. 我之所以需要这个功能,我在一组来自Excel中的小数正在阅读。它们不是100%精确的(它们缺少一些小数点),所以总和通常来自0.999999xxxxx或1.000xxxxx。例如,我会得到的值如下所示:

    0.568887955,0.070564759,0.360547286 
    

为了解决这个问题,我行采取前n-1数字的总和,然后更改最后一位数字稍微使所有的这些数字合计为1.0(必须满足使用上述公式进行验证,或者无论结果如何)。我目前正在实施这一如下:

  sum = 0.0 
      array.each do |item| 
      sum += item * 100.0 
      end 
      array[i] = (100 - sum.round)/100.0 

我知道我可以用注射做到这一点,但试图与它玩,看看是什么在起作用。我认为这通常是可行的(从检查输出),但它并不总是符合上述验证总和。所以如果需要的话,我也可以调整这个。请注意,在这些数字中我只需要两位小数精度 - 即0.56而不是0.5623225。我可以在介绍时或者在这个计算过程中将它们四舍五入......对我来说并不重要。

非常感谢您的帮助!

回答

8

如果准确性对您很重要,您不应该使用浮点值,根据定义,这些值不准确。Ruby有一些精确的数据类型来进行算术,其中准确性很重要。他们是我的头顶,BigDecimalRationalComplex,这取决于你实际需要计算的东西。

看起来在你的情况下,你要找的是BigDecimal,它基本上是一个具有固定数字位数的数字,其中有小数点后的固定数字位数(与浮点数,小数点后有任意数字的数字)。

当您从Excel中读取并故意将这些字符串(例如“0.9987”)转换为浮点时,您将立即丢失字符串中包含的准确值。

require "bigdecimal" 
BigDecimal("0.9987") 

该值是精确。它是0.9987。不是0.9,或者任何接近它的值,但是是0.9987。你可以使用所有通常的算术运算。如果您不将浮点数混合到算术运算中,则返回值将保持精确。

如果您的数组包含从Excel中得到了原始字符串(即你没有#to_f倒是他们),那么这会给你一个BigDecimal,这是他们的总和与1

1 - array.map{|v| BigDecimal(v)}.reduce(:+) 
之间的区别
+0

谢谢!有用的答案。 – Brandon

2

或者:

  • 继续使用花车和round(2)您汇总:12.341.round(2) # => 12.34

  • 使用整数(即美分而不是美元)

  • 使用BigDecimal的,你会不会需要只要你用BigDecimal开始,只有两位小数。

0

我认为算法在精度和精度方面比在另一种表示上选择IEEE浮点更重要。

人们曾经做过一些精细的计算,但仍然处理精度和精度问题。他们会通过管理他们使用的算法并理解如何更深入地表示函数来实现。我认为你可能会犯错误,抛弃更好的理解,并假设另一种表述是解决方案。

例如,没有函数的多项式表示将正确处理渐近线或奇点。

不要如此迅速地丢弃浮点数。我可以说,更聪明地使用它们的方式会很好。