Ruby浮点数学 - Sum Calc中的精度问题

Bra*_*don 6 ruby math floating-point validation ruby-on-rails

大家早上好,

我在浮点数学方面遇到了一些问题,并且在".to_f","*100"和".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
    
    Run Code Online (Sandbox Code Playgroud)
  2. 我需要这个功能的原因是我正在读取一组来自excel的小数.它们不是100%精确(它们缺少一些小数点)所以总和通常来自0.999999xxxxx或1.000xxxxx.例如,我将获得如下值:

    0.568887955,0.070564759,0.360547286
    
    Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,我可以得到前n-1个数字的总和,然后稍微改变最终数字,以便所有数字总和为1.0(必须使用上面的等式,或者我最终得到的任何数字进行验证) ).我目前正在实现如下:

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

我知道我可以通过注射来做到这一点,但是试图用它来看看它有什么用.我认为这通常是有效的(从检查输出),但它并不总是符合上面的验证总和.所以,如果需要,我也可以调整这个.请注意,我在这些数字中只需要两个小数精度 - 即0.56而不是0.5623225.我可以在演示时或者在计算期间将它们围绕下来......对我来说无关紧要.

非常感谢您的帮助!

d11*_*wtq 9

如果准确性对您很重要,则不应使用浮点值,根据定义,浮点值不准确.Ruby有一些精确的数据类型,用于进行精度很重要的算术运算.它们是我的头顶BigDecimal,Rational并且Complex,取决于你实际需要计算的东西.

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

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

require "bigdecimal"
BigDecimal("0.9987")
Run Code Online (Sandbox Code Playgroud)

这个价值是准确的.它是0.9987.不是0.998732109,或任何接近它的东西,但是0.9987.您可以对其使用所有常用的算术运算.如果不将浮点混合到算术运算中,则返回值将保持精确.

如果你的数组包含你从Excel得到的原始字符串(即你没有#to_f它们),那么这将给你一个BigDecimal,它是它们之和和1的差值.

1 - array.map{|v| BigDecimal(v)}.reduce(:+)
Run Code Online (Sandbox Code Playgroud)