xref: /petsc/src/sys/classes/random/impls/rander48/rander48.c (revision e4e5cec90ac966f0095f59da87f5333fd41aaed0)
1003ee160SMatthew G. Knepley #include <../src/sys/classes/random/randomimpl.h>
2003ee160SMatthew G. Knepley 
3*e4e5cec9SBarry Smith typedef struct {
4*e4e5cec9SBarry Smith   unsigned short seed[3];
5*e4e5cec9SBarry Smith   unsigned short mult[3];
6*e4e5cec9SBarry Smith   unsigned short add;
7*e4e5cec9SBarry Smith } PetscRandom_Rander48;
8*e4e5cec9SBarry 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 
17*e4e5cec9SBarry 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 
22*e4e5cec9SBarry 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;
25*e4e5cec9SBarry 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;
28*e4e5cec9SBarry Smith   accu    += r48->mult[0] * r48->seed[2] + r48->mult[1] * r48->seed[1] + r48->mult[2] * r48->seed[0];
29*e4e5cec9SBarry Smith   r48->seed[0] = temp[0];
30*e4e5cec9SBarry Smith   r48->seed[1] = temp[1];
31*e4e5cec9SBarry Smith   r48->seed[2] = (unsigned short) accu;
32*e4e5cec9SBarry 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 
35003ee160SMatthew G. Knepley #undef __FUNCT__
36003ee160SMatthew G. Knepley #define __FUNCT__ "PetscRandomSeed_Rander48"
37*e4e5cec9SBarry Smith static PetscErrorCode  PetscRandomSeed_Rander48(PetscRandom r)
38003ee160SMatthew G. Knepley {
39*e4e5cec9SBarry Smith   PetscRandom_Rander48 *r48 = (PetscRandom_Rander48*)r->data;
40*e4e5cec9SBarry Smith 
41003ee160SMatthew G. Knepley   PetscFunctionBegin;
42*e4e5cec9SBarry Smith   r48->seed[0] = RANDER48_SEED_0;
43*e4e5cec9SBarry Smith   r48->seed[1] = (unsigned short) r->seed;
44*e4e5cec9SBarry Smith   r48->seed[2] = (unsigned short) (r->seed >> 16);
45*e4e5cec9SBarry Smith   r48->mult[0] = RANDER48_MULT_0;
46*e4e5cec9SBarry Smith   r48->mult[1] = RANDER48_MULT_1;
47*e4e5cec9SBarry Smith   r48->mult[2] = RANDER48_MULT_2;
48*e4e5cec9SBarry Smith   r48->add     = RANDER48_ADD;
49003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
50003ee160SMatthew G. Knepley }
51003ee160SMatthew G. Knepley 
52003ee160SMatthew G. Knepley #undef __FUNCT__
53003ee160SMatthew G. Knepley #define __FUNCT__ "PetscRandomGetValue_Rander48"
54*e4e5cec9SBarry Smith static PetscErrorCode  PetscRandomGetValue_Rander48(PetscRandom r, PetscScalar *val)
55003ee160SMatthew G. Knepley {
56*e4e5cec9SBarry Smith   PetscRandom_Rander48 *r48 = (PetscRandom_Rander48*)r->data;
57*e4e5cec9SBarry Smith 
58003ee160SMatthew G. Knepley   PetscFunctionBegin;
59003ee160SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX)
60003ee160SMatthew G. Knepley   if (r->iset) {
619f0394f4SBarry Smith     *val = PetscRealPart(r->low) + PetscImaginaryPart(r->low) * PETSC_i;
629f0394f4SBarry Smith     if (PetscRealPart(r->width)) {
63*e4e5cec9SBarry Smith       *val += PetscRealPart(r->width)* _dorander48(r48);
649f0394f4SBarry Smith     }
659f0394f4SBarry Smith     if (PetscImaginaryPart(r->width)) {
66*e4e5cec9SBarry Smith       *val += PetscImaginaryPart(r->width)* _dorander48(r48) * PETSC_i;
679f0394f4SBarry Smith     }
68003ee160SMatthew G. Knepley   } else {
69*e4e5cec9SBarry Smith     *val = _dorander48(r48) +  _dorander48(r48)*PETSC_i;
70003ee160SMatthew G. Knepley   }
71003ee160SMatthew G. Knepley #else
72*e4e5cec9SBarry Smith   if (r->iset) *val = r->width * _dorander48(r48) + r->low;
73*e4e5cec9SBarry Smith   else         *val = _dorander48(r48);
74003ee160SMatthew G. Knepley #endif
75003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
76003ee160SMatthew G. Knepley }
77003ee160SMatthew G. Knepley 
78003ee160SMatthew G. Knepley #undef __FUNCT__
79003ee160SMatthew G. Knepley #define __FUNCT__ "PetscRandomGetValueReal_Rander48"
80*e4e5cec9SBarry Smith static PetscErrorCode  PetscRandomGetValueReal_Rander48(PetscRandom r, PetscReal *val)
81003ee160SMatthew G. Knepley {
82*e4e5cec9SBarry Smith   PetscRandom_Rander48 *r48 = (PetscRandom_Rander48*)r->data;
83*e4e5cec9SBarry Smith 
84003ee160SMatthew G. Knepley   PetscFunctionBegin;
85003ee160SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX)
86*e4e5cec9SBarry Smith   if (r->iset) *val = PetscRealPart(r->width)*_dorander48(r48) + PetscRealPart(r->low);
87*e4e5cec9SBarry Smith   else         *val = _dorander48(r48);
88003ee160SMatthew G. Knepley #else
89*e4e5cec9SBarry Smith   if (r->iset) *val = r->width * _dorander48(r48) + r->low;
90*e4e5cec9SBarry Smith   else         *val = _dorander48(r48);
91003ee160SMatthew G. Knepley #endif
92003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
93003ee160SMatthew G. Knepley }
94003ee160SMatthew G. Knepley 
95*e4e5cec9SBarry Smith #undef __FUNCT__
96*e4e5cec9SBarry Smith #define __FUNCT__ "PetscRandomDestroy_Rander48"
97*e4e5cec9SBarry Smith static PetscErrorCode  PetscRandomDestroy_Rander48(PetscRandom r)
98*e4e5cec9SBarry Smith {
99*e4e5cec9SBarry Smith   PetscErrorCode ierr;
100*e4e5cec9SBarry Smith 
101*e4e5cec9SBarry Smith   PetscFunctionBegin;
102*e4e5cec9SBarry Smith   ierr = PetscFree(r->data);CHKERRQ(ierr);
103*e4e5cec9SBarry Smith   PetscFunctionReturn(0);
104*e4e5cec9SBarry Smith }
105*e4e5cec9SBarry Smith 
106003ee160SMatthew G. Knepley static struct _PetscRandomOps PetscRandomOps_Values = {
107003ee160SMatthew G. Knepley   /* 0 */
108003ee160SMatthew G. Knepley   PetscRandomSeed_Rander48,
109003ee160SMatthew G. Knepley   PetscRandomGetValue_Rander48,
110003ee160SMatthew G. Knepley   PetscRandomGetValueReal_Rander48,
111*e4e5cec9SBarry Smith   PetscRandomDestroy_Rander48,
112003ee160SMatthew G. Knepley   /* 5 */
113003ee160SMatthew G. Knepley   0
114003ee160SMatthew G. Knepley };
115003ee160SMatthew G. Knepley 
116003ee160SMatthew G. Knepley /*MC
117b3bd51deSBarry Smith    PETSCRANDER48 - simple portable reimplementation of basic Unix drand48() random number generator that should generate the
118b3bd51deSBarry Smith         exact same random numbers on any system.
119003ee160SMatthew G. Knepley 
120003ee160SMatthew G. Knepley    Options Database Keys:
121003ee160SMatthew G. Knepley . -random_type <rand,rand48,rander48,sprng>
122003ee160SMatthew G. Knepley 
123*e4e5cec9SBarry Smith   Notes: This is the default random number generate provided by PetscRandomCreate() if you do not set a particular implementation.
124*e4e5cec9SBarry Smith 
125*e4e5cec9SBarry Smith   Each PetscRandom object created with this type has its own seed and its own history, so multiple PetscRandom objects of this type
126*e4e5cec9SBarry Smith   will not interfer with random numbers generated by other objects. Each PETSc object of this type will produce the exact same set of
127*e4e5cec9SBarry Smith   random numbers so if you wish different PetscObjects of this type set different seeds for each one after you create them with
128*e4e5cec9SBarry Smith   PetscRandomSetSeed() followed by PetscRandomSeed().
129*e4e5cec9SBarry Smith 
130003ee160SMatthew G. Knepley   Level: beginner
131003ee160SMatthew G. Knepley 
132*e4e5cec9SBarry Smith .seealso: RandomCreate(), RandomSetType(), PETSCRAND, PETSCRAND48, PETSCRANDER48, PETSCSPRNG, PetscRandomSetSeed(), PetscRandomSeed()
133003ee160SMatthew G. Knepley M*/
134003ee160SMatthew G. Knepley 
135003ee160SMatthew G. Knepley #undef __FUNCT__
136003ee160SMatthew G. Knepley #define __FUNCT__ "PetscRandomCreate_Rander48"
137003ee160SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscRandomCreate_Rander48(PetscRandom r)
138003ee160SMatthew G. Knepley {
139003ee160SMatthew G. Knepley   PetscErrorCode       ierr;
140*e4e5cec9SBarry Smith   PetscRandom_Rander48 *r48;
141003ee160SMatthew G. Knepley 
142003ee160SMatthew G. Knepley   PetscFunctionBegin;
143*e4e5cec9SBarry Smith   ierr = PetscNewLog(r,&r48);CHKERRQ(ierr);
144*e4e5cec9SBarry Smith   /* r48 does not need to be initialized because PetscRandomSeed() is always called before use and sets the needed values */
145*e4e5cec9SBarry Smith   r->data = r48;
146003ee160SMatthew G. Knepley   ierr = PetscMemcpy(r->ops, &PetscRandomOps_Values, sizeof(PetscRandomOps_Values));CHKERRQ(ierr);
147003ee160SMatthew G. Knepley   ierr = PetscObjectChangeTypeName((PetscObject) r, PETSCRANDER48);CHKERRQ(ierr);
148003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
149003ee160SMatthew G. Knepley }
150