xref: /petsc/src/sys/classes/random/impls/rander48/rander48.c (revision 267267bdcbfbae225216e8078da17f7ca9d5f149)
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 
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 = {
99*267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(seed,PetscRandomSeed_Rander48),
100*267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvalue,PetscRandomGetValue_Rander48),
101*267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvaluereal,PetscRandomGetValueReal_Rander48),
102*267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvalues,NULL),
103*267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(getvaluesreal,NULL),
104*267267bdSJacob Faibussowitsch   PetscDesignatedInitializer(destroy,PetscRandomDestroy_Rander48),
105003ee160SMatthew G. Knepley };
106003ee160SMatthew G. Knepley 
107003ee160SMatthew G. Knepley /*MC
108b3bd51deSBarry Smith    PETSCRANDER48 - simple portable reimplementation of basic Unix drand48() random number generator that should generate the
109b3bd51deSBarry Smith         exact same random numbers on any system.
110003ee160SMatthew G. Knepley 
111003ee160SMatthew G. Knepley    Options Database Keys:
112003ee160SMatthew G. Knepley . -random_type <rand,rand48,rander48,sprng>
113003ee160SMatthew G. Knepley 
11495452b02SPatrick Sanan   Notes:
11595452b02SPatrick Sanan     This is the default random number generate provided by PetscRandomCreate() if you do not set a particular implementation.
116e4e5cec9SBarry Smith 
117e4e5cec9SBarry Smith   Each PetscRandom object created with this type has its own seed and its own history, so multiple PetscRandom objects of this type
118e4e5cec9SBarry Smith   will not interfer with random numbers generated by other objects. Each PETSc object of this type will produce the exact same set of
119e4e5cec9SBarry Smith   random numbers so if you wish different PetscObjects of this type set different seeds for each one after you create them with
120e4e5cec9SBarry Smith   PetscRandomSetSeed() followed by PetscRandomSeed().
121e4e5cec9SBarry Smith 
122003ee160SMatthew G. Knepley   Level: beginner
123003ee160SMatthew G. Knepley 
124808ba619SStefano Zampini .seealso: PetscRandomCreate(), PetscRandomSetType(), PETSCRAND, PETSCRAND48, PETSCRANDER48, PETSCSPRNG, PetscRandomSetSeed(), PetscRandomSeed()
125003ee160SMatthew G. Knepley M*/
126003ee160SMatthew G. Knepley 
127003ee160SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscRandomCreate_Rander48(PetscRandom r)
128003ee160SMatthew G. Knepley {
129003ee160SMatthew G. Knepley   PetscErrorCode       ierr;
130e4e5cec9SBarry Smith   PetscRandom_Rander48 *r48;
131003ee160SMatthew G. Knepley 
132003ee160SMatthew G. Knepley   PetscFunctionBegin;
133e4e5cec9SBarry Smith   ierr = PetscNewLog(r,&r48);CHKERRQ(ierr);
134e4e5cec9SBarry Smith   /* r48 does not need to be initialized because PetscRandomSeed() is always called before use and sets the needed values */
135e4e5cec9SBarry Smith   r->data = r48;
136003ee160SMatthew G. Knepley   ierr = PetscMemcpy(r->ops, &PetscRandomOps_Values, sizeof(PetscRandomOps_Values));CHKERRQ(ierr);
137003ee160SMatthew G. Knepley   ierr = PetscObjectChangeTypeName((PetscObject) r, PETSCRANDER48);CHKERRQ(ierr);
138003ee160SMatthew G. Knepley   PetscFunctionReturn(0);
139003ee160SMatthew G. Knepley }
140