生成一个浮点数组会产生一个奇怪的结果

时间:2014-10-07 13:56:24

标签: ruby arrays floating-point enumerable

我想生成一个float数组。例如,这一个:

[0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0]

所以,我使用这条小线:

(0.5..2).step(0.1).to_a

但它产生了这个:

[0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2000000000000002, 1.3, 1.4, 1.5, 1.6, 1.7000000000000002, 1.8, 1.9000000000000001, 2.0]

我做错了什么?

4 个答案:

答案 0 :(得分:6)

无法精确表示0.1等浮点数。使用浮动指针数作为步骤会给你意想不到的结果。

更好的选择是:

(5 .. 20).map {|e| e / 10.0}
#=> [0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0]

答案 1 :(得分:3)

使用Rational Literals,然后映射到Floats

浮点数可以咬你。具体而言,binary can't represent 0.1 accurately。 Ruby有许多类可以准确处理任意精度的数字,包括BigDecimalRational

您可以使用新的2.1 syntax for rational literals来创建一系列花车。例如:

(0.5r..2r).step(0.1r).map &:to_f
#=> [0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0]

这样做可能看起来比currently-accepted answer更混乱,但这种方法适用于更广泛的精度问题,其中除以10.0不是解决方案。

答案 2 :(得分:1)

我会像@YuHao建议的那样做 - 干净且易于阅读 - 但我想指出你也可以使用BigDecimal类:

require 'bigdecimal'

v = BigDecimal.new(0.5, 1)
a = (20-5+1).times.with_object([]) { |_,arr| arr << v.to_f; v += 0.1 }
  #=> [0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2,
  #    1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0]

注意:

  • 使用BigDecimal初始化Float对象时,必须给出精度(此处为, 1)。
  • 如果vBigDecimal的实例,v + 0.1也是如此。
  • BigDecimal没有succ方法,因此无法进行迭代。因此,不能只将BigDecimal范围映射到Floats数组中。 (BD的范围是允许的,但我质疑无法迭代的范围的效用。)

答案 3 :(得分:0)

另一个问题,如何获得此结果(保留2位小数)

[0.50,0.60,0.70,0.80,0.90,1.00,1.10,1.20,1.30,1.40,1.50,1.60,1.70,1.80,1.90,2.00]