我在浮点数学方面遇到了一些问题,并且在“.to_f”,“* 100”和“.0”中完全丢失了!
我希望有人可以帮我解决我的具体问题,并解释为什么他们的解决方案有效,以便我下次理解这一点.
我的程序需要做两件事:
>求和小数列表,确定它们是否总和为1.0
>确定1.0和数字之和之间的差异 – 将变量的值设置为精确差值,使总和等于1.0.
例如:
> [0.28,0.55,0.17] – >应该总和为1.0,但我一直得到1.xxxxxx.我正在以下列方式实现总和:
sum = array.inject(0.0){|sum,x| sum+ (x*100)} / 100
>我需要这个功能的原因是我正在读取一组来自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.我可以在演示时或者在计算期间将它们围绕下来……对我来说无关紧要.
非常感谢您的帮助!
解决方法
BigDecimal
,Rational
和
Complex
.
看起来在你的情况下,你正在寻找的是BigDecimal,它基本上是一个具有固定位数的数字,其中小数点后面有一个固定的位数(与浮点相反,小数点后面有任意位数).
当您从Excel中读取并故意将这些字符串(如“0.9987”)转换为浮点时,您将立即丢失字符串中包含的准确值.
require "bigdecimal" BigDecimal("0.9987")
这个价值是准确的.它是0.9987.不是0.998732109,或任何接近它的东西,但是0.9987.您可以对其使用所有常用的算术运算.如果不将浮点混合到算术运算中,则返回值将保持精确.
如果你的数组包含你从Excel得到的原始字符串(即你没有#to_f’d它们),那么这将给你一个BigDecimal,它是它们之和和1的差值.
1 - array.map{|v| BigDecimal(v)}.reduce(:+)