2012-10-28

Ruby の Float#round

PHPの新しいround関数を読み解く (2)pre-roundingの意味 - hnwの日記 を読んだ.次のようにして確かめてみた.

$ uname -mrs
Darwin 9.8.0 i386
$ ruby -v
ruby 1.8.6 (2009-06-08 patchlevel 369) [universal-darwin9.0]
$ irb
>> 1.255
=> 1.255
>> 1.255 * 10**2
=> 125.5
>> ( 1.255 * 10**2 ).round.quo( 10**2 )
=> 1.25
>> 125.5.round
=> 126
>> sprintf( '%.17e', 1.255 )
=> "1.25499999999999989e+00"
>> sprintf( '%.17e', 1.255 * 10**2 )
=> "1.25499999999999986e+02"
>> sprintf( '%.17e', 125.5 )
=> "1.25500000000000000e+02"

上で引用した記事より:

まず、1.255のような場合への対策が必要かどうかについての議論があるでしょう。これは僕も非常に疑問ではありますが、「小数点以下n位への丸めを行う引数を提供している時点で、小数が10進で格納されているかのような振る舞いをすべきだ」という考えは理解できます。整数以外の桁への丸めを導入したこと自体が関数設計レベルの失敗であり*3、今さらこの引数を撤回できない以上、この実装も必要だということで僕個人は納得しています。

Ruby 1.8.7 の Float#round は,このような丸める位を指定する引数を取らない.1.255 を 1.26 に丸めるには,BigDecimal を使うのが正解ということになるか.

>> require 'bigdecimal'
=> true
> BigDecimal( 1.255.to_s )
=> #<BigDecimal:586ec,'0.1255E1',8(8)>
>> BigDecimal( 1.255.to_s ).round( 2 )
=> #<BigDecimal:50758,'0.126E1',8(16)>

Ruby 1.9.3 の Float#round は,丸める位を指定する引数を取る.この動きはまだ見ていない.