xref: /petsc/src/sys/classes/random/impls/rander48/rander48.c (revision 003ee160c06d6753aad01d831b1272bd95bdcd1e)
1*003ee160SMatthew G. Knepley #include <../src/sys/classes/random/randomimpl.h>
2*003ee160SMatthew G. Knepley 
3*003ee160SMatthew G. Knepley /* This shit is even more random than drand48(). It is random enough to run on Windows. Fuck you Microsoft, and your utter failure to implement POSIX. */
4*003ee160SMatthew G. Knepley #define RANDER48_SEED_0 (0x330e)
5*003ee160SMatthew G. Knepley #define RANDER48_SEED_1 (0xabcd)
6*003ee160SMatthew G. Knepley #define RANDER48_SEED_2 (0x1234)
7*003ee160SMatthew G. Knepley #define RANDER48_MULT_0 (0xe66d)
8*003ee160SMatthew G. Knepley #define RANDER48_MULT_1 (0xdeec)
9*003ee160SMatthew G. Knepley #define RANDER48_MULT_2 (0x0005)
10*003ee160SMatthew G. Knepley #define RANDER48_ADD    (0x000b)
11*003ee160SMatthew G. Knepley 
12*003ee160SMatthew G. Knepley unsigned short _rander48_seed[3] = {
13*003ee160SMatthew G. Knepley   RANDER48_SEED_0,
14*003ee160SMatthew G. Knepley   RANDER48_SEED_1,
15*003ee160SMatthew G. Knepley   RANDER48_SEED_2
16*003ee160SMatthew G. Knepley };
17*003ee160SMatthew G. Knepley unsigned short _rander48_mult[3] = {
18*003ee160SMatthew G. Knepley   RANDER48_MULT_0,
19*003ee160SMatthew G. Knepley   RANDER48_MULT_1,
20*003ee160SMatthew G. Knepley   RANDER48_MULT_2
21*003ee160SMatthew G. Knepley };
22*003ee160SMatthew G. Knepley unsigned short _rander48_add = RANDER48_ADD;
23*003ee160SMatthew G. Knepley 
24*003ee160SMatthew G. Knepley void _dorander48(unsigned short xseed[3])
25*003ee160SMatthew G. Knepley {
26*003ee160SMatthew G. Knepley   unsigned long accu;
27*003ee160SMatthew G. Knepley   unsigned short temp[2];
28*003ee160SMatthew G. Knepley 
29*003ee160SMatthew G. Knepley   accu     = (unsigned long) _rander48_mult[0] * (unsigned long) xseed[0] + (unsigned long)_rander48_add;
30*003ee160SMatthew G. Knepley   temp[0]  = (unsigned short) accu;        /* lower 16 bits */
31*003ee160SMatthew G. Knepley   accu   >>= sizeof(unsigned short) * 8;
32*003ee160SMatthew G. Knepley   accu    += (unsigned long) _rander48_mult[0] * (unsigned long) xseed[1] + (unsigned long) _rander48_mult[1] * (unsigned long) xseed[0];
33*003ee160SMatthew G. Knepley   temp[1]  = (unsigned short)accu;        /* middle 16 bits */
34*003ee160SMatthew G. Knepley   accu   >>= sizeof(unsigned short) * 8;
35*003ee160SMatthew G. Knepley   accu    += _rander48_mult[0] * xseed[2] + _rander48_mult[1] * xseed[1] + _rander48_mult[2] * xseed[0];
36*003ee160SMatthew G. Knepley   xseed[0] = temp[0];
37*003ee160SMatthew G. Knepley   xseed[1] = temp[1];
38*003ee160SMatthew G. Knepley   xseed[2] = (unsigned short) accu;
39*003ee160SMatthew G. Knepley }
40*003ee160SMatthew G. Knepley 
41*003ee160SMatthew G. Knepley double erander48(unsigned short xseed[3])
42*003ee160SMatthew G. Knepley {
43*003ee160SMatthew G. Knepley   _dorander48(xseed);
44*003ee160SMatthew G. Knepley   return ldexp((double) xseed[0], -48) + ldexp((double) xseed[1], -32) + ldexp((double) xseed[2], -16);
45*003ee160SMatthew G. Knepley }
46*003ee160SMatthew G. Knepley 
47*003ee160SMatthew G. Knepley double drander48() {
48*003ee160SMatthew G. Knepley   return erander48(_rander48_seed);
49*003ee160SMatthew G. Knepley }
50*003ee160SMatthew G. Knepley 
51*003ee160SMatthew G. Knepley void srander48(long seed) {
52*003ee160SMatthew G. Knepley   _rander48_seed[0] = RANDER48_SEED_0;
53*003ee160SMatthew G. Knepley   _rander48_seed[1] = (unsigned short) seed;
54*003ee160SMatthew G. Knepley   _rander48_seed[2] = (unsigned short) (seed >> 16);
55*003ee160SMatthew G. Knepley   _rander48_mult[0] = RANDER48_MULT_0;
56*003ee160SMatthew G. Knepley   _rander48_mult[1] = RANDER48_MULT_1;
57*003ee160SMatthew G. Knepley   _rander48_mult[2] = RANDER48_MULT_2;
58*003ee160SMatthew G. Knepley   _rander48_add     = RANDER48_ADD;
59*003ee160SMatthew G. Knepley }
60*003ee160SMatthew G. Knepley 
61*003ee160SMatthew G. Knepley #undef __FUNCT__
62*003ee160SMatthew G. Knepley #define __FUNCT__ "PetscRandomSeed_Rander48"
63*003ee160SMatthew G. Knepley PetscErrorCode  PetscRandomSeed_Rander48(PetscRandom r)
64*003ee160SMatthew G. Knepley {
65*003ee160SMatthew G. Knepley   PetscFunctionBegin;
66*003ee160SMatthew G. Knepley   srander48(r->seed);
67*003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
68*003ee160SMatthew G. Knepley }
69*003ee160SMatthew G. Knepley 
70*003ee160SMatthew G. Knepley #undef __FUNCT__
71*003ee160SMatthew G. Knepley #define __FUNCT__ "PetscRandomGetValue_Rander48"
72*003ee160SMatthew G. Knepley PetscErrorCode  PetscRandomGetValue_Rander48(PetscRandom r, PetscScalar *val)
73*003ee160SMatthew G. Knepley {
74*003ee160SMatthew G. Knepley   PetscFunctionBegin;
75*003ee160SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX)
76*003ee160SMatthew G. Knepley   if (r->iset) {
77*003ee160SMatthew G. Knepley     *val = PetscRealPart(r->width)*(PetscReal) drander48() + PetscRealPart(r->low) + (PetscImaginaryPart(r->width)*(PetscReal) drander48() + PetscImaginaryPart(r->low)) * PETSC_i;
78*003ee160SMatthew G. Knepley   } else {
79*003ee160SMatthew G. Knepley     *val = (PetscReal) drander48() + ((PetscReal) drander48())*PETSC_i;
80*003ee160SMatthew G. Knepley   }
81*003ee160SMatthew G. Knepley #else
82*003ee160SMatthew G. Knepley   if (r->iset) *val = r->width * drander48() + r->low;
83*003ee160SMatthew G. Knepley   else         *val = drander48();
84*003ee160SMatthew G. Knepley #endif
85*003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
86*003ee160SMatthew G. Knepley }
87*003ee160SMatthew G. Knepley 
88*003ee160SMatthew G. Knepley #undef __FUNCT__
89*003ee160SMatthew G. Knepley #define __FUNCT__ "PetscRandomGetValueReal_Rander48"
90*003ee160SMatthew G. Knepley PetscErrorCode  PetscRandomGetValueReal_Rander48(PetscRandom r, PetscReal *val)
91*003ee160SMatthew G. Knepley {
92*003ee160SMatthew G. Knepley   PetscFunctionBegin;
93*003ee160SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX)
94*003ee160SMatthew G. Knepley   if (r->iset) *val = PetscRealPart(r->width)*drander48() + PetscRealPart(r->low);
95*003ee160SMatthew G. Knepley   else         *val = drander48();
96*003ee160SMatthew G. Knepley #else
97*003ee160SMatthew G. Knepley   if (r->iset) *val = r->width * drander48() + r->low;
98*003ee160SMatthew G. Knepley   else         *val = drander48();
99*003ee160SMatthew G. Knepley #endif
100*003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
101*003ee160SMatthew G. Knepley }
102*003ee160SMatthew G. Knepley 
103*003ee160SMatthew G. Knepley static struct _PetscRandomOps PetscRandomOps_Values = {
104*003ee160SMatthew G. Knepley   /* 0 */
105*003ee160SMatthew G. Knepley   PetscRandomSeed_Rander48,
106*003ee160SMatthew G. Knepley   PetscRandomGetValue_Rander48,
107*003ee160SMatthew G. Knepley   PetscRandomGetValueReal_Rander48,
108*003ee160SMatthew G. Knepley   0,
109*003ee160SMatthew G. Knepley   /* 5 */
110*003ee160SMatthew G. Knepley   0
111*003ee160SMatthew G. Knepley };
112*003ee160SMatthew G. Knepley 
113*003ee160SMatthew G. Knepley /*MC
114*003ee160SMatthew G. Knepley    PETSCRANDER48 - simple reimplementation of basic Unix drand48() random number generator, because Microsoft
115*003ee160SMatthew G. Knepley 
116*003ee160SMatthew G. Knepley    Options Database Keys:
117*003ee160SMatthew G. Knepley . -random_type <rand,rand48,rander48,sprng>
118*003ee160SMatthew G. Knepley 
119*003ee160SMatthew G. Knepley   Level: beginner
120*003ee160SMatthew G. Knepley 
121*003ee160SMatthew G. Knepley .seealso: RandomCreate(), RandomSetType(), PETSCRAND, PETSCRAND48, PETSCRANDER48, PETSCSPRNG
122*003ee160SMatthew G. Knepley M*/
123*003ee160SMatthew G. Knepley 
124*003ee160SMatthew G. Knepley #undef __FUNCT__
125*003ee160SMatthew G. Knepley #define __FUNCT__ "PetscRandomCreate_Rander48"
126*003ee160SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscRandomCreate_Rander48(PetscRandom r)
127*003ee160SMatthew G. Knepley {
128*003ee160SMatthew G. Knepley   PetscErrorCode ierr;
129*003ee160SMatthew G. Knepley 
130*003ee160SMatthew G. Knepley   PetscFunctionBegin;
131*003ee160SMatthew G. Knepley   ierr = PetscMemcpy(r->ops, &PetscRandomOps_Values, sizeof(PetscRandomOps_Values));CHKERRQ(ierr);
132*003ee160SMatthew G. Knepley   ierr = PetscObjectChangeTypeName((PetscObject) r, PETSCRANDER48);CHKERRQ(ierr);
133*003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
134*003ee160SMatthew G. Knepley }
135