xref: /petsc/src/sys/classes/random/impls/rander48/rander48.c (revision 9f0394f42870b9e0a92685bbca597cb20a1d83c8)
1003ee160SMatthew G. Knepley #include <../src/sys/classes/random/randomimpl.h>
2003ee160SMatthew G. Knepley 
3003ee160SMatthew 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. */
4003ee160SMatthew G. Knepley #define RANDER48_SEED_0 (0x330e)
5003ee160SMatthew G. Knepley #define RANDER48_SEED_1 (0xabcd)
6003ee160SMatthew G. Knepley #define RANDER48_SEED_2 (0x1234)
7003ee160SMatthew G. Knepley #define RANDER48_MULT_0 (0xe66d)
8003ee160SMatthew G. Knepley #define RANDER48_MULT_1 (0xdeec)
9003ee160SMatthew G. Knepley #define RANDER48_MULT_2 (0x0005)
10003ee160SMatthew G. Knepley #define RANDER48_ADD    (0x000b)
11003ee160SMatthew G. Knepley 
12003ee160SMatthew G. Knepley unsigned short _rander48_seed[3] = {
13003ee160SMatthew G. Knepley   RANDER48_SEED_0,
14003ee160SMatthew G. Knepley   RANDER48_SEED_1,
15003ee160SMatthew G. Knepley   RANDER48_SEED_2
16003ee160SMatthew G. Knepley };
17003ee160SMatthew G. Knepley unsigned short _rander48_mult[3] = {
18003ee160SMatthew G. Knepley   RANDER48_MULT_0,
19003ee160SMatthew G. Knepley   RANDER48_MULT_1,
20003ee160SMatthew G. Knepley   RANDER48_MULT_2
21003ee160SMatthew G. Knepley };
22003ee160SMatthew G. Knepley unsigned short _rander48_add = RANDER48_ADD;
23003ee160SMatthew G. Knepley 
24003ee160SMatthew G. Knepley void _dorander48(unsigned short xseed[3])
25003ee160SMatthew G. Knepley {
26003ee160SMatthew G. Knepley   unsigned long accu;
27003ee160SMatthew G. Knepley   unsigned short temp[2];
28003ee160SMatthew G. Knepley 
29003ee160SMatthew G. Knepley   accu     = (unsigned long) _rander48_mult[0] * (unsigned long) xseed[0] + (unsigned long)_rander48_add;
30003ee160SMatthew G. Knepley   temp[0]  = (unsigned short) accu;        /* lower 16 bits */
31003ee160SMatthew G. Knepley   accu   >>= sizeof(unsigned short) * 8;
32003ee160SMatthew G. Knepley   accu    += (unsigned long) _rander48_mult[0] * (unsigned long) xseed[1] + (unsigned long) _rander48_mult[1] * (unsigned long) xseed[0];
33003ee160SMatthew G. Knepley   temp[1]  = (unsigned short)accu;        /* middle 16 bits */
34003ee160SMatthew G. Knepley   accu   >>= sizeof(unsigned short) * 8;
35003ee160SMatthew G. Knepley   accu    += _rander48_mult[0] * xseed[2] + _rander48_mult[1] * xseed[1] + _rander48_mult[2] * xseed[0];
36003ee160SMatthew G. Knepley   xseed[0] = temp[0];
37003ee160SMatthew G. Knepley   xseed[1] = temp[1];
38003ee160SMatthew G. Knepley   xseed[2] = (unsigned short) accu;
39003ee160SMatthew G. Knepley }
40003ee160SMatthew G. Knepley 
41003ee160SMatthew G. Knepley double erander48(unsigned short xseed[3])
42003ee160SMatthew G. Knepley {
43003ee160SMatthew G. Knepley   _dorander48(xseed);
44003ee160SMatthew G. Knepley   return ldexp((double) xseed[0], -48) + ldexp((double) xseed[1], -32) + ldexp((double) xseed[2], -16);
45003ee160SMatthew G. Knepley }
46003ee160SMatthew G. Knepley 
47003ee160SMatthew G. Knepley double drander48() {
48003ee160SMatthew G. Knepley   return erander48(_rander48_seed);
49003ee160SMatthew G. Knepley }
50003ee160SMatthew G. Knepley 
51003ee160SMatthew G. Knepley void srander48(long seed) {
52003ee160SMatthew G. Knepley   _rander48_seed[0] = RANDER48_SEED_0;
53003ee160SMatthew G. Knepley   _rander48_seed[1] = (unsigned short) seed;
54003ee160SMatthew G. Knepley   _rander48_seed[2] = (unsigned short) (seed >> 16);
55003ee160SMatthew G. Knepley   _rander48_mult[0] = RANDER48_MULT_0;
56003ee160SMatthew G. Knepley   _rander48_mult[1] = RANDER48_MULT_1;
57003ee160SMatthew G. Knepley   _rander48_mult[2] = RANDER48_MULT_2;
58003ee160SMatthew G. Knepley   _rander48_add     = RANDER48_ADD;
59003ee160SMatthew G. Knepley }
60003ee160SMatthew G. Knepley 
61003ee160SMatthew G. Knepley #undef __FUNCT__
62003ee160SMatthew G. Knepley #define __FUNCT__ "PetscRandomSeed_Rander48"
63003ee160SMatthew G. Knepley PetscErrorCode  PetscRandomSeed_Rander48(PetscRandom r)
64003ee160SMatthew G. Knepley {
65003ee160SMatthew G. Knepley   PetscFunctionBegin;
66003ee160SMatthew G. Knepley   srander48(r->seed);
67003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
68003ee160SMatthew G. Knepley }
69003ee160SMatthew G. Knepley 
70003ee160SMatthew G. Knepley #undef __FUNCT__
71003ee160SMatthew G. Knepley #define __FUNCT__ "PetscRandomGetValue_Rander48"
72003ee160SMatthew G. Knepley PetscErrorCode  PetscRandomGetValue_Rander48(PetscRandom r, PetscScalar *val)
73003ee160SMatthew G. Knepley {
74003ee160SMatthew G. Knepley   PetscFunctionBegin;
75003ee160SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX)
76003ee160SMatthew G. Knepley   if (r->iset) {
77*9f0394f4SBarry Smith     *val = PetscRealPart(r->low) + PetscImaginaryPart(r->low) * PETSC_i;
78*9f0394f4SBarry Smith     if (PetscRealPart(r->width)) {
79*9f0394f4SBarry Smith       *val += PetscRealPart(r->width)* drander48();
80*9f0394f4SBarry Smith     }
81*9f0394f4SBarry Smith     if (PetscImaginaryPart(r->width)) {
82*9f0394f4SBarry Smith       *val += PetscImaginaryPart(r->width)* drander48() * PETSC_i;
83*9f0394f4SBarry Smith     }
84003ee160SMatthew G. Knepley   } else {
85*9f0394f4SBarry Smith     *val = drander48() +  drander48()*PETSC_i;
86003ee160SMatthew G. Knepley   }
87003ee160SMatthew G. Knepley #else
88003ee160SMatthew G. Knepley   if (r->iset) *val = r->width * drander48() + r->low;
89003ee160SMatthew G. Knepley   else         *val = drander48();
90003ee160SMatthew G. Knepley #endif
91003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
92003ee160SMatthew G. Knepley }
93003ee160SMatthew G. Knepley 
94003ee160SMatthew G. Knepley #undef __FUNCT__
95003ee160SMatthew G. Knepley #define __FUNCT__ "PetscRandomGetValueReal_Rander48"
96003ee160SMatthew G. Knepley PetscErrorCode  PetscRandomGetValueReal_Rander48(PetscRandom r, PetscReal *val)
97003ee160SMatthew G. Knepley {
98003ee160SMatthew G. Knepley   PetscFunctionBegin;
99003ee160SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX)
100003ee160SMatthew G. Knepley   if (r->iset) *val = PetscRealPart(r->width)*drander48() + PetscRealPart(r->low);
101003ee160SMatthew G. Knepley   else         *val = drander48();
102003ee160SMatthew G. Knepley #else
103003ee160SMatthew G. Knepley   if (r->iset) *val = r->width * drander48() + r->low;
104003ee160SMatthew G. Knepley   else         *val = drander48();
105003ee160SMatthew G. Knepley #endif
106003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
107003ee160SMatthew G. Knepley }
108003ee160SMatthew G. Knepley 
109003ee160SMatthew G. Knepley static struct _PetscRandomOps PetscRandomOps_Values = {
110003ee160SMatthew G. Knepley   /* 0 */
111003ee160SMatthew G. Knepley   PetscRandomSeed_Rander48,
112003ee160SMatthew G. Knepley   PetscRandomGetValue_Rander48,
113003ee160SMatthew G. Knepley   PetscRandomGetValueReal_Rander48,
114003ee160SMatthew G. Knepley   0,
115003ee160SMatthew G. Knepley   /* 5 */
116003ee160SMatthew G. Knepley   0
117003ee160SMatthew G. Knepley };
118003ee160SMatthew G. Knepley 
119003ee160SMatthew G. Knepley /*MC
120003ee160SMatthew G. Knepley    PETSCRANDER48 - simple reimplementation of basic Unix drand48() random number generator, because Microsoft
121003ee160SMatthew G. Knepley 
122003ee160SMatthew G. Knepley    Options Database Keys:
123003ee160SMatthew G. Knepley . -random_type <rand,rand48,rander48,sprng>
124003ee160SMatthew G. Knepley 
125003ee160SMatthew G. Knepley   Level: beginner
126003ee160SMatthew G. Knepley 
127003ee160SMatthew G. Knepley .seealso: RandomCreate(), RandomSetType(), PETSCRAND, PETSCRAND48, PETSCRANDER48, PETSCSPRNG
128003ee160SMatthew G. Knepley M*/
129003ee160SMatthew G. Knepley 
130003ee160SMatthew G. Knepley #undef __FUNCT__
131003ee160SMatthew G. Knepley #define __FUNCT__ "PetscRandomCreate_Rander48"
132003ee160SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscRandomCreate_Rander48(PetscRandom r)
133003ee160SMatthew G. Knepley {
134003ee160SMatthew G. Knepley   PetscErrorCode ierr;
135003ee160SMatthew G. Knepley 
136003ee160SMatthew G. Knepley   PetscFunctionBegin;
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