Actual source code: rander48.c
1: #include <petsc/private/randomimpl.h>
3: typedef struct {
4: unsigned short seed[3];
5: unsigned short mult[3];
6: unsigned short add;
7: } PetscRandom_Rander48;
9: #define RANDER48_SEED_0 (0x330e)
10: #define RANDER48_SEED_1 (0xabcd)
11: #define RANDER48_SEED_2 (0x1234)
12: #define RANDER48_MULT_0 (0xe66d)
13: #define RANDER48_MULT_1 (0xdeec)
14: #define RANDER48_MULT_2 (0x0005)
15: #define RANDER48_ADD (0x000b)
17: static double _dorander48(PetscRandom_Rander48 *r48)
18: {
19: unsigned long accu;
20: unsigned short temp[2];
22: accu = (unsigned long)r48->mult[0] * (unsigned long)r48->seed[0] + (unsigned long)r48->add;
23: temp[0] = (unsigned short)accu; /* lower 16 bits */
24: accu >>= sizeof(unsigned short) * 8;
25: accu += (unsigned long)r48->mult[0] * (unsigned long)r48->seed[1] + (unsigned long)r48->mult[1] * (unsigned long)r48->seed[0];
26: temp[1] = (unsigned short)accu; /* middle 16 bits */
27: accu >>= sizeof(unsigned short) * 8;
28: accu += (unsigned long)r48->mult[0] * r48->seed[2] + (unsigned long)r48->mult[1] * r48->seed[1] + (unsigned long)r48->mult[2] * r48->seed[0];
29: r48->seed[0] = temp[0];
30: r48->seed[1] = temp[1];
31: r48->seed[2] = (unsigned short)accu;
32: return ldexp((double)r48->seed[0], -48) + ldexp((double)r48->seed[1], -32) + ldexp((double)r48->seed[2], -16);
33: }
35: static PetscErrorCode PetscRandomSeed_Rander48(PetscRandom r)
36: {
37: PetscRandom_Rander48 *r48 = (PetscRandom_Rander48 *)r->data;
39: PetscFunctionBegin;
40: r48->seed[0] = RANDER48_SEED_0;
41: r48->seed[1] = (unsigned short)r->seed;
42: r48->seed[2] = (unsigned short)(r->seed >> 16);
43: r48->mult[0] = RANDER48_MULT_0;
44: r48->mult[1] = RANDER48_MULT_1;
45: r48->mult[2] = RANDER48_MULT_2;
46: r48->add = RANDER48_ADD;
47: PetscFunctionReturn(PETSC_SUCCESS);
48: }
50: static PetscErrorCode PetscRandomGetValue_Rander48(PetscRandom r, PetscScalar *val)
51: {
52: PetscRandom_Rander48 *r48 = (PetscRandom_Rander48 *)r->data;
54: PetscFunctionBegin;
55: #if defined(PETSC_USE_COMPLEX)
56: if (r->iset) {
57: *val = PetscRealPart(r->low) + PetscImaginaryPart(r->low) * PETSC_i;
58: if (PetscRealPart(r->width)) *val += PetscRealPart(r->width) * _dorander48(r48);
59: if (PetscImaginaryPart(r->width)) *val += PetscImaginaryPart(r->width) * _dorander48(r48) * PETSC_i;
60: } else {
61: *val = _dorander48(r48) + _dorander48(r48) * PETSC_i;
62: }
63: #else
64: if (r->iset) *val = r->width * _dorander48(r48) + r->low;
65: else *val = _dorander48(r48);
66: #endif
67: PetscFunctionReturn(PETSC_SUCCESS);
68: }
70: static PetscErrorCode PetscRandomGetValueReal_Rander48(PetscRandom r, PetscReal *val)
71: {
72: PetscRandom_Rander48 *r48 = (PetscRandom_Rander48 *)r->data;
74: PetscFunctionBegin;
75: #if defined(PETSC_USE_COMPLEX)
76: if (r->iset) *val = PetscRealPart(r->width) * _dorander48(r48) + PetscRealPart(r->low);
77: else *val = _dorander48(r48);
78: #else
79: if (r->iset) *val = r->width * _dorander48(r48) + r->low;
80: else *val = _dorander48(r48);
81: #endif
82: PetscFunctionReturn(PETSC_SUCCESS);
83: }
85: static PetscErrorCode PetscRandomDestroy_Rander48(PetscRandom r)
86: {
87: PetscFunctionBegin;
88: PetscCall(PetscFree(r->data));
89: PetscFunctionReturn(PETSC_SUCCESS);
90: }
92: static struct _PetscRandomOps PetscRandomOps_Values = {
93: PetscDesignatedInitializer(seed, PetscRandomSeed_Rander48),
94: PetscDesignatedInitializer(getvalue, PetscRandomGetValue_Rander48),
95: PetscDesignatedInitializer(getvaluereal, PetscRandomGetValueReal_Rander48),
96: PetscDesignatedInitializer(getvalues, NULL),
97: PetscDesignatedInitializer(getvaluesreal, NULL),
98: PetscDesignatedInitializer(destroy, PetscRandomDestroy_Rander48),
99: };
101: /*MC
102: PETSCRANDER48 - simple portable reimplementation of basic Unix `drand48()` random number generator that should generate the
103: exact same random numbers on any system.
105: Options Database Key:
106: . -random_type <rand,rand48,rander48,sprng> - select the random number generator at runtime
108: Level: beginner
110: Notes:
111: This is the default random number generate provided by `PetscRandomCreate()` if you do not set a particular implementation.
113: Each `PetscRandom` object created with this type has its own seed and its own history, so multiple `PetscRandom` objects of this type
114: will not interfere with random numbers generated by other objects. Each PETSc object of this type will produce the exact same set of
115: random numbers so if you wish different `PetscRandom` objects of this type set different seeds for each one after you create them with
116: `PetscRandomSetSeed()` followed by `PetscRandomSeed()`.
118: .seealso: `PetscRandomCreate()`, `PetscRandomSetType()`, `PETSCRAND`, `PETSCRAND48`, `PETSCRANDER48`, `PETSCSPRNG`, `PetscRandomSetSeed()`,
119: `PetscRandomSeed()`, `PetscRandomSetFromOptions()`
120: M*/
122: PETSC_EXTERN PetscErrorCode PetscRandomCreate_Rander48(PetscRandom r)
123: {
124: PetscRandom_Rander48 *r48;
126: PetscFunctionBegin;
127: PetscCall(PetscNew(&r48));
128: /* r48 does not need to be initialized because PetscRandomSeed() is always called before use and sets the needed values */
129: r->data = r48;
130: r->ops[0] = PetscRandomOps_Values;
131: PetscCall(PetscObjectChangeTypeName((PetscObject)r, PETSCRANDER48));
132: PetscFunctionReturn(PETSC_SUCCESS);
133: }