Sunteți pe pagina 1din 16

ALGEBRA COMPUTATIONALA

NUMERE MERSENNE
-proiect-

1)ISTORIC

Marin Mersenne s-a nascut la 8 septembrie 1588 in Oize in Maine,Franta si a murit la 1 septembrie 1648 la
Paris.
Mersenne a studiat teologia la Sorbonne din 1609 pina in 1611.In 1912 s-a intors la Paris unde a devenit preot la
Palatul Regal.
Mersenne Marin(1588 – 1648)a fost calugar,filozof si matematician francez renumit pentru interesul sau in
formularea si generarea numerelor prime bazate pe ceea ce astazi sunt cunoscute sub numele de numere
Mersenne. Totusi Mersenne nu a fost numai matematician,el a scris despre teoria muzicii si alte subiecte ,a lucrat
cu Euclid,Archimedes si alti matematicieni.
El a studiat numerele prime si a incercat sa gaseasca o formula prin care sa reprezinte toate aceste numere.
Marin Mersenne a studiat numerele prime si a incercat sa gaseasca o formula care sa determine toate numerele
prime.umere.Este usor sa demonstram ca daca numarul n = 2^p – 1 atunci n trebuie sa fie prim.In 1644
Mersenne afirma in lucrarea “Cugetari fizico – matematice “ ca numarele de forma 2^p – 1 sunt prime pentru n =
2,3,5,7,13,17,19,31,67,127,257.
Multa vreme s-a crezut ca numerele de forma 2^n- 1 sunt numere prime pentru orice n,dar in 1536 Hudalricus
Regius a aratat ca 2^11 -1 =2047 nu este numar prim(este egal cu 23*89).In 1603 Pietro Cataldi a verificat corect
ca 2^17-1 si 2^19 – 1 sunt ambele numere prime,si de asemenea sunt prime si 23,29,31 si 37.In 1640 Fermat
demonstreaza ca Cataldi a gresit in legatura cu numerele 23 si 37,acestea nefiind prime;apoi Euler in 1738
demonstreaza ca acest Cataldi a gresit si in privinta numarului 29.Ceva mai tirziu Euler arata ca in privinta
numarului 31 Cataldi a facut o afirmatie corecta,acesta fiind prim.
Mersenne a prefatat lucrarea”Cugetari fizico-matematice”(1644) cu afirmatia prin care sustinea ca numerele de
forma 2^n-1 sunt prime pentru n=2,3,5,7,13,17,19,31,67,127 si 257.
Daca un numar de forma 2^n-1(n-numar prim) este prim spunem ca este un numar prim Mersenne.
Era evident ca Mersenne nu a reusit sa testeze toate aceste numere .In 1750,cind Euler a verificat urmatorul
numar din lista numerelor Mersenne,2^31-1,a descoperit ca si acest numar este prim.in 1876,Lucas verifica
numarul 2^127-1 si ajunge la concluzia ca si acest numar este prim.Sapte ani mai tirziu Pervouchine arata ca
numarul 2^61-1 este prim,deci Mersenne a omis acest numar.in jurul anului 1900 Powers demonstreaza ca
Mersenne a omis de asemenea alte doua numere:pe 2^89 - 1 si 2^107 - 1 .In sfirsit,in 1947,rangul numerelor
Mersenne ,<=258,a fost complet verificat si s-a determinat lista corecta a numerelor Mersenne:
N=2,3,5,7,13,17,19,31,61,89,107 si 127.

2)Definitia Numerelor Mersenne

Fie n un numar intrg prim.Numarul 2^n – 1 se numeste numar Mersenne prim.

Numerele Mersenne sunt numere de forma Mn=2^n – 1,unde n este un numar prim.
Primele numere Mersenne prime sunt 3,7,31,127,8191,131071,… corespunzind indicilor n = 2,3,5,7,13,17,… .
Numerele Mersenne prime au fost studiate pentru proprietatea remarcabila pe care aceste numere o au si
anume:fiecare numar prim corespunde exact unui numar patrat perfect.

S-a presupus ca exista o ifinitate de numere Mersenne prime.

Tabela cu numerele Mersenne prime:

Fie M(p) = 2p-1 si P(p) = 2p-1(2p-1). Lista tuturor numerelor Mersenne prime p,cunoscute pentru fiecare M(p)
(therefore P(p) este un numar perfect) :
## p
(exponent) digits
in Mp digits
in Pp year discoverer notes
1 2 1 1 ---- ----
2 3 1 2 ---- ----
3 5 2 3 ---- ----
4 7 3 4 ---- ----
5 13 4 8 1456 Anonymous
6 17 6 10 1588 Cataldi
7 19 6 12 1588 Cataldi
8 31 10 19 1772 Euler
9 61 19 37 1883 Pervushin
10 89 27 54 1911 Powers
11 107 33 65 1914 Powers note12 127 39 77 1876 Lucas
13 521 157 314 1952 Robinson
14 607 183 366 1952 Robinson
15 1279 386 770 1952 Robinson
16 2203 664 1327 1952 Robinson
17 2281 687 1373 1952 Robinson
18 3217 969 1937 1957 Riesel
19 4253 1281 2561 1961 Hurwitz
20 4423 1332 2663 1961 Hurwitz
21 9689 2917 5834 1963 Gillies

22 9941 2993 5985 1963 Gillies


23 11213 3376 6751 1963 Gillies
24 19937 6002 12003 1971 Tuckerman [Tuckerman71]25 21701 6533 13066 1978 Noll & Nickel
[NN80]26 23209 6987 13973 1979 Noll "
27 44497 13395 26790 1979 Nelson & Slowinski
[Slowinski79]28 86243 25962 51924 1982 Slowinski [Ewing83]29 110503 33265 66530 1988 Colquitt & Welsh
[CW91]30 132049 39751 79502 1983 Slowinski
31 216091 65050 130100 1985 Slowinski
32 756839 227832 455663 1992 Slowinski & Gage
[Peterson92]33 859433 258716 517430 1994 Slowinski & Gage
34 1257787 378632 757263 1996 Slowinski & Gage (web page)35 1398269 420921 841842 1996 Armengaud,
Woltman,
et. al. (GIMPS)
(web page)36 2976221 895932 1791864 1997 Spence, Woltman,
et. al. (GIMPS) (web page)37 3021377 909526 1819050 1998 Clarkson, Woltman, Kurowski
et. al. (GIMPS, PrimeNet)
(web page)38 6972593 2098960 4197919 1999 Hajratwala, Woltman, Kurowski
et. al. (GIMPS, PrimeNet) (web page)?? 13466917 4053946 8107892 2001 Cameron, Woltman, Kurowski
et. al. (GIMPS, PrimeNet) (web page)?? 20996011 6320430 12640858 2003 Shafer, Woltman, Kurowski
et. al. (GIMPS, PrimeNet) (web page)?? 24036583 7235733 14471465 2004 Findley, Woltman, Kurowski
et. al. (GIMPS, PrimeNet) (web page)

3)Numere perfecte si citeva teoreme

Multe culture antice au fost preocupate de relatiile care le are un numar cu suma si divizorii sai,de multe ori
dinduli-se interpretari mistice.Pe noi ne preocupa gasirea unei singure relatii de acest fel(relatia dintre un numar
dat ,suma si divizorii acestui numar).

Definitie:

Un numar intreg pozitiv n se numeste numar perfect daca acesta este egal cu suma tuturor divizorilor sai
proprii,mai putin el insusi(excuzindu-l pe n din suma).

De exemplu, 6 este primul numar perfect pentru ca 6=1+2+3.Urmatorul numar perfect este
28=1+2+4+7+14.Urmatoarele doua numere prime sunt 496 si 8128.Daca privim cu atentie aceste patru numere
observam ca 2*3,4*7,16*31,64*127 .Numerele au aceeasi forma :2^n-1(2^n-1)(pentru n=2,3,5 si 7).In fiecare
caz 2^n – 1 este un numar prim Mersenne.

Teorema1:
Un numar k este patrat perfect daca si numai daca are forma: 2^n-1(2^n-1) si 2^n-1 sunt numere prime.

Teorema2:
Daca 2^n-1 este prim,atunci n este de asemenea prim.

Deci cautarea numerelor Mersenne implica de asemenea cautarea numerelor care sunt patrate perfecte!!!

Daca dorim putem sa folosim si reprezentarea binara a numerelor.Pentru primele patru numere patrate perfecte
reprezentarea binara arata astfel:
6=110
28 =11100
496 = 111110000
8128 = 1111111000000

Reprezentarea in forma binara a numerelor este o consecinta a primei teoreme enuntate mai sus.
Cind dorim sa verificam daca un numar este numar prim Mersenne,de obicei,cautam mai intai divizori mai
mici.Urmatoarea teorema a lui Euler si Fermat este folositoare in acest sens:

Teorema3:
Presupunem ca p si q sunt doua numere prime.Daca q divide pe Mp=2^p – 1, atunci
Q=+/-1( mod 8) si q = 2kp + 1
pentru k intreg.

Teorema4:
Sa presupunem ca p=3 (mod 4 ) ar fi prim.2p+1 este de asemenea primdaca si numai daca 2p+1 il divide pe Mp.

Teorema5:
Daca adunam cifrele oricarui numar perfect(cu exceptia lui 6),apoi suma cifrelor numarului rezutat,si repetam
acest process pina cind ne ramine o singura cifra,acea cifra va fi unu.

Legatura dintre numerele Mersenne si numerele perfecte:

Exista o strinsa relatie intre numerele Mersenne si numerele perfecte.


Numerele perfecte sunt acele numere care sunt egale cu suma divizorilor lor proprii.
Ex:1+ 2 + 3 = 6
1 + 2 + 4 + 7 + 14 = 28
acest lucru a fost demonstrate de Euler :
cind 2^n – 1 este un numar prim,
numarul 2^(n-1) * ( 2^n – 1 ) este patrat perfect.

Numerele Mersenne prime cunoscute :

Mersenne Primes Numere perfecte

2
2-136
3
2 - 1 7 28

5
2 - 1 31 496

7
2 - 1 127 8,128

13
2 - 1 8,191 33,550,336

17
2 - 1 131,071 8,589,869,056

19
2 - 1 524,287 137,438,691,328

31
2 - 1 2,147,483,647

61
2 - 1 2,305,843,009,213,693,952

89
2 - 1 618,970,019,642,690,137,449,562,112

107
2 - 1 162,259,276,829,213,363,391,578,010,288,127

127
2 - 1 170,141,183,460,469,231,731,687,303,715,884,105,727

521
2-1

607
2-1

1,279
2-1

2,203
2-1

2,281
2-1

3,217
2-1

4,253
2-1

4,423
2-1
9,689
2-1

9,941
2-1

11,213
2-1

19,937
2-1

21,701
2-1

23,209
2-1

44,497
2-1

86,243
2-1

110,503
2-1

132,049
2-1

216,091
2-1

756,839
2-1

859,433
2-1

1,257,787
2-1

1,398,269
2-1

2,976,221
2-1

3,021,377
2-1

6,972,593
2-1

13,466,917
2-1
20,996,011
2-1

24,036,583
2-1

25,964,951
2-1

In 1985 cel mai mare numar prim cunoscut era


2^(216,091) – 1.

4) Testele Lucas-Lehmer(Testul de primalitate al unui numar prim)


Generarea numerelor Mersenne prime

Numerele Mersenne prime(asadar si numerele perfecte) au avut la baza urmatoarea teorema:

Testul Lucas-Lehmer :

Pentru p prim,numarul Mersenne 2^p – 1 este prim daca si numai daca 2^p – 1 divide pe S
(p – 1) unde S(n + 1) = S(n)^2 – 2, si S(1) = 4.

(Putem incepe si cu S(1) = 10 )


In pseudocod acest test se scrie astfel:

Lucas_Lehmer_Test(p):
s := 4;
for i from 3 to p do s := s^2 – 2 mod 2^p – 1;
if s = = 0 then
2^p este numar prim
else
2^p – 1 este numar compus

bazele acestei teorii au fost puse de Lucas in 1870 si a fost concretizata intr-un test de catre Lehmer in 1930.
Acest test este ideal pentru calculatoarele binare pentru ca impartirea prin 2^n – 1( in cod binary) poate fi facuta
folosind numai rotirea si adunarea.

5)Ipoteze si probleme nerezolvate referitoare la numerele Mersenne

Sunt infinite multe numere Mersenne compuse?


Euler a aratat:

Teorema:
Daca k>1 si p = 4k + 1 este prim,atunci 2*p + 1 este pri daca si numai daca 2^p = 1(mod 2*p + 1).
Deci,daca p = 4k + 3 si 2*p + 1 sunt prime atunci numarul Mersenne 2^p – 1 este compus.

Noua ipoteza referitoare la numere Mersenne:


Bateman,Selfridge si Wagstaff au presupus urmatoarele:
Sa presupunem ca p este un numar natural.Daca sunt indeplinite doua din conditiile de mai jos atunci este
indeplinita si a treia conditie:
1. p = 2^k+/-1 sau p = 4^k +/-3
2. 2^p – 1 este prim (evident este un numar Mersenne prim)
3. (2^p + 1) /3 este prim.

Exista mai multe numere Mersenne prime duble?

Daca n = Mp este prim,atunci si Mn este tot prim;sa numin acest numar MMp(un numar “dublu Mersenn”).Intr –
adevar fiecare din primele patru numere sunt prime:

MM2 = 2^3 – 1 = 7
MM3 = 2^7 – 1 = 127
MM5 = 2^31 – 1 = 2147483647

MM7 = 2^127 – 1 = 170141183460469231731687303715884105727

6)Cifru Mersenne

a)Algoritm de determinare a cifrului Mersenne:

Acest algoritm este format din doua parti:


-partea recurenta(schimba starea bitilor 19,937 cu cea a succesorilor)
- procedura de extragere a multiplilor
Specificarea algoritmului (schimbarea registrilor):

for i = 0 to 623
temp = first bit of a(i) followed by last 31 bits of a(i+1) ;
a(i) = temp shifted right one bit xor
X'9908B0DF' if temp is odd xor
a(i+397) ;
next i
Implementarea algoritmului in C arata astfel:

for i = 0 to 226
temp = first bit of a(i) followed by last 31 bits of a(i+1) ;
a(i) = temp shifted right one bit xor
X'9908B0DF' if temp is odd xor
a(i+397) ;
next i
for i = 227 to 622
temp = first bit of a(i) followed by last 31 bits of a(i+1) ;
a(i) = temp shifted right one bit xor
X'9908B0DF' if temp is odd xor
a(i-227) ;
next i
temp = first bit of a(623) followed by last 31 bits of a(0) ;
a(i) = temp shifted right one bit xor
X'9908B0DF' if temp is odd xor
a(396) ;
Cifru Mersenne parametrizeaza familia generatorilor ,parametrii aratind astfel:
L=19937
W=32
M=397
A = X'9908B0DF'
Unde W reprezinta lungimea in biti a sirurilor iar L este lungimea in biti a registrului pe care dorim sa-l
mutam,care trebuie sa fie exponent pentru numerele Mersenne prime parametrii suplimentari putind fi dervati
din urmatoarele:

N = floor(L/W) + 1
R = L mod W
Astfel,dupa ce L a fost impartit la W,R este restul si N este un coeficient intreg.Aceasta ecuatie se aplica numai
in cazul in care R este diferit de zero,care este intotdeauna adevarata dar in cazul trivial pentru un numar prim
N,N trebuie sa fie prim pentru a fi un exponent Mersene valid.

Daca aplicam parametrizarile de mai sus obtinem urmatorul cod:

for i = 0 to N-M-1
temp = first R bits of x(i) followed by last W-R bits of x(i+1) ;
x(i) = temp shifted right one bit xor
A if temp is odd xor
x(i+M) ;
next i
for i = N-M to N-2
temp = first R bits of x(i) followed by last W-R bits of x(i+1) ;
x(i) = temp shifted right one bit xor
A if temp is odd xor
x(i+M-N) ;
next i
temp = first R bits of x(N-1) followed by last W-R bits of x(0) ;
x(N-1) = temp shifted right one bit xor
A if temp is odd xor
x(M-1) ;

Algoritmul pentru determinarea cifrului Mersenne poate fi ilustrat ca un fel de feedback liniar cu schimbarea
registrului:

Un alt algoritm pentru determinarea cifrului Mersenne este urmatorul:

-partea de specificarea a algoritmului


for i = 0 to 350
temp = first 13 bits of a(i) followed by last 19 bits of a(i+1) ;
a(i) = temp shifted right one bit xor
X'E4BD75F5' [or X'CCAB8EE7'] if temp is odd xor
a(i+175) ;
next i

-implementarea partii de specificare


for i = 0 to 175
temp = first 13 bits of a(i) followed by last 19 bits of a(i+1) ;
a(i) = temp shifted right one bit xor
X'E4BD75F5' [or X'CCAB8EE7'] if temp is odd xor
a(i+175) ;
next i
for i = 176 to 349
temp = first 13 bits of a(i) followed by last 19 bits of a(i+1) ;
a(i) = temp shifted right one bit xor
X'E4BD75F5' [or X'CCAB8EE7'] if temp is odd xor
a(i-176) ;
next i
temp = first 13 bits of a(350) followed by last 19 bits of a(0) ;
a(i) = temp shifted right one bit xor
X'E4BD75F5' [or X'CCAB8EE7'] if temp is odd xor
a(174) ;

- functia principala

temp = selected array element ;


temp = temp xor
temp shifted right 11 bits ;
temp = temp xor
((temp shifted left 7 bits) and X'655E5280' [or X'31B6AB00'] ) ;
temp = temp xor
((temp shifted left 15 bits) and X'FFD58000' [or X'FFE50000']) ;
value = temp xor
temp shifted right 17 bits ;

b)Algoritm pentru determinarea cifrului Mersenne:

Acest algoritm a fost proiectat tinind cont de numerosi generatori.Este un generator rapid si evita imultirile si
impartirile,acesta beneficiind si de pipelines.
Algoritmul lui Mersenne a fost implementat in C++.Este un algoritm liber si portabil.

Descrierea algoritmului:
-crearea generatorului cu MTRand r;
-generarea numerelor intregi
- Optiuni
-forma implicita
-numar intreg unic
-sir de orice lungime
-este usor de schimbat declaratiile
-exemplu de program
-teste de validare a rezultatelor si performantelor

// The Mersenne Twister is an algorithm for generating random numbers. It


// was designed with consideration of the flaws in various other generators.
// The period, 2^19937-1, and the order of equidistribution, 623 dimensions,
// are far greater. The generator is also fast; it avoids multiplication and
// division, and it benefits from caches and pipelines. For more information

#ifndef MERSENNETWISTER_H
#define MERSENNETWISTER_H

// Not thread safe (unless auto-initialization is avoided and each thread has
// its own MTRand object)

#include <iostream>
#include <limits.h>
#include <stdio.h>
#include <time.h>
#include <math.h>

class MTRand {
// Data
public:
typedef unsigned long uint32; // unsigned integer type, at least 32 bits

enum { N = 624 }; // length of state vector


enum { SAVE = N + 1 }; // length of array for save()

protected:
enum { M = 397 }; // period parameter

uint32 state[N]; // internal state


uint32 *pNext; // next value to get from state
int left; // number of values left before reload needed

//Methods
public:
MTRand( const uint32& oneSeed ); // initialize with a simple uint32
MTRand( uint32 *const bigSeed, uint32 const seedLength = N ); // or an array
MTRand(); // auto-initialize with /dev/urandom or time() and clock()

// Do NOT use for CRYPTOGRAPHY without securely hashing several returned


// values together, otherwise the generator state can be learned after
// reading 624 consecutive values.

// Access to 32-bit random numbers


double rand(); // real number in [0,1]
double rand( const double& n ); // real number in [0,n]
double randExc(); // real number in [0,1)
double randExc( const double& n ); // real number in [0,n)
double randDblExc(); // real number in (0,1)
double randDblExc( const double& n ); // real number in (0,n)
uint32 randInt(); // integer in [0,2^32-1]
uint32 randInt( const uint32& n ); // integer in [0,n] for n < 2^32
double operator()() { return rand(); } // same as rand()

// Access to 53-bit random numbers (capacity of IEEE double precision)


double rand53(); // real number in [0,1)

// Access to nonuniform random number distributions


double randNorm( const double& mean = 0.0, const double& variance = 0.0 );

// Re-seeding functions with same behavior as initializers


void seed( const uint32 oneSeed );
void seed( uint32 *const bigSeed, const uint32 seedLength = N );
void seed();

// Saving and loading generator state


void save( uint32* saveArray ) const; // to array of size SAVE
void load( uint32 *const loadArray ); // from such array
friend std::ostream& operator<<( std::ostream& os, const MTRand& mtrand );
friend std::istream& operator>>( std::istream& is, MTRand& mtrand );

protected:
void initialize( const uint32 oneSeed );
void reload();
uint32 hiBit( const uint32& u ) const { return u & 0x80000000UL; }
uint32 loBit( const uint32& u ) const { return u & 0x00000001UL; }
uint32 loBits( const uint32& u ) const { return u & 0x7fffffffUL; }
uint32 mixBits( const uint32& u, const uint32& v ) const
{ return hiBit(u) | loBits(v); }
uint32 twist( const uint32& m, const uint32& s0, const uint32& s1 ) const
{ return m ^ (mixBits(s0,s1)>>1) ^ (-loBit(s1) & 0x9908b0dfUL); }
static uint32 hash( time_t t, clock_t c );
};

inline MTRand::MTRand( const uint32& oneSeed )


{ seed(oneSeed); }

inline MTRand::MTRand( uint32 *const bigSeed, const uint32 seedLength )


{ seed(bigSeed,seedLength); }

inline MTRand::MTRand()
{ seed(); }

inline double MTRand::rand()


{ return double(randInt()) * (1.0/4294967295.0); }

inline double MTRand::rand( const double& n )


{ return rand() * n; }

inline double MTRand::randExc()


{ return double(randInt()) * (1.0/4294967296.0); }

inline double MTRand::randExc( const double& n )


{ return randExc() * n; }

inline double MTRand::randDblExc()


{ return ( double(randInt()) + 0.5 ) * (1.0/4294967296.0); }

inline double MTRand::randDblExc( const double& n )


{ return randDblExc() * n; }

inline double MTRand::rand53()


{
uint32 a = randInt() >> 5, b = randInt() >> 6;
return ( a * 67108864.0 + b ) * (1.0/9007199254740992.0); // by Isaku Wada
}

inline double MTRand::randNorm( const double& mean, const double& variance )


{
// Return a real number from a normal (Gaussian) distribution with given
// mean and variance by Box-Muller method
double r = sqrt( -2.0 * log( 1.0-randDblExc()) ) * variance;
double phi = 2.0 * 3.14159265358979323846264338328 * randExc();
return mean + r * cos(phi);
}

inline MTRand::uint32 MTRand::randInt()


{
// Pull a 32-bit integer from the generator state
// Every other access function simply transforms the numbers extracted here

if( left == 0 ) reload();


--left;

register uint32 s1;


s1 = *pNext++;
s1 ^= (s1 >> 11);
s1 ^= (s1 << 7) & 0x9d2c5680UL;
s1 ^= (s1 << 15) & 0xefc60000UL;
return ( s1 ^ (s1 >> 18) );
}

inline MTRand::uint32 MTRand::randInt( const uint32& n )


{
// Find which bits are used in n
// Optimized by Magnus Jonsson (magnus@smartelectronix.com)
uint32 used = n;
used |= used >> 1;
used |= used >> 2;
used |= used >> 4;
used |= used >> 8;
used |= used >> 16;

// Draw numbers until one is found in [0,n]


uint32 i;
do
i = randInt() & used; // toss unused bits to shorten search
while( i > n );
return i;
}

inline void MTRand::seed( const uint32 oneSeed )


{
// Seed the generator with a simple uint32
initialize(oneSeed);
reload();
}

inline void MTRand::seed( uint32 *const bigSeed, const uint32 seedLength )


{
// Seed the generator with an array of uint32's
// There are 2^19937-1 possible initial states. This function allows
// all of those to be accessed by providing at least 19937 bits (with a
// default seed length of N = 624 uint32's). Any bits above the lower 32
// in each element are discarded.
// Just call seed() if you want to get array from /dev/urandom
initialize(19650218UL);
register int i = 1;
register uint32 j = 0;
register int k = ( N > seedLength ? N : seedLength );
for( ; k; --k )
{
state[i] =
state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1664525UL );
state[i] += ( bigSeed[j] & 0xffffffffUL ) + j;
state[i] &= 0xffffffffUL;
++i; ++j;
if( i >= N ) { state[0] = state[N-1]; i = 1; }
if( j >= seedLength ) j = 0;
}
for( k = N - 1; k; --k )
{
state[i] =
state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1566083941UL );
state[i] -= i;
state[i] &= 0xffffffffUL;
++i;
if( i >= N ) { state[0] = state[N-1]; i = 1; }
}
state[0] = 0x80000000UL; // MSB is 1, assuring non-zero initial array
reload();
}

inline void MTRand::seed()


{
// Seed the generator with an array from /dev/urandom if available
// Otherwise use a hash of time() and clock() values

// First try getting an array from /dev/urandom


FILE* urandom = fopen( "/dev/urandom", "rb" );
if( urandom )
{
uint32 bigSeed[N];
register uint32 *s = bigSeed;
register int i = N;
register bool success = true;
while( success && i-- )
success = fread( s++, sizeof(uint32), 1, urandom );
fclose(urandom);
if( success ) { seed( bigSeed, N ); return; }
}

// Was not successful, so use time() and clock() instead


seed( hash( time(NULL), clock() ) );
}

inline void MTRand::initialize( const uint32 seed )


{
// Initialize generator state with seed
// See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier.
// In previous versions, most significant bits (MSBs) of the seed affect
// only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto.
register uint32 *s = state;
register uint32 *r = state;
register int i = 1;
*s++ = seed & 0xffffffffUL;
for( ; i < N; ++i )
{
*s++ = ( 1812433253UL * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffUL;
r++;
}
}

inline void MTRand::reload()


{
// Generate N new values in state
// Made clearer and faster by Matthew Bellew (matthew.bellew@home.com)
register uint32 *p = state;
register int i;
for( i = N - M; i--; ++p )
*p = twist( p[M], p[0], p[1] );
for( i = M; --i; ++p )
*p = twist( p[M-N], p[0], p[1] );
*p = twist( p[M-N], p[0], state[0] );

left = N, pNext = state;


}

inline MTRand::uint32 MTRand::hash( time_t t, clock_t c )


{
// Get a uint32 from t and c
// Better than uint32(x) in case x is floating point in [0,1]
// Based on code by Lawrence Kirby (fred@genesis.demon.co.uk)

static uint32 differ = 0; // guarantee time-based seeds will change

uint32 h1 = 0;
unsigned char *p = (unsigned char *) &t;
for( size_t i = 0; i < sizeof(t); ++i )
{
h1 *= UCHAR_MAX + 2U;
h1 += p[i];
}
uint32 h2 = 0;
p = (unsigned char *) &c;
for( size_t j = 0; j < sizeof(c); ++j )
{
h2 *= UCHAR_MAX + 2U;
h2 += p[j];
}
return ( h1 + differ++ ) ^ h2;
}

inline void MTRand::save( uint32* saveArray ) const


{
register uint32 *sa = saveArray;
register const uint32 *s = state;
register int i = N;
for( ; i--; *sa++ = *s++ ) {}
*sa = left;
}

inline void MTRand::load( uint32 *const loadArray )


{
register uint32 *s = state;
register uint32 *la = loadArray;
register int i = N;
for( ; i--; *s++ = *la++ ) {}
left = *la;
pNext = &state[N-left];
}

inline std::ostream& operator<<( std::ostream& os, const MTRand& mtrand )


{
register const MTRand::uint32 *s = mtrand.state;
register int i = mtrand.N;
for( ; i--; os << *s++ << "\t" ) {}
return os << mtrand.left;
}

inline std::istream& operator>>( std::istream& is, MTRand& mtrand )


{
register MTRand::uint32 *s = mtrand.state;
register int i = mtrand.N;
for( ; i--; is >> *s++ ) {}
is >> mtrand.left;
mtrand.pNext = &mtrand.state[mtrand.N-mtrand.left];
return is;
}

#endif // MERSENNETWISTER_H

// Change log:
//
// v0.1 - First release on 15 May 2000
// - Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
// - Translated from C to C++
// - Made completely ANSI compliant
// - Designed convenient interface for initialization, seeding, and
// obtaining numbers in default or user-defined ranges
// - Added automatic seeding from /dev/urandom or time() and clock()
// - Provided functions for saving and loading generator state
//
// v0.2 - Fixed bug which reloaded generator one step too late
//
// v0.3 - Switched to clearer, faster reload() code from Matthew Bellew
//
// v0.4 - Removed trailing newline in saved generator format to be consistent
// with output format of built-in types
//
// v0.5 - Improved portability by replacing static const int's with enum's and
// clarifying return values in seed(); suggested by Eric Heimburg
// - Removed MAXINT constant; use 0xffffffffUL instead
//
// v0.6 - Eliminated seed overflow when uint32 is larger than 32 bits
// - Changed integer [0,n] generator to give better uniformity
//
// v0.7 - Fixed operator precedence ambiguity in reload()
// - Added access for real numbers in (0,1) and (0,n)
//
// v0.8 - Included time.h header to properly support time_t and clock_t
//
// v1.0 - Revised seeding to match 26 Jan 2002 update of Nishimura and Matsumoto
// - Allowed for seeding with arrays of any length
// - Added access for real numbers in [0,1) with 53-bit resolution
// - Added access for real numbers from normal (Gaussian) distributions
// - Increased overall speed by optimizing twist()
// - Doubled speed of integer [0,n] generation
// - Fixed out-of-range number generation on 64-bit machines
// - Improved portability by substituting literal constants for long enum's
// - Changed license from GNU LGPL to BSD

S-ar putea să vă placă și