LoginSignup
46
37

More than 5 years have passed since last update.

なぜmt_rand()の誤った実装をサクッと修正できないのか

Last updated at Posted at 2016-02-20

@scaled_wurm さんのPHP の mt_rand() は一貫して壊れている(consistently broken)らしいに便乗してみる。

擬似乱数の特性は「周期性があること」です。周期性とはつまり再現性で、ほとんどの擬似乱数は長い周期性をもち次に出力される数を予測することが困難である一方、初期状態を固定する事で決まったパターンで値を返します。これは完全な乱数にはないもので、用途によっては完全な乱数より擬似乱数を使う方が好ましいこともあります。

例えば単体テストで乱数を扱う場合のことを考えてみましょう。

class RandomTest extends TestCase
{
    public function testInitialValue()
    {
        mt_srand(0);
        $this->assertEquals(963932192, mt_rand());
    }
}

mt_rand()が「正しい」実装に修正されたなら上記テストは壊れてしまいます。これは極端な例ですが、PHPをアップグレードした瞬間、世の中にごまんとある(かもしれない)mt_rand()の周期性に依存したコードが想定外の動作をするとなると、どんな影響があるか想像もつきません。

修正がRevertされたコミットに最初に付いたコメントは名言ですね。「一貫して壊れている」と訳されましたが、僕が訳すなら「壊れ方に一貫性がある」とする方が意図が通じやすいかなと。

"Sure it's broken, but at least it's consistently broken!"
https://github.com/php/php-src/commit/a0724d30817600540946b41e40f4cfc2a0c30f80#commitcomment-16174204

mt_rand()は既に広く使われている関数で、修正するにしても別関数なりiniディレクティブなりで「壊れた」mt_rand()が使えないと困るケースは確実にあります。
あとセキュリティが求められる用途にmt_rand()を使っているコードがあるとしたら、アルゴリズム選定の時点で間違っているのでまた別問題です。

メルセンヌツイスタが正しく実装されていなかったことはとても残念ですし、バグを発見・レポートされた @kusano_k さんは素晴らしいと思います。でも影響範囲を考えると誤っているからといっておいそれと直せない性質のものであることも、みなさんには理解していただきたいです。

なお、大垣さんによる検証によると通常の擬似乱数が求められる用途では修正前でも大きな問題はないんじゃないかとのことです。

46
37
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
46
37