2017-08-09 18 views
4

私はアセンブリで完全な乱数を作成しようとしていますが、プログラムを開始するたびに同じ番号が同じ順序で与えられます。 数字が12,132,4113などの場合は、コードを開始するたびに繰り返します。アセンブリで乱数ジェネレータをシードする方法は?

私が作ろうとしているプログラムは、推測ゲームのようなものです。

IDEAL 
MODEL small 
STACK 100h 
DATASEG 
;vars here 
RNG_Seed dw ? 

CODESEG 
; Generates a pseudo-random 15-bit number. 
; Parameters: <none> 
; Clobbers: AX, DX 
; Returns: AX contains the random number 
proc GenerateRandNum 
    push bx 
    push cx 
    push si 
    push di 


    ; 32-bit multiplication in 16-bit mode (DX:AX * CX:BX == SI:DI) 
    mov ax, [RNG_Seed] 
    xor dx, dx 
    mov cx, 041C6h 
    mov bx, 04E6Dh 
    xor di, di 
    push ax 
    mul bx 
    mov si, dx 
    xchg di, ax 
    mul bx 
    add si, ax 
    pop ax 
    mul cx 
    add si, ax 


    ; Do addition 
    add di, 3039h 
    adc si, 0 


    ; Save seed 
    mov [RNG_Seed], di 


    ; Get result and mask bits 
    mov ax, si 
    and ah, 07Fh 


    pop di 
    pop si 
    pop cx 
    pop bx 
    ret 
endp GenerateRandNum 

実行ごとに異なる乱数を得るにはどうすればよいですか?

+0

プログラムがOSなしで実行されていますか? – James

+0

@James osではどういう意味ですか? –

+0

オペレーティングシステム – Ped7g

答えて

4

RNG_Seedを「ランダム」で初期化する必要があります。そして、それは実際にコンピュータのような決定論的なマシンでは少し問題があります。

特に乱数を暗号化に強くしたいのであれば、現在のソリューション、いくつかの産業ソリューションでは、ホワイトノイズジェネレータを備えた特別なHWチップを含む、乱数ジェネレータとして使用することができます。

あなたはゲームのためだけにそれをしたいと思うので、それはそれほど悪くはありませんが、まだ少しトリッキーです。

私は(あなたが16bのレジスタを使用するよう)あなたがリアルモードになっていると思いますので、BIOSティック-以来、真夜中エントロピー源の一つとして読ま:

xor ah,ah ; ah = 0 
int 1Ah ; returns in cx:dx ticks since midnight (18.2Hz ticks) 
; let's mix the cx:dx a bit together to get a bit more entropy out of it 
rol cx,8 
xor dx,cx 
xor [RNG_Seed],dx ; "add" that entropy to the original seed 

これはそれを少し向上しますが、それはです(ゲームを同時に実行すると同じランダム値が生成される可能性があります)ので、ここでは安価なエントロピー源の別の提案があります:

名前を入力するには、プレイヤーに少なくとも3キーを待つ間に常にinc counterを実行して各キーストロークを時間を計り、毎回カウンタの下位4ビットを保持します(3文字+入力= 4×4ビット=合計16ビット)。その後、「追加」(xor)してRNG_Seedに再度追加します。

これらの2つのものは、ゲームRNGのために十分なエントロピーを生成するはずです(ただし、暗号化などのセキュリティ目的では十分ではありません)。


EDIT:コメントで述べたように異なるシード値を混合する際に、それらのいずれかが関係していないことを確認してください、というかaddxorよりもを使用しています。私の最初のアイデアは真夜中からxorからBIOSティックを使用して、変数のランダムなメモリ(おそらくゼロ、BTW、exeロード時にOSによってクリアされたもの)と比較してから、ユーザーのキーストロークの時間を測定しました。 :4:4ビットの4キーストローク(xorなし、完全な16bが準備完了するまでお互いにちょうど追加されます)、およびxorで最終値をメインシードに使用します。キーストロークはBIOSティックに何ら関連していないので、これは干渉してはならず、xorはこの特定のケースではうまくいくはずです。

また、キーストロークから4:4:4:4を選択し、xor-edを繰り返し実行するたびに1つの16b値ではない理由。私はint 16h, ah=1を呼び出すことによってそのキーストロークの遅延カウンタを実装することを期待しています。したがって、無限にループしていくつかのカウンタを増やすと、非常に速く(おそらく数千秒以内に)16の値を超えることになります。そのようなカウンタの下位4ビットを使用することは、ユーザがどのようにしてキーにヒットするかにほとんど関係しない。非常に遅いコンピュータでは、16ビットのフル待ち時間を使用しても、実際には上位ビットに似たビットパターンが生成されることがあります(つまり、カウンタ - >上位2ビットの10000-13000の値が常にゼロで、ビットは毎回非常に似ています)。だから、私は4ビットを使って16ビットの値を形成します。ユーザーが長い名前を入力した場合、シード調整のためにこれらのキーストロークを使用することはなく、最初の4つだけを使用します。実際にどのように動作するかを確認するためにデバッグを行うことになるでしょう。おそらく私は結果についてあまりにも楽観的で、隠れたシンクのようなキャッチがあります。しかし、私は実際にそれを書いて試してみるのは面倒です(20行ほどのコードですが、dosboxとDOSデバッガが必要です)。

+4

(主に)確定的なマシンからエントロピーを作成することは、常に私のお気に入りのタスクの1つでした。エントロピーソースの大きなリストをビット単位で書くことは楽しいでしょう(これは証明するのが難しいかもしれません)。たとえば、 'rdtsc'、' rdseed'、 'rdrand'の横には、次の垂直帰線時間の時間(何であれ)が素敵なソースでした。 –

+1

@ S.josh:[' RDRAND r16'](https:///hjlebbink.github.io/x86doc/html/RDRAND.html)*はVEXエンコーディングを使用しないため、16ビットモードで動作するはずです(BMI/BMI2命令の中には16ビットで使用できないものがあるモード)。もちろん、それをサポートするCPUだけで、特定のCPUのRNGハードウェアが誤動作してCF = 0の非ランダムデータを返す可能性があります。 –

+2

@ Ped7g: 'xor'は相関関係のあるものの危険な混合関数です。 [@Yakkが言うように](https://stackoverflow.com/questions/45069219/how-to-succinctly-portably-and-thoroughly-seed-the-mt19937-prng#comment77114547_45070076): '+'は通常より良い: ' 「x + x」はエントロピーの1ビットを「x」で燃やし、「x^x」はそれらをすべて焼き付けます。同じ値を2回使用した場合です。 –

関連する問題