任意のビット列を0以上1以下の数値に変換する
やりたかったこと
- 文字列に対して0以上1以下の数値を割り当てる
- 複数回実行した場合でも割り当てる数値は常に等しい
2つ目の要件がなければ乱数を取ってきて割り当てれば良いのだが、再現性が必要なため乱数は使えない。 したがって、文字列をもとに一見すると乱数のように見える数値を算出する必要がある。
言い換えれば、任意のビット列から[0, 1]への一様性がある写像を考えるということになると思う。
方法
元データからハッシュを求め、それを小数に変換する。
require "digest/sha1" # ハッシュ関数はSHA1じゃなくても良い def convert(arg) hex_digest = Digest::SHA1.hexdigest(arg.to_s) hex_digest.to_i(16).to_f / 16 ** hex_digest.size end convert(1) # => 0.20865018187858086 convert(2) # => 0.8527156244334038 convert(3) # => 0.4682374510274206
結果
とりあえず、1から1000までの数値を文字列にして試してみた。
各文字列はどういった値になったか
横軸は引数とした数値文字列"#{n}"
、縦軸は結果として得られた数値。
ヒストグラム
階級数は20。
結論
雑な検証ではあるが、ある程度使えそうなことはわかった。
得られる数値が乱数っぽいかどうかはハッシュ関数の一様性に依存するので、一様性を気にする場合はハッシュ関数の選択に気をつける必要がある。
参考:The distribution of hash function outputs
Special Thanks
@osa522 ちらっと見た感じここらへんどうでしょう?
1. http://t.co/0e7VLGdQs7
2. http://t.co/8bVash1V3f
3. http://t.co/NSVxUBQc6u
— ひまじん (@__Himajin) 2014, 12月 27