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