随机数生成方法

当代计算机的创始人约翰.冯.诺依曼曾经说过,任何试图以算法生成随机数据的人都将处于一种两难境地。所谓两难说是指随机性与算法确定性之间是不可能完全统一的。所以我们必须有意识地根据需要伪随机序列的随机性才能达到模拟真随机序列的效果。
线性同余伪随机数发生器
目前应用最为广泛的均匀分布伪随面数发生器就是线线同余伪随机发生器(LCG)
LCG的迭代描述公式为:
Xi+1=(a*Xi+c)(mod m)  (1)
式(1)中有三个参数a,c,m。其中m是一个素数,a是m的一个原根,c属于[0,m),初值x为种子。我们将a,c,m分别叫做乘数、增量、模。

Microsoft Visual C/C++的随机函数rand()就是用的上面相似的算法
其a=214013即343FDh   ,c=2531011即269EC3h   m=2^32 即一个DWORD数据

那你可能会问,x的初值取什么呢?对于rand(),初值为1,即randseek=1,当然也可以通过一个函数srand(int x)将种子更改,这样我们得到的随机数序列就不一样了,通常使用时间戳(用rdtsc指令)

通过简单的写一个c函数,然后OD跟踪一下,就可以得到rand了
#include "stdlib.h"

int main(int argc, char* argv[])
{
int Array[5][5];
int i,j;


//srand(1);
for(i=0;i<=4;i++)
 for(j=0;j<=4;j++)
  Array[i][j] = rand();
for(i=0;i<=4;i++){            //测试输出
 for(j=0;j<=4;j++)
  printf("%d    ",Array[i][j]);
 printf("/n");
}
return 0;
}
//----------------------
跟踪rand得到:
mov eax,dword ptr ds:[40703c];种子赋给eax
imul eax,eax,343fd   ;eax=a*x (有符号乘法)
add eax,269ec3   ;eax=a*x+c
mov dword ptr ds:[40703c],eax;将当前值(下一次的种子)写回
sar eax,10    ;算术右移16位(0~32767)
and eax,7fff   ;取低15位(保证为正数),即得到了一个随机数
retn
;-----------------------------

下面给出一个完整的例子:

;************************************************************
;*--==--* Rand  example

;*--==--* By G-Spider 2010.11.2
;*--==--* Web:http://blog.csdn.net/G_Spider
;*--==--* -------------------------------------------------------
;*--==--* ml  /c /coff rand.asm  
;*--==--* link /subsystem:console rand.obj
;*--==--* 请保持以上完整性!!
;************************************************************
 .686p
.XMM
 
 .model flat,stdcall
 option casemap:none
 
 include windows.inc
 include user32.inc
 include kernel32.inc
 include msvcrt.inc
 
 includelib user32.lib
 includelib kernel32.lib  
 includelib msvcrt.lib

.data
RandSeed        dd      1       ;默认的种子
fmt0            db      '%f',0dh,0ah,0
fmt1            db      '%6d/32767=',0

.data?
lpA             dd      ?       
lpB             dd      ?    
lpC             dd      ?  
lpFloatA        dd      ?
lpFloatB        dd      ?
lpFloatC        dd      ?
.code
;*************************************
;种子生成函数
;-------------------------------------
_srand  proc seed
        push  seed
        pop   RandSeed
        ret
_srand    endp
;*************************************
;m为矩阵的行,n为矩阵的列,生成m*n个随机数
;返回数据首指针
;------------------------------------
rand    proc    m,n     
        local   @lpRand
        mov     eax,m   ;eax作乘数
        mul     n       ;n*m,结果高位在edx中,低位在eax中
        ;-------------------------------------------------
        push    eax
        shl     eax,2
        ;-------------------------------------------------
        ;申请空间
        invoke  VirtualAlloc,NULL,eax,MEM_RESERVE /
                or MEM_COMMIT,PAGE_READWRITE
        .if     eax
                mov     @lpRand,eax         ;分配的指针是页对齐的
                mov     esi,eax
        .else
                xor     eax,eax   ;失败则返回NULL
                ret
        .endif 
        pop     eax       
Loop1:        
        mov    ecx,RandSeed
        imul   ecx,ecx,343FDh
        add    ecx,269EC3h
        mov    RandSeed,ecx
        sar    ecx,10h
        and    ecx,7FFFh
        mov    [esi],ecx
        add    esi,4
        dec    eax
        jnz    Loop1

        mov     eax,@lpRand ;成功则返回0
        ret

rand    endp
;*************************************
;将rand生成的随机整数转成0~1之间的随机数
Int2FloatRand0_1  proc  m,n,lpRand,flag
        local   @lpNewRand
        
        mov     esi,lpRand 
        mov     eax,m   ;eax作乘数
        mul     n       ;n*m,结果高位在edx中,低位在eax中,总共eax=n*m个数
        push    eax     ;保存数据个数在eax中
        shl     eax,2   ;满足四个数据对齐,粒度为4字节,16字节对齐,最好的情形

        ;-------------------------------------------------
        ;申请空间
        invoke  VirtualAlloc,NULL,eax,MEM_RESERVE or MEM_COMMIT,PAGE_READWRITE
        .if     eax
                mov     @lpNewRand,eax  ;分配的指针是页对齐的
                mov     edi,eax
        .else
                xor     eax,eax   ;失败则返回NULL
                ret
        .endif
        
        ;**************************************************
        ;整形转浮点0~1
        mov     eax,38000100H   ;1/7fffh=0.000030518509476
        movd    xmm0,eax
        pslldq  xmm0,12
        movaps  xmm1,xmm0
        psrldq  xmm1,4
        orpd    xmm0,xmm1
        psrldq  xmm1,4
        orpd    xmm0,xmm1
        psrldq  xmm1,4
        orpd    xmm0,xmm1

        movaps  xmm7,xmm0       ;xmm7=1/7fffh,1/7fffh,1/7fffh,1/7fffh

        ;整形转浮点
        pop     eax             ;保存数据个数在eax中
        mov     ecx,eax
        cmp     eax,32
        jl      A002            ;整数个数(<32个)
        
        test    ecx,1Fh         ;是不是32的整数倍?
        jz      A001
        and     ecx,-20h
        and     eax, 1fh        ;剩余的整数(<32个)
        
        ;每128字节=32个数一次
A001:
        cvtdq2ps        xmm0,[esi]
        cvtdq2ps        xmm1,[esi+10h]
        mulps           xmm0,xmm7
        mulps           xmm1,xmm7
        movaps          [edi],xmm0 ;// Write to destination
        movaps          [edi+10h],xmm1
        
        cvtdq2ps        xmm2,[esi+20h]
        cvtdq2ps        xmm3,[esi+30h]
        mulps           xmm2,xmm7
        mulps           xmm3,xmm7        
        movaps          [edi+20h],xmm2 ;// Write to destination
        movaps          [edi+30h],xmm3
        
        cvtdq2ps        xmm4,[esi+40h]
        cvtdq2ps        xmm5,[esi+50h]
        mulps           xmm4,xmm7
        mulps           xmm5,xmm7        
        movaps          [edi+40h],xmm4 ;// Write to destination
        movaps          [edi+50h],xmm5
        
        movaps          xmm0,xmm7       
        cvtdq2ps        xmm6,[esi+60h]
        cvtdq2ps        xmm7,[esi+70h]
        mulps           xmm6,xmm0
        mulps           xmm7,xmm0        
        movaps          [edi+60h],xmm6 ;// Write to destination
        movaps          [edi+70h],xmm7
 
        movaps          xmm7,xmm0        
        add     esi,128
        add     edi,128
        sub     ecx,32
        jnz     A001
        
        ;处理<32个整数(16-8-4-2-1)
        
A002:  test    eax,10h
        jz      A003   ;小于16个整数
        sub     eax,10h
        cvtdq2ps        xmm0,[esi]
        cvtdq2ps        xmm1,[esi+10h]
        mulps           xmm0,xmm7
        mulps           xmm1,xmm7
        movaps          [edi],xmm0 ;// Write to destination
        movaps          [edi+10h],xmm1
        
        cvtdq2ps        xmm2,[esi+20h]
        cvtdq2ps        xmm3,[esi+30h]
        mulps           xmm2,xmm7
        mulps           xmm3,xmm7        
        movaps          [edi+20h],xmm2 ;// Write to destination
        movaps          [edi+30h],xmm3
        add     esi,64
        add     edi,64
A003:   test    eax,8
        jz      A004
        sub     eax,8
        cvtdq2ps        xmm0,[esi]
        cvtdq2ps        xmm1,[esi+10h]
        mulps           xmm0,xmm7
        mulps           xmm1,xmm7        
        movaps          [edi],xmm0 ;// Write to destination
        movaps          [edi+10h],xmm1
        add     esi,32
        add     edi,32
        
A004:   test    eax,4
        jz      A005
        sub     eax,4
        cvtdq2ps        xmm0,[esi]
        mulps           xmm0,xmm7
        movaps          [edi],xmm0
        add     esi,16
        add     edi,16
        
A005:   test    eax,2
        jz      A006
        sub     eax,2
        movlpd          xmm1,QWORD PTR [esi]
        cvtdq2ps        xmm0,xmm1
        mulps           xmm0,xmm7
        movlpd          QWORD PTR [edi],xmm0
        add     esi,8
        add     edi,8
        
A006:   test    eax,1
        jz      A007
        sub     eax,1
        movd          xmm1,DWORD PTR [esi]
        cvtdq2ps      xmm0,xmm1
        mulps         xmm0,xmm7
        movd        DWORD PTR [edi],xmm0
        add     esi,4
        add     edi,4                     
A007:
        
        mov     eax,@lpNewRand
        ret
        
Int2FloatRand0_1        endp

;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
start:

        invoke  rand,5,5 ;默认的种子为1,生成5*5=25个随机数
        .if     eax
                mov     lpA,eax
        .else
                invoke MessageBox,NULL,0,0,0
                ret
        .endif
        ;---------------------------------------
        ;种子为2的随机数输出
        invoke  _srand,2  ;种子取2
        invoke  rand,5,5  ;生成5*5=25个随机数
        .if     eax
                mov     lpB,eax
        .else
                invoke MessageBox,NULL,0,0,0
                ret
        .endif
        
        ;---------------------------------------
        ;种子为时间戳
        rdtsc
        and     eax,7fffffffh
        invoke  _srand,eax  ;种子取2
        invoke  rand,5,5  ;生成5*5=25个随机数
        .if     eax
                mov     lpC,eax
        .else
                invoke MessageBox,NULL,0,0,0
                ret
        .endif
        ;---------------------------------------
        ;将上面生成的随机整数转成0~1之间的单精度浮点
        invoke  Int2FloatRand0_1,5,5,lpA,0
        mov     lpFloatA,eax
        invoke  Int2FloatRand0_1,5,5,lpB,0
        mov     lpFloatB,eax 
        invoke  Int2FloatRand0_1,5,5,lpB,0
        mov     lpFloatC,eax 
         
;**********************************************        
;输出前8个随机数,种子为1(种子为2的类似)
;包括整型随机数和对应的0~1之间的单精度随机数
;----------------------------------------------        
        xor     ecx,ecx   
@@:
        push    ecx
        mov     esi,lpA
        invoke  crt_printf,offset fmt1,DWORD ptr [esi+ecx*4]
        pop     ecx
        push    ecx
        
        mov     edi,lpFloatA
        fld     DWORD PTR [edi+ecx*4]
        sub     esp,8
        fstp    QWORD PTR [esp]
        push    offset fmt0
        call    crt_printf
        add     esp,12
        pop     ecx
        inc     ecx
        test    ecx,7
        jnz     @B
;**********************************************  
;释放       
        invoke  VirtualFree,lpA,0,MEM_RELEASE
        invoke  VirtualFree,lpB,0,MEM_RELEASE
        invoke  VirtualFree,lpC,0,MEM_RELEASE
        invoke  VirtualFree,lpFloatA,0,MEM_RELEASE 
        invoke  VirtualFree,lpFloatB,0,MEM_RELEASE
        invoke  VirtualFree,lpFloatC,0,MEM_RELEASE
     
        
        invoke ExitProcess,0

end start

 

 

 

 

你可能感兴趣的:(随机数生成方法)