2012-08-17 5 views
8

irbで3 ** 557を計算しようとしたときにこの問題に遭遇しました。 RubyとMacRubyはどちらもMac(OS X 10.8)にインストールされています。また、ルビのバージョンはMacRuby 0.12(ルビ1.9.2)の1.8.7です。 ribとmacirbは3 ** 557の計算で2つの異なる答えをくれました。 (macirb'sは正しいです。)Rubyの指数関数1.8.7が間違った答えを返す

$ irb 
>> 3**557 
=> 54755702179342762063551440788945541007926808765326951193810107165429610423703291760740244724326099993131913104272587572918520442872536889724676586931200965615875242243330408150984753872526006744122187638040962508934109837755428764447134683114539218909666971979603 

$ macirb 
irb(main):001:0> 3**557 
=> 57087217942658063217290581978966727348872586279944803346410228520919738045995056049600505293676159316424182057188730248707922985741467061108015301244570536546607487919981026877250949414156613856336341922395385463291076789878575326

そして、私はもっと大きなものを試しました。 3 ** 5337、私は今回も同じ答えを得ました。

これはRuby 1.8.7のバグですか、それとも指数を計算する別の方法ですか?

+0

ていますが、[べき乗剰余演算]を見てみたいことがあり(http://en.wikipedia.org/wiki/Modular_exponentiation)を実行します。 – jli

+0

私は1.9.3より前のMRIをインストールしていませんが、正しい結果が得られます。 –

+0

どのMacの正確なモデルをお使いですか? MacPro(Xeon)で同じバージョンのRuby(1.8.7 p358)でこれを再現することはできません。 32ビットで動作している古い1.8.6では動かすこともできません。 –

答えて

3

計算すると、Ru byはFixnumからBignumに変換されるはずですが、その数がFixnumの範囲を超えたときです。 Rubyの旧バージョンの場合、**演算子で失敗します。

$ ruby --version 
ruby 1.8.7 (2012-02-08 patchlevel 358) [universal-darwin12.0] 
$ irb 
>> 2 ** 62 
=> 4611686018427387904 
>> 2 ** 63 
=> -9223372036854775808 
>> 2 ** 64 
=> 0 

ここで失敗するのは、アーキテクチャのワードサイズによって異なります。この例では、iMacの64ビットワードです。内部的には、Fixnumは長い整数にキャストされ、演算子はlongで処理されます。 long型は、ワードサイズでオーバーフロー、およびRubyが不正に(BIGNUMへの変換)*演算子が正しく動作することを0

注意を返すことによって、これを処理している、**失敗した場所:

>> a = 2 ** 62 
=> 4611686018427387904 
>> 2 ** 63 
=> -9223372036854775808 
>> a * 2 
=> 9223372036854775808 
>> 2 ** 64 
=> 0 
>> a * 4 
=> 18446744073709551616 

はへの移行します新しいバージョンのRubyではこれが修正されます。新しいバージョンに移行できない場合は、大きな力でFixnumと**を使用しないでください。独自の累乗法を書く

2

1.9.3を使用すると正しい結果が得られます。本当に良い理由がない限り、1.8.7が段階的に廃止されているので、1.9.3以上を使用してみてください。

Linux上で1.8.7-p358でテストしたところ、正しい答えも得られました。あなたが使っている1.8.7の特定のバージョンのバグかもしれません。

+0

ありがとう!それはXcode と一緒にインストールされるかもしれない$ ruby​​ --version ruby​​ 1.8.7(2012-02-08パッチレベル358)[universal-darwin12.0] – Vej

+0

XCodeにはRubyは含まれていませんが、OS Xには通常、システムにいくつかのバージョンが含まれていますが、Rubyについて真剣な人は 'rvm'または' rbenv' – tadman

+0

私はRubyを1.9.3-p194に更新するためにJewelryBoxを使用していますが、現在はRubyをシステムで所有しているため、システムによって所有されている可能性があります。 。 – Vej

1

これは間違いなくバグです。おそらく、プロセッサーやコンパイルオプションに依存しています。

this commitで修正されても驚くことはありません。

他の人も述べているように、セキュリティの修正だけで1.8.7になっているので、1.9.3にアップグレードしてください。

0

これは、明示的にべき乗とは関係ありません。私はそれが表現に必要な63から64ビットへの移行に何らかの形で関係していると思いますが、これは100%一貫しているとは思われません。

>> 19**14 
=> 799006685782884121 
>> 19**15 
=> -3265617043834753317 
>> (19**14)*19 
=> -3265617043834753317 

、まだ

>> 2**64-1 
=> -1 
>> 2**64 
=> 0 
>> 0x7fffffffffffffff 
=> 9223372036854775807 

また

>> 0x8000000000000000 
=> 9223372036854775808 

:、私はこの時点でこれが表示されていない32ビットモードでのIRB(arch -i386 irb)を実行しているが、それ以前:

>> 19**15 
=> 15181127029874798299 
>> 2**31 
=> -2147483648 
0

は、エラーを生成しません。それを行うための別の方法であるように思わ:

def xpnt(base, exponent) 
    sum = base 
    while exponent >= 2 
     sum = sum * base 
     exponent -= 1 
    end 
    puts sum 
end 

「10」いずれかの電源への単一の「1」で始まらなければなりませんし、何が続きますしかしゼロ。 Rubyの**機能:

10 ** 40 
=> 10000000000000000000092233720368547758080 

カスタムxpnt方法:

特にルビーとは無関係の
xpnt 10, 40 
10000000000000000000000000000000000000000 
=> nil 
関連する問題