('%.20g' % 1.001r).to_r != 1.001r

有理数しか使っていないのに誤差があり、なんでだろうと思って調べた。
直接の原因は、"%g" による書式化。

```ruby
# ruby 2.2.0
"%.20g" % 1.001r #=> "1.0009999999999998899"
```

しかし、%f は大丈夫。

```ruby
# ruby 2.2.0
"%.20f" % 1.001r #=> "1.00100000000000000000"
```

かと思ったら、1.9 だとそうでもない。

```ruby
# ruby 1.9.3-p551
"%.20f" % "1.001".to_r #=> "1.00099999999999988987"
```

という状況に不安を感じ、いろいろ実験してみた：

#調査結果

##ruby 2.2.0p0

||Rational|Float|
|:--|:--|:--|:--|:--|
|inspect|(1001/1000)|1.001|
|to_s|1001/1000|1.001|
|%f|1.001000|1.001000|
|%.20f|1.00100000000000000000|1.00099999999999988987|
|%g|1.001|1.001|
|%.20g|1.0009999999999998899|1.0009999999999998899|
|%e|1.001000e+00|1.001000e+00|
|%.20e|1.00099999999999988987e+00|1.00099999999999988987e+00|

##ruby 2.1.5p273

||Rational|Float|
|:--|:--|:--|:--|:--|
|inspect|(1001/1000)|1.001|
|to_s|1001/1000|1.001|
|%f|1.001000|1.001000|
|%.20f|1.00099999999999988987|1.00099999999999988987|
|%g|1.001|1.001|
|%.20g|1.0009999999999998899|1.0009999999999998899|
|%e|1.001000e+00|1.001000e+00|
|%.20e|1.00099999999999988987e+00|1.00099999999999988987e+00|

##ruby 2.0.0p598

||Rational|Float|
|:--|:--|:--|:--|:--|
|inspect|(1001/1000)|1.001|
|to_s|1001/1000|1.001|
|%f|1.001000|1.001000|
|%.20f|1.00099999999999988987|1.00099999999999988987|
|%g|1.001|1.001|
|%.20g|1.0009999999999998899|1.0009999999999998899|
|%e|1.001000e+00|1.001000e+00|
|%.20e|1.00099999999999988987e+00|1.00099999999999988987e+00|

##ruby 1.9.3p551

||Rational|Float|
|:--|:--|:--|:--|:--|
|inspect|(1001/1000)|1.001|
|to_s|1001/1000|1.001|
|%f|1.001000|1.001000|
|%.20f|1.00099999999999988987|1.00099999999999988987|
|%g|1.001|1.001|
|%.20g|1.0009999999999998899|1.0009999999999998899|
|%e|1.001000e+00|1.001000e+00|
|%.20e|1.00099999999999988987e+00|1.00099999999999988987e+00|

##jruby 1.7.18 (1.9.3p551)

||Rational|Float|
|:--|:--|:--|:--|:--|
|inspect|(1001/1000)|1.001|
|to_s|1001/1000|1.001|
|%f|1.001000|1.001000|
|%.20f|1.00100000000000000000|1.00100000000000000000|
|%g|1.001|1.001|
|%.20g|1.001|1.001|
|%e|1.001000e+00|1.001000e+00|
|%.20e|1.00100000000000000000e+00|1.00100000000000000000e+00|

#調査のためソースコード

```ruby
vals=[ "1.001".to_r, 1.001]
forms=[:inspect, :to_s] + %w( %f %.20f %g %.20g %e %.20e)
puts (["",""]+vals.map( &:class)+[""]).join("|")
puts( "|:--"*5+"|")
forms.map{ |f|
  s=["", f]+vals.map{ |v|
    case f
    when Symbol
      v.send(f)
    else
      f % v
    end
  }+[""]
  puts s.join("|")
}
```

#まとめ

* `"%.20f" % 1.001r` の件は、 2.1.5 まではなんかおかしかったけど、2.2.0 で治ったらしい。
* `"%.20g" % 1.001r` と  `"%.20e" % 1.001r` は 2.2.0 でも治ってない。
* jruby の `"%.20f"%1.001` の出力は誠実じゃないと思う。

## 他の言語で `"%.20f" % 1.001` がどうなるか。

1.001 の浮動小数点表現はぴったり 1.001 ではないので、`"%.20f" ` のようなことをしたときに `1.00100000000000000000` のような出力をするのは誠実ではないように思う。

他の言語がどうしているのか調べてみた。

```ruby
(1..3).map{ |x| "%.20f" % (1.001*x ) }
```

```groovy
(1..3).collect{sprintf("%.20f",it*(double)1.001)}
```

```python
["%.20f" % (x*1.001) for x in [1,2,3]]
```

```C
#include <stdio.h>
// clang -std=c99 -Wall
// Apple LLVM version 6.0 (clang-600.0.56)
int main()
{for( int i=1 ; i<=3 ; ++i ){printf( "%.20f ", 1.001*i );}}
```

の結果は、以下のようになる：

|処理系|結果|
|:--|:--|
|ruby2.2.0|`["1.00099999999999988987", "2.00199999999999977973", "3.00299999999999966960"]`|
|jruby 1.7.18 (1.9.3p551)|`["1.00100000000000000000", "2.00200000000000000000", "3.00299999999999970000"]`|
|groovy2.3.9|`[1.00100000000000000000, 2.00200000000000000000, 3.00299999999999970000]`|
|Python 3.4.2|`['1.00099999999999988987', '2.00199999999999977973', '3.00299999999999966960']`|
|C99(clang)|`1.00099999999999988987 2.00199999999999977973 3.00299999999999966960 `|

というわけで、JVM が特別だという印象になった。