xref: /petsc/src/sys/classes/random/impls/rander48/rander48.c (revision 95452b02e12c0ee11232c7ff2b24b568a8e07e43)
1003ee160SMatthew G. Knepley #include <../src/sys/classes/random/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   PetscErrorCode ierr;
92e4e5cec9SBarry Smith 
93e4e5cec9SBarry Smith   PetscFunctionBegin;
94e4e5cec9SBarry Smith   ierr = PetscFree(r->data);CHKERRQ(ierr);
95e4e5cec9SBarry Smith   PetscFunctionReturn(0);
96e4e5cec9SBarry Smith }
97e4e5cec9SBarry Smith 
98003ee160SMatthew G. Knepley static struct _PetscRandomOps PetscRandomOps_Values = {
99003ee160SMatthew G. Knepley   /* 0 */
100003ee160SMatthew G. Knepley   PetscRandomSeed_Rander48,
101003ee160SMatthew G. Knepley   PetscRandomGetValue_Rander48,
102003ee160SMatthew G. Knepley   PetscRandomGetValueReal_Rander48,
103e4e5cec9SBarry Smith   PetscRandomDestroy_Rander48,
104003ee160SMatthew G. Knepley   /* 5 */
105003ee160SMatthew G. Knepley   0
106003ee160SMatthew G. Knepley };
107003ee160SMatthew G. Knepley 
108003ee160SMatthew G. Knepley /*MC
109b3bd51deSBarry Smith    PETSCRANDER48 - simple portable reimplementation of basic Unix drand48() random number generator that should generate the
110b3bd51deSBarry Smith         exact same random numbers on any system.
111003ee160SMatthew G. Knepley 
112003ee160SMatthew G. Knepley    Options Database Keys:
113003ee160SMatthew G. Knepley . -random_type <rand,rand48,rander48,sprng>
114003ee160SMatthew G. Knepley 
115*95452b02SPatrick Sanan   Notes:
116*95452b02SPatrick Sanan     This is the default random number generate provided by PetscRandomCreate() if you do not set a particular implementation.
117e4e5cec9SBarry Smith 
118e4e5cec9SBarry Smith   Each PetscRandom object created with this type has its own seed and its own history, so multiple PetscRandom objects of this type
119e4e5cec9SBarry Smith   will not interfer with random numbers generated by other objects. Each PETSc object of this type will produce the exact same set of
120e4e5cec9SBarry Smith   random numbers so if you wish different PetscObjects of this type set different seeds for each one after you create them with
121e4e5cec9SBarry Smith   PetscRandomSetSeed() followed by PetscRandomSeed().
122e4e5cec9SBarry Smith 
123003ee160SMatthew G. Knepley   Level: beginner
124003ee160SMatthew G. Knepley 
125e4e5cec9SBarry Smith .seealso: RandomCreate(), RandomSetType(), PETSCRAND, PETSCRAND48, PETSCRANDER48, PETSCSPRNG, PetscRandomSetSeed(), PetscRandomSeed()
126003ee160SMatthew G. Knepley M*/
127003ee160SMatthew G. Knepley 
128003ee160SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscRandomCreate_Rander48(PetscRandom r)
129003ee160SMatthew G. Knepley {
130003ee160SMatthew G. Knepley   PetscErrorCode       ierr;
131e4e5cec9SBarry Smith   PetscRandom_Rander48 *r48;
132003ee160SMatthew G. Knepley 
133003ee160SMatthew G. Knepley   PetscFunctionBegin;
134e4e5cec9SBarry Smith   ierr = PetscNewLog(r,&r48);CHKERRQ(ierr);
135e4e5cec9SBarry Smith   /* r48 does not need to be initialized because PetscRandomSeed() is always called before use and sets the needed values */
136e4e5cec9SBarry Smith   r->data = r48;
137003ee160SMatthew G. Knepley   ierr = PetscMemcpy(r->ops, &PetscRandomOps_Values, sizeof(PetscRandomOps_Values));CHKERRQ(ierr);
138003ee160SMatthew G. Knepley   ierr = PetscObjectChangeTypeName((PetscObject) r, PETSCRANDER48);CHKERRQ(ierr);
139003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
140003ee160SMatthew G. Knepley }
141