xref: /petsc/src/sys/classes/random/impls/rander48/rander48.c (revision 3cb3609b6a296a92a70bbd05421941ba494f28de)
1d6cc7855SJacob Faibussowitsch #include <petsc/private/randomimpl.h>
2003ee160SMatthew G. Knepley 
3e4e5cec9SBarry Smith typedef struct {
4e4e5cec9SBarry Smith   unsigned short seed[3];
5e4e5cec9SBarry Smith   unsigned short mult[3];
6e4e5cec9SBarry Smith   unsigned short add;
7e4e5cec9SBarry Smith } PetscRandom_Rander48;
8e4e5cec9SBarry Smith 
9003ee160SMatthew G. Knepley #define RANDER48_SEED_0 (0x330e)
10003ee160SMatthew G. Knepley #define RANDER48_SEED_1 (0xabcd)
11003ee160SMatthew G. Knepley #define RANDER48_SEED_2 (0x1234)
12003ee160SMatthew G. Knepley #define RANDER48_MULT_0 (0xe66d)
13003ee160SMatthew G. Knepley #define RANDER48_MULT_1 (0xdeec)
14003ee160SMatthew G. Knepley #define RANDER48_MULT_2 (0x0005)
15003ee160SMatthew G. Knepley #define RANDER48_ADD    (0x000b)
16003ee160SMatthew G. Knepley 
_dorander48(PetscRandom_Rander48 * r48)17d71ae5a4SJacob Faibussowitsch static double _dorander48(PetscRandom_Rander48 *r48)
18d71ae5a4SJacob Faibussowitsch {
19003ee160SMatthew G. Knepley   unsigned long  accu;
20003ee160SMatthew G. Knepley   unsigned short temp[2];
21003ee160SMatthew G. Knepley 
22e4e5cec9SBarry Smith   accu    = (unsigned long)r48->mult[0] * (unsigned long)r48->seed[0] + (unsigned long)r48->add;
23003ee160SMatthew G. Knepley   temp[0] = (unsigned short)accu; /* lower 16 bits */
24003ee160SMatthew G. Knepley   accu >>= sizeof(unsigned short) * 8;
25e4e5cec9SBarry Smith   accu += (unsigned long)r48->mult[0] * (unsigned long)r48->seed[1] + (unsigned long)r48->mult[1] * (unsigned long)r48->seed[0];
26003ee160SMatthew G. Knepley   temp[1] = (unsigned short)accu; /* middle 16 bits */
27003ee160SMatthew G. Knepley   accu >>= sizeof(unsigned short) * 8;
286f2c871aSStefano Zampini   accu += (unsigned long)r48->mult[0] * r48->seed[2] + (unsigned long)r48->mult[1] * r48->seed[1] + (unsigned long)r48->mult[2] * r48->seed[0];
29e4e5cec9SBarry Smith   r48->seed[0] = temp[0];
30e4e5cec9SBarry Smith   r48->seed[1] = temp[1];
31e4e5cec9SBarry Smith   r48->seed[2] = (unsigned short)accu;
32e4e5cec9SBarry Smith   return ldexp((double)r48->seed[0], -48) + ldexp((double)r48->seed[1], -32) + ldexp((double)r48->seed[2], -16);
33003ee160SMatthew G. Knepley }
34003ee160SMatthew G. Knepley 
PetscRandomSeed_Rander48(PetscRandom r)35d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscRandomSeed_Rander48(PetscRandom r)
36d71ae5a4SJacob Faibussowitsch {
37e4e5cec9SBarry Smith   PetscRandom_Rander48 *r48 = (PetscRandom_Rander48 *)r->data;
38e4e5cec9SBarry Smith 
39003ee160SMatthew G. Knepley   PetscFunctionBegin;
40e4e5cec9SBarry Smith   r48->seed[0] = RANDER48_SEED_0;
41e4e5cec9SBarry Smith   r48->seed[1] = (unsigned short)r->seed;
42e4e5cec9SBarry Smith   r48->seed[2] = (unsigned short)(r->seed >> 16);
43e4e5cec9SBarry Smith   r48->mult[0] = RANDER48_MULT_0;
44e4e5cec9SBarry Smith   r48->mult[1] = RANDER48_MULT_1;
45e4e5cec9SBarry Smith   r48->mult[2] = RANDER48_MULT_2;
46e4e5cec9SBarry Smith   r48->add     = RANDER48_ADD;
473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48003ee160SMatthew G. Knepley }
49003ee160SMatthew G. Knepley 
PetscRandomGetValue_Rander48(PetscRandom r,PetscScalar * val)50d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscRandomGetValue_Rander48(PetscRandom r, PetscScalar *val)
51d71ae5a4SJacob Faibussowitsch {
52e4e5cec9SBarry Smith   PetscRandom_Rander48 *r48 = (PetscRandom_Rander48 *)r->data;
53e4e5cec9SBarry Smith 
54003ee160SMatthew G. Knepley   PetscFunctionBegin;
55003ee160SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX)
56003ee160SMatthew G. Knepley   if (r->iset) {
579f0394f4SBarry Smith     *val = PetscRealPart(r->low) + PetscImaginaryPart(r->low) * PETSC_i;
58ad540459SPierre Jolivet     if (PetscRealPart(r->width)) *val += PetscRealPart(r->width) * _dorander48(r48);
59ad540459SPierre Jolivet     if (PetscImaginaryPart(r->width)) *val += PetscImaginaryPart(r->width) * _dorander48(r48) * PETSC_i;
60003ee160SMatthew G. Knepley   } else {
61e4e5cec9SBarry Smith     *val = _dorander48(r48) + _dorander48(r48) * PETSC_i;
62003ee160SMatthew G. Knepley   }
63003ee160SMatthew G. Knepley #else
64e4e5cec9SBarry Smith   if (r->iset) *val = r->width * _dorander48(r48) + r->low;
65e4e5cec9SBarry Smith   else *val = _dorander48(r48);
66003ee160SMatthew G. Knepley #endif
673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
68003ee160SMatthew G. Knepley }
69003ee160SMatthew G. Knepley 
PetscRandomGetValueReal_Rander48(PetscRandom r,PetscReal * val)70d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscRandomGetValueReal_Rander48(PetscRandom r, PetscReal *val)
71d71ae5a4SJacob Faibussowitsch {
72e4e5cec9SBarry Smith   PetscRandom_Rander48 *r48 = (PetscRandom_Rander48 *)r->data;
73e4e5cec9SBarry Smith 
74003ee160SMatthew G. Knepley   PetscFunctionBegin;
75003ee160SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX)
76e4e5cec9SBarry Smith   if (r->iset) *val = PetscRealPart(r->width) * _dorander48(r48) + PetscRealPart(r->low);
77e4e5cec9SBarry Smith   else *val = _dorander48(r48);
78003ee160SMatthew G. Knepley #else
79e4e5cec9SBarry Smith   if (r->iset) *val = r->width * _dorander48(r48) + r->low;
80e4e5cec9SBarry Smith   else *val = _dorander48(r48);
81003ee160SMatthew G. Knepley #endif
823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
83003ee160SMatthew G. Knepley }
84003ee160SMatthew G. Knepley 
PetscRandomDestroy_Rander48(PetscRandom r)85d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscRandomDestroy_Rander48(PetscRandom r)
86d71ae5a4SJacob Faibussowitsch {
87e4e5cec9SBarry Smith   PetscFunctionBegin;
889566063dSJacob Faibussowitsch   PetscCall(PetscFree(r->data));
893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
90e4e5cec9SBarry Smith }
91e4e5cec9SBarry Smith 
92003ee160SMatthew G. Knepley static struct _PetscRandomOps PetscRandomOps_Values = {
93267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(seed, PetscRandomSeed_Rander48),
94267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvalue, PetscRandomGetValue_Rander48),
95267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvaluereal, PetscRandomGetValueReal_Rander48),
96267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvalues, NULL),
97267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvaluesreal, NULL),
98267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(destroy, PetscRandomDestroy_Rander48),
99*8a403008SStefano Zampini   PetscDesignatedInitializer(setfromoptions, NULL),
100003ee160SMatthew G. Knepley };
101003ee160SMatthew G. Knepley 
102003ee160SMatthew G. Knepley /*MC
103c31d2375SBarry Smith    PETSCRANDER48 - simple portable reimplementation of basic Unix `drand48()` random number generator that should generate the
104b3bd51deSBarry Smith         exact same random numbers on any system.
105003ee160SMatthew G. Knepley 
106c31d2375SBarry Smith    Options Database Key:
1071179163eSBarry Smith . -random_type <rand,rand48,rander48,sprng> - select the random number generator at runtime
108003ee160SMatthew G. Knepley 
109c31d2375SBarry Smith   Level: beginner
110c31d2375SBarry Smith 
11195452b02SPatrick Sanan   Notes:
112811af0c4SBarry Smith     This is the default random number generate provided by `PetscRandomCreate()` if you do not set a particular implementation.
113e4e5cec9SBarry Smith 
114811af0c4SBarry Smith   Each `PetscRandom` object created with this type has its own seed and its own history, so multiple `PetscRandom` objects of this type
115d5b43468SJose E. Roman   will not interfere with random numbers generated by other objects. Each PETSc object of this type will produce the exact same set of
116811af0c4SBarry Smith   random numbers so if you wish different `PetscRandom` objects of this type set different seeds for each one after you create them with
117811af0c4SBarry Smith   `PetscRandomSetSeed()` followed by `PetscRandomSeed()`.
118e4e5cec9SBarry Smith 
1191179163eSBarry Smith .seealso: `PetscRandomCreate()`, `PetscRandomSetType()`, `PETSCRAND`, `PETSCRAND48`, `PETSCRANDER48`, `PETSCSPRNG`, `PetscRandomSetSeed()`,
1201179163eSBarry Smith           `PetscRandomSeed()`, `PetscRandomSetFromOptions()`
121003ee160SMatthew G. Knepley M*/
122003ee160SMatthew G. Knepley 
PetscRandomCreate_Rander48(PetscRandom r)123d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscRandomCreate_Rander48(PetscRandom r)
124d71ae5a4SJacob Faibussowitsch {
125e4e5cec9SBarry Smith   PetscRandom_Rander48 *r48;
126003ee160SMatthew G. Knepley 
127003ee160SMatthew G. Knepley   PetscFunctionBegin;
1284dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&r48));
129e4e5cec9SBarry Smith   /* r48 does not need to be initialized because PetscRandomSeed() is always called before use and sets the needed values */
130e4e5cec9SBarry Smith   r->data   = r48;
131aea10558SJacob Faibussowitsch   r->ops[0] = PetscRandomOps_Values;
1329566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)r, PETSCRANDER48));
1333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
134003ee160SMatthew G. Knepley }
135