2017-06-28 14 views
3

私が持っている:Rubyの和STDIN整数

$ ruby -v 
ruby 2.0.0p648 (2015-12-16 revision 53162) [universal.x86_64-darwin16] 

あなたは、整数のシーケンス1..nルビー初心者はそうのようなシーケンスを合計うがあるとします。

$ ruby -e 's=0 
    for i in 1..500000 
     s+=i 
    end 
    puts s' 
125000250000 

は、今私は、同じ配列を持っていると仮定それはstdinから来て:

$ seq 1 500000 | ruby -lne 'BEGIN{s=0} 
          s+=$_.to_i 
          END{puts s} ' 
125000250000 

これまでのところとても良いです。

は今5,000,000 500,000から端末価値を高める:

$ ruby -e 's=0 
     for i in 1..5000000 
      s+=i 
     end 
     puts s' 
12500002500000 <=== CORRECT 

$ seq 1 5000000 | ruby -lne 'BEGIN{s=0} 
          s+=$_.to_i 
          END{puts s} ' 
500009500025  <=== WRONG! 

それは別の合計を生成します。

awkperlの両方が同じ順序で正しい結果を生成します。

$ seq 1 5000000 | awk '{s+=$1} END{print s}' 
12500002500000 
$ seq 1 5000000 | perl -nle '$s+=$_; END{print $s}' 
12500002500000 

はなぜルビーが間違っ合計を生産していますか? awkperlが同じ入力に対して正しく機能しているため、オーバーフローしているとは思われません。


結論:

これを診断するためのあなたのデビッド・オルドリッジをありがとうございます。 GNU seqは、任意精度の整数をサポートしながら

  1. OS XとBSD seqは1,000,000でフロート出力に変換します。 OS X seqは、1,000,000を超える整数のソースとしては役に立たない。 OS X上の例:

    $ seq 999999 1000002 
    999999 
    1e+06 
    1e+06 
    1e+06 
    
  2. サイレント整数に部分文字列を変換し、すなわち、この場合に「バグ」であった.to_iルビー方法。例:

    irb(main):002:0> '5e+06'.to_i 
    #=> 5 
    
  3. スクリプトで「正しい」ラインは、浮動小数点数を使用するか、スクリプトが黙って失敗していないためにInteger($_)を使用する$_.to_f.to_iを使用するかのいずれかです。 awkperl解析5E + 06フロートに、とrubyは暗黙的にしません:.to_i行動に関するルビーfeature requestを開くための

    $ echo '5e+06' | awk '{print $1+0}' 
    5000000 
    $ echo '5e+06' | ruby -lne 'print $_.to_i+0' 
    5 
    
  4. そしてステファンSchusslerのおかげで。

+1

この問題については、[機能リクエスト](https://bugs.ruby-lang.org/issues/13693)を開設しました。 – Stefan

+2

FWIW Ruby 2.4 Enumerable#sumメソッドはこのために最適化されているので、 '(1..5000000).sum'はほとんど瞬時に戻ります。 – steenslag

+0

なぜ私はこの質問または今後の質問を修正することができますので、投票をなぜ尋ねることができますか?他のRuby初心者のためにここで不明な点や役に立たなかった点がありましたか? – dawg

答えて

5

私は、これは100%の答えであることをわからないんだけど、私がいることに気づく:

seq 500000 500001 | ruby -lne 'BEGIN{} 
          puts $_ 
          END{} ' 
500000 
500001 

...しかし...

seq 5000000 5000001 | ruby -lne 'BEGIN{} 
          puts $_ 
          END{} ' 
5e+06 
5e+06 

...そう#to_iはまだ動作します整数に値を変換するのにかかる「リラックス」のアプローチ...

seq 5000000 5000001 | ruby -lne 'BEGIN{} 
          puts $_.to_i 
          END{} ' 
5 
5 

...しかし、より厳密#to_intしません

seq 5000000 5000001 | ruby -lne 'BEGIN{} 
          puts $_.to_int 
          END{} ' 
-e:2:in `<main>': undefined method `to_int' for "5e+06":String (NoMethodError) 

編集:Iまた気づく:

seq 5000000 5000001 

5e+06 
5e+06 

ので-fフラグは、整数フォーマットを取得するには、配列に渡す必要があります。

編集再び:

最終的な答え:

seq -f %f 1 5000000 | ruby -lne 'BEGIN{s=0} 
            s+=$_.to_i 
           END{puts s} ' 

12500002500000 
+0

ねえ、そうだと思います。 –

+0

また、あなたは 'seq 1 5000000 | tail =) –

+0

これを克服するために、 's + = $ _。to_f.to_i'を使用することができます –

1

電子表記出力を説明するために、seqのためのOS Xのmanページには、いくつかの洞察力を与える:

したがって

Use a printf(3) style format to print each number. [...] The default is %g .

seqの出力はRubyと同等です:

sprintf('%g', 100000) 
#=> "100000" 

sprintf('%g', 1000000) 
#=> "1e+06" 
関連する問題