xref: /petsc/src/sys/classes/random/impls/rander48/rander48.c (revision 4dfa11a44d5adf2389f1d3acbc8f3c1116dc6c3a)
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 
179371c9d4SSatish Balay static double _dorander48(PetscRandom_Rander48 *r48) {
18003ee160SMatthew G. Knepley   unsigned long  accu;
19003ee160SMatthew G. Knepley   unsigned short temp[2];
20003ee160SMatthew G. Knepley 
21e4e5cec9SBarry Smith   accu    = (unsigned long)r48->mult[0] * (unsigned long)r48->seed[0] + (unsigned long)r48->add;
22003ee160SMatthew G. Knepley   temp[0] = (unsigned short)accu; /* lower 16 bits */
23003ee160SMatthew G. Knepley   accu >>= sizeof(unsigned short) * 8;
24e4e5cec9SBarry Smith   accu += (unsigned long)r48->mult[0] * (unsigned long)r48->seed[1] + (unsigned long)r48->mult[1] * (unsigned long)r48->seed[0];
25003ee160SMatthew G. Knepley   temp[1] = (unsigned short)accu; /* middle 16 bits */
26003ee160SMatthew G. Knepley   accu >>= sizeof(unsigned short) * 8;
27e4e5cec9SBarry Smith   accu += r48->mult[0] * r48->seed[2] + r48->mult[1] * r48->seed[1] + r48->mult[2] * r48->seed[0];
28e4e5cec9SBarry Smith   r48->seed[0] = temp[0];
29e4e5cec9SBarry Smith   r48->seed[1] = temp[1];
30e4e5cec9SBarry Smith   r48->seed[2] = (unsigned short)accu;
31e4e5cec9SBarry Smith   return ldexp((double)r48->seed[0], -48) + ldexp((double)r48->seed[1], -32) + ldexp((double)r48->seed[2], -16);
32003ee160SMatthew G. Knepley }
33003ee160SMatthew G. Knepley 
349371c9d4SSatish Balay static PetscErrorCode PetscRandomSeed_Rander48(PetscRandom r) {
35e4e5cec9SBarry Smith   PetscRandom_Rander48 *r48 = (PetscRandom_Rander48 *)r->data;
36e4e5cec9SBarry Smith 
37003ee160SMatthew G. Knepley   PetscFunctionBegin;
38e4e5cec9SBarry Smith   r48->seed[0] = RANDER48_SEED_0;
39e4e5cec9SBarry Smith   r48->seed[1] = (unsigned short)r->seed;
40e4e5cec9SBarry Smith   r48->seed[2] = (unsigned short)(r->seed >> 16);
41e4e5cec9SBarry Smith   r48->mult[0] = RANDER48_MULT_0;
42e4e5cec9SBarry Smith   r48->mult[1] = RANDER48_MULT_1;
43e4e5cec9SBarry Smith   r48->mult[2] = RANDER48_MULT_2;
44e4e5cec9SBarry Smith   r48->add     = RANDER48_ADD;
45003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
46003ee160SMatthew G. Knepley }
47003ee160SMatthew G. Knepley 
489371c9d4SSatish Balay static PetscErrorCode PetscRandomGetValue_Rander48(PetscRandom r, PetscScalar *val) {
49e4e5cec9SBarry Smith   PetscRandom_Rander48 *r48 = (PetscRandom_Rander48 *)r->data;
50e4e5cec9SBarry Smith 
51003ee160SMatthew G. Knepley   PetscFunctionBegin;
52003ee160SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX)
53003ee160SMatthew G. Knepley   if (r->iset) {
549f0394f4SBarry Smith     *val = PetscRealPart(r->low) + PetscImaginaryPart(r->low) * PETSC_i;
55ad540459SPierre Jolivet     if (PetscRealPart(r->width)) *val += PetscRealPart(r->width) * _dorander48(r48);
56ad540459SPierre Jolivet     if (PetscImaginaryPart(r->width)) *val += PetscImaginaryPart(r->width) * _dorander48(r48) * PETSC_i;
57003ee160SMatthew G. Knepley   } else {
58e4e5cec9SBarry Smith     *val = _dorander48(r48) + _dorander48(r48) * PETSC_i;
59003ee160SMatthew G. Knepley   }
60003ee160SMatthew G. Knepley #else
61e4e5cec9SBarry Smith   if (r->iset) *val = r->width * _dorander48(r48) + r->low;
62e4e5cec9SBarry Smith   else *val = _dorander48(r48);
63003ee160SMatthew G. Knepley #endif
64003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
65003ee160SMatthew G. Knepley }
66003ee160SMatthew G. Knepley 
679371c9d4SSatish Balay static PetscErrorCode PetscRandomGetValueReal_Rander48(PetscRandom r, PetscReal *val) {
68e4e5cec9SBarry Smith   PetscRandom_Rander48 *r48 = (PetscRandom_Rander48 *)r->data;
69e4e5cec9SBarry Smith 
70003ee160SMatthew G. Knepley   PetscFunctionBegin;
71003ee160SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX)
72e4e5cec9SBarry Smith   if (r->iset) *val = PetscRealPart(r->width) * _dorander48(r48) + PetscRealPart(r->low);
73e4e5cec9SBarry Smith   else *val = _dorander48(r48);
74003ee160SMatthew G. Knepley #else
75e4e5cec9SBarry Smith   if (r->iset) *val = r->width * _dorander48(r48) + r->low;
76e4e5cec9SBarry Smith   else *val = _dorander48(r48);
77003ee160SMatthew G. Knepley #endif
78003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
79003ee160SMatthew G. Knepley }
80003ee160SMatthew G. Knepley 
819371c9d4SSatish Balay static PetscErrorCode PetscRandomDestroy_Rander48(PetscRandom r) {
82e4e5cec9SBarry Smith   PetscFunctionBegin;
839566063dSJacob Faibussowitsch   PetscCall(PetscFree(r->data));
84e4e5cec9SBarry Smith   PetscFunctionReturn(0);
85e4e5cec9SBarry Smith }
86e4e5cec9SBarry Smith 
87003ee160SMatthew G. Knepley static struct _PetscRandomOps PetscRandomOps_Values = {
88267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(seed, PetscRandomSeed_Rander48),
89267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvalue, PetscRandomGetValue_Rander48),
90267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvaluereal, PetscRandomGetValueReal_Rander48),
91267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvalues, NULL),
92267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvaluesreal, NULL),
93267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(destroy, PetscRandomDestroy_Rander48),
94003ee160SMatthew G. Knepley };
95003ee160SMatthew G. Knepley 
96003ee160SMatthew G. Knepley /*MC
97b3bd51deSBarry Smith    PETSCRANDER48 - simple portable reimplementation of basic Unix drand48() random number generator that should generate the
98b3bd51deSBarry Smith         exact same random numbers on any system.
99003ee160SMatthew G. Knepley 
100003ee160SMatthew G. Knepley    Options Database Keys:
1011179163eSBarry Smith . -random_type <rand,rand48,rander48,sprng> - select the random number generator at runtime
102003ee160SMatthew G. Knepley 
10395452b02SPatrick Sanan   Notes:
104811af0c4SBarry Smith     This is the default random number generate provided by `PetscRandomCreate()` if you do not set a particular implementation.
105e4e5cec9SBarry Smith 
106811af0c4SBarry Smith   Each `PetscRandom` object created with this type has its own seed and its own history, so multiple `PetscRandom` objects of this type
107e4e5cec9SBarry Smith   will not interfer with random numbers generated by other objects. Each PETSc object of this type will produce the exact same set of
108811af0c4SBarry Smith   random numbers so if you wish different `PetscRandom` objects of this type set different seeds for each one after you create them with
109811af0c4SBarry Smith   `PetscRandomSetSeed()` followed by `PetscRandomSeed()`.
110e4e5cec9SBarry Smith 
111003ee160SMatthew G. Knepley   Level: beginner
112003ee160SMatthew G. Knepley 
1131179163eSBarry Smith .seealso: `PetscRandomCreate()`, `PetscRandomSetType()`, `PETSCRAND`, `PETSCRAND48`, `PETSCRANDER48`, `PETSCSPRNG`, `PetscRandomSetSeed()`,
1141179163eSBarry Smith           `PetscRandomSeed()`, `PetscRandomSetFromOptions()`
115003ee160SMatthew G. Knepley M*/
116003ee160SMatthew G. Knepley 
1179371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PetscRandomCreate_Rander48(PetscRandom r) {
118e4e5cec9SBarry Smith   PetscRandom_Rander48 *r48;
119003ee160SMatthew G. Knepley 
120003ee160SMatthew G. Knepley   PetscFunctionBegin;
121*4dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&r48));
122e4e5cec9SBarry Smith   /* r48 does not need to be initialized because PetscRandomSeed() is always called before use and sets the needed values */
123e4e5cec9SBarry Smith   r->data = r48;
1249566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(r->ops, &PetscRandomOps_Values, sizeof(PetscRandomOps_Values)));
1259566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)r, PETSCRANDER48));
126003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
127003ee160SMatthew G. Knepley }
128