スキームでランダムを生成するにはどうすればよいですか? 特別なフォームはありますか、それとも手順を作成する必要がありますか? もしそうなら、どうすればいいですか?(2 つの戦略を入力し、ランダムに 1 つを返す、random-choice と呼ばれる手順を作成しようとしています。)
3 に答える
標準スキームは乱数ジェネレーターを提供しません。ほとんどのスキーム実装は乱数ジェネレーターを提供しますが、詳細が異なる傾向があります。移植可能な Scheme プログラムを書きたい場合、独自の乱数ジェネレータを作成するのは簡単です。ここにクヌースによる方法があります:
(define random
(let ((a 69069) (c 1) (m (expt 2 32)) (seed 19380110))
(lambda new-seed
(if (pair? new-seed)
(set! seed (car new-seed))
(set! seed (modulo (+ (* seed a) c) m)))
(/ seed m))))
呼び出す(random)
と、0 (含む) と 1 (含まない) の間のランダムな分数が返されます。ランダムな分数は周期m で循環します。を呼び出す(random seed)
と、乱数ジェネレーターのシードがリセットされるため、同じシードから始まる 2 つの乱数シーケンスは同一になります。YYYYMMDD の形式の日付は良いシードになります (上記のクヌースの誕生日です)。コインを投げたい場合は、次のように言います(if (< (random) 1/2) 'heads 'tails)
。
範囲内のランダムな整数が必要な場合があります。以下に示す関数は、範囲lo (含む) からhirandint
(含まない)のランダムな整数を返します。loのデフォルトは 0 です。
(define (randint . args)
(cond ((= (length args) 1)
(floor (* (random) (car args))))
((= (length args) 2)
(+ (car args) (floor (* (random) (- (cadr args) (car args))))))
(else (error 'randint "usage: (randint [lo] hi)"))))
このような乱数は単純なシミュレーションには十分ですが、暗号化アプリケーションには適していないことに注意してください。興味があれば、私のブログで、暗号化アプリケーションに適したものを含む、いくつかの乱数ジェネレーターを用意しています。
驚くべきことに、プロシージャーが呼び出されrandom
ます。正確な構文は、使用している Scheme インタープリターによって異なる場合がありますが (ドキュメントを読んでください!)、一般的な考え方は次のとおりです。
(random)
=> 0.9113789707345018
2 つの可能な値のうちの 1 つを返すために、これは Racket でトリックを実行します。
(define (random-choice a b)
(if (zero? (random 2)) a b))
2
に渡された引数random
により、2 つの可能な値0
またはのいずれかがランダムに返されることに注意してください1
。したがって、(random 2)
評価された場合は0
thena
が返され、そうでない場合b
は返されます。
(random-choice 4 2)
=> 4
(random-choice 4 2)
=> 2
あなたのもう 1 つの質問は、DrRacket での宇宙船ゲームの実装に関するものだったので、Scheme とは、DrRacket の教育用言語の 1 つを意味していると思います。
DrRacket で利用可能な機能に関する情報を見つける方法は簡単です。random
たとえば、対話ウィンドウに書き込みます。カーソルを一番上に置き、F1 キーを押します。
random
htdp-languagesのドキュメントは次のとおりです。
ランダムな値を返す 1 つの方法:
(list-ref (list "one" "two") (random 2))
ここで (ランダム 2) は 0 または 1 を返します。したがって、list-ref は、リストのインデックス 0 またはインデックス 1 を持つエントリを返します。
上記のアプローチを使用する利点は、3 つ以上の値に簡単に拡張できることです。