xref: /petsc/src/sys/classes/random/impls/rander48/rander48.c (revision 1179163e0bf5c4dd309079707fd3c0dfe8d44eee)
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 
17e4e5cec9SBarry Smith static double _dorander48(PetscRandom_Rander48 *r48)
18003ee160SMatthew G. Knepley {
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;
28e4e5cec9SBarry Smith   accu    += r48->mult[0] * r48->seed[2] + r48->mult[1] * r48->seed[1] + 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 
35e4e5cec9SBarry Smith static PetscErrorCode  PetscRandomSeed_Rander48(PetscRandom r)
36003ee160SMatthew G. Knepley {
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;
47003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
48003ee160SMatthew G. Knepley }
49003ee160SMatthew G. Knepley 
50e4e5cec9SBarry Smith static PetscErrorCode  PetscRandomGetValue_Rander48(PetscRandom r, PetscScalar *val)
51003ee160SMatthew G. Knepley {
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;
589f0394f4SBarry Smith     if (PetscRealPart(r->width)) {
59e4e5cec9SBarry Smith       *val += PetscRealPart(r->width)* _dorander48(r48);
609f0394f4SBarry Smith     }
619f0394f4SBarry Smith     if (PetscImaginaryPart(r->width)) {
62e4e5cec9SBarry Smith       *val += PetscImaginaryPart(r->width)* _dorander48(r48) * PETSC_i;
639f0394f4SBarry Smith     }
64003ee160SMatthew G. Knepley   } else {
65e4e5cec9SBarry Smith     *val = _dorander48(r48) +  _dorander48(r48)*PETSC_i;
66003ee160SMatthew G. Knepley   }
67003ee160SMatthew G. Knepley #else
68e4e5cec9SBarry Smith   if (r->iset) *val = r->width * _dorander48(r48) + r->low;
69e4e5cec9SBarry Smith   else         *val = _dorander48(r48);
70003ee160SMatthew G. Knepley #endif
71003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
72003ee160SMatthew G. Knepley }
73003ee160SMatthew G. Knepley 
74e4e5cec9SBarry Smith static PetscErrorCode  PetscRandomGetValueReal_Rander48(PetscRandom r, PetscReal *val)
75003ee160SMatthew G. Knepley {
76e4e5cec9SBarry Smith   PetscRandom_Rander48 *r48 = (PetscRandom_Rander48*)r->data;
77e4e5cec9SBarry Smith 
78003ee160SMatthew G. Knepley   PetscFunctionBegin;
79003ee160SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX)
80e4e5cec9SBarry Smith   if (r->iset) *val = PetscRealPart(r->width)*_dorander48(r48) + PetscRealPart(r->low);
81e4e5cec9SBarry Smith   else         *val = _dorander48(r48);
82003ee160SMatthew G. Knepley #else
83e4e5cec9SBarry Smith   if (r->iset) *val = r->width * _dorander48(r48) + r->low;
84e4e5cec9SBarry Smith   else         *val = _dorander48(r48);
85003ee160SMatthew G. Knepley #endif
86003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
87003ee160SMatthew G. Knepley }
88003ee160SMatthew G. Knepley 
89e4e5cec9SBarry Smith static PetscErrorCode  PetscRandomDestroy_Rander48(PetscRandom r)
90e4e5cec9SBarry Smith {
91e4e5cec9SBarry Smith   PetscFunctionBegin;
929566063dSJacob Faibussowitsch   PetscCall(PetscFree(r->data));
93e4e5cec9SBarry Smith   PetscFunctionReturn(0);
94e4e5cec9SBarry Smith }
95e4e5cec9SBarry Smith 
96003ee160SMatthew G. Knepley static struct _PetscRandomOps PetscRandomOps_Values = {
97267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(seed,PetscRandomSeed_Rander48),
98267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvalue,PetscRandomGetValue_Rander48),
99267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvaluereal,PetscRandomGetValueReal_Rander48),
100267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvalues,NULL),
101267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvaluesreal,NULL),
102267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(destroy,PetscRandomDestroy_Rander48),
103003ee160SMatthew G. Knepley };
104003ee160SMatthew G. Knepley 
105003ee160SMatthew G. Knepley /*MC
106b3bd51deSBarry Smith    PETSCRANDER48 - simple portable reimplementation of basic Unix drand48() random number generator that should generate the
107b3bd51deSBarry Smith         exact same random numbers on any system.
108003ee160SMatthew G. Knepley 
109003ee160SMatthew G. Knepley    Options Database Keys:
110*1179163eSBarry Smith . -random_type <rand,rand48,rander48,sprng> - select the random number generator at runtime
111003ee160SMatthew G. Knepley 
11295452b02SPatrick Sanan   Notes:
11395452b02SPatrick Sanan     This is the default random number generate provided by PetscRandomCreate() if you do not set a particular implementation.
114e4e5cec9SBarry Smith 
115e4e5cec9SBarry Smith   Each PetscRandom object created with this type has its own seed and its own history, so multiple PetscRandom objects of this type
116e4e5cec9SBarry Smith   will not interfer with random numbers generated by other objects. Each PETSc object of this type will produce the exact same set of
117e4e5cec9SBarry Smith   random numbers so if you wish different PetscObjects of this type set different seeds for each one after you create them with
118e4e5cec9SBarry Smith   PetscRandomSetSeed() followed by PetscRandomSeed().
119e4e5cec9SBarry Smith 
120003ee160SMatthew G. Knepley   Level: beginner
121003ee160SMatthew G. Knepley 
122*1179163eSBarry Smith .seealso: `PetscRandomCreate()`, `PetscRandomSetType()`, `PETSCRAND`, `PETSCRAND48`, `PETSCRANDER48`, `PETSCSPRNG`, `PetscRandomSetSeed()`,
123*1179163eSBarry Smith           `PetscRandomSeed()`, `PetscRandomSetFromOptions()`
124003ee160SMatthew G. Knepley M*/
125003ee160SMatthew G. Knepley 
126003ee160SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscRandomCreate_Rander48(PetscRandom r)
127003ee160SMatthew G. Knepley {
128e4e5cec9SBarry Smith   PetscRandom_Rander48 *r48;
129003ee160SMatthew G. Knepley 
130003ee160SMatthew G. Knepley   PetscFunctionBegin;
1319566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(r,&r48));
132e4e5cec9SBarry Smith   /* r48 does not need to be initialized because PetscRandomSeed() is always called before use and sets the needed values */
133e4e5cec9SBarry Smith   r->data = r48;
1349566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(r->ops, &PetscRandomOps_Values, sizeof(PetscRandomOps_Values)));
1359566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject) r, PETSCRANDER48));
136003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
137003ee160SMatthew G. Knepley }
138