xref: /petsc/src/sys/classes/random/impls/rander48/rander48.c (revision d5b43468fb8780a8feea140ccd6fa3e6a50411cc)
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 
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;
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 
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;
47003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
48003ee160SMatthew G. Knepley }
49003ee160SMatthew G. Knepley 
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
67003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
68003ee160SMatthew G. Knepley }
69003ee160SMatthew G. Knepley 
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
82003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
83003ee160SMatthew G. Knepley }
84003ee160SMatthew G. Knepley 
85d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscRandomDestroy_Rander48(PetscRandom r)
86d71ae5a4SJacob Faibussowitsch {
87e4e5cec9SBarry Smith   PetscFunctionBegin;
889566063dSJacob Faibussowitsch   PetscCall(PetscFree(r->data));
89e4e5cec9SBarry Smith   PetscFunctionReturn(0);
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),
99003ee160SMatthew G. Knepley };
100003ee160SMatthew G. Knepley 
101003ee160SMatthew G. Knepley /*MC
102b3bd51deSBarry Smith    PETSCRANDER48 - simple portable reimplementation of basic Unix drand48() random number generator that should generate the
103b3bd51deSBarry Smith         exact same random numbers on any system.
104003ee160SMatthew G. Knepley 
105003ee160SMatthew G. Knepley    Options Database Keys:
1061179163eSBarry Smith . -random_type <rand,rand48,rander48,sprng> - select the random number generator at runtime
107003ee160SMatthew G. Knepley 
10895452b02SPatrick Sanan   Notes:
109811af0c4SBarry Smith     This is the default random number generate provided by `PetscRandomCreate()` if you do not set a particular implementation.
110e4e5cec9SBarry Smith 
111811af0c4SBarry Smith   Each `PetscRandom` object created with this type has its own seed and its own history, so multiple `PetscRandom` objects of this type
112*d5b43468SJose 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
113811af0c4SBarry Smith   random numbers so if you wish different `PetscRandom` objects of this type set different seeds for each one after you create them with
114811af0c4SBarry Smith   `PetscRandomSetSeed()` followed by `PetscRandomSeed()`.
115e4e5cec9SBarry Smith 
116003ee160SMatthew G. Knepley   Level: beginner
117003ee160SMatthew G. Knepley 
1181179163eSBarry Smith .seealso: `PetscRandomCreate()`, `PetscRandomSetType()`, `PETSCRAND`, `PETSCRAND48`, `PETSCRANDER48`, `PETSCSPRNG`, `PetscRandomSetSeed()`,
1191179163eSBarry Smith           `PetscRandomSeed()`, `PetscRandomSetFromOptions()`
120003ee160SMatthew G. Knepley M*/
121003ee160SMatthew G. Knepley 
122d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscRandomCreate_Rander48(PetscRandom r)
123d71ae5a4SJacob Faibussowitsch {
124e4e5cec9SBarry Smith   PetscRandom_Rander48 *r48;
125003ee160SMatthew G. Knepley 
126003ee160SMatthew G. Knepley   PetscFunctionBegin;
1274dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&r48));
128e4e5cec9SBarry Smith   /* r48 does not need to be initialized because PetscRandomSeed() is always called before use and sets the needed values */
129e4e5cec9SBarry Smith   r->data = r48;
1309566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(r->ops, &PetscRandomOps_Values, sizeof(PetscRandomOps_Values)));
1319566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)r, PETSCRANDER48));
132003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
133003ee160SMatthew G. Knepley }
134