Rubyのrandの挙動はややこしく、最近さらにややこしくなったのでメモ。
ふるまい(before 1.9.2)
1.9.2までは、
Random#randは引数にInteger, Float, Rangeを扱うことができるのに対し、
Kernel#rand, Random.randではIntegerしか扱うことができない
rand 10 #=> 7 rand 7.5 #=> 4 rand 10..20 #=> TypeError: can't convert Range into Integer Random.rand 10 #=> 8 Random.rand 7.5 #=> 3 Random.rand 10..20 #=> TypeError: can't convert Range into Integer Random.new.rand 10 #=> 8 Random.new.rand 7.5 #=> 6.258043599450456 Random.new.rand 10..20 #=> 20
仕様変更の提案
この挙動が不満だったのでruby-listで聞いてみたところ、
「redmineに投げてみたら」
と言われたので投げたら通ってしまった。
Random#randとKernel#randでRangeを扱えるように(http://redmine.ruby-lang.org/issues/4605)
提案ないようは最初はKernel#randとかでもFloatとRangeを扱えるようにするものだったが、それだとFloat値が与えられた時の互換性がなくなってしまいヤバい。
しょうがないのでRangeの対応だけを追加するものを提案した。
実装
提案したらsora_hとmrknさんが即効でパッチを書いてくれてcommitされたようです。
ソースコードながめてたらKernel#randとRandom.randはCレベルでは全く同じ関数と知ってびっくり
まとめ
Kernel#rand | Random.rand | Random#rand | |
---|---|---|---|
1.9.2まで | Integer | Integer | Integer, Float, Range |
1.9.3から | Integer, Range | Integer, Range | Integer, Float, Range |
Random#randの存在を知らずに「RubyではFloatの乱数作れないのかよ……つかえねえ」とか思う人がでてこないといいなあ