Date: 2025-03-29T05:58:42+00:00

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:   PetscDesignatedInitializer(setfromoptions, NULL),
    100: };

    102: /*MC
    103:    PETSCRANDER48 - simple portable reimplementation of basic Unix `drand48()` random number generator that should generate the
    104:         exact same random numbers on any system.

    106:    Options Database Key:
    107: . -random_type <rand,rand48,rander48,sprng> - select the random number generator at runtime

    109:   Level: beginner

    111:   Notes:
    112:     This is the default random number generate provided by `PetscRandomCreate()` if you do not set a particular implementation.

    114:   Each `PetscRandom` object created with this type has its own seed and its own history, so multiple `PetscRandom` objects of this type
    115:   will not interfere with random numbers generated by other objects. Each PETSc object of this type will produce the exact same set of
    116:   random numbers so if you wish different `PetscRandom` objects of this type set different seeds for each one after you create them with
    117:   `PetscRandomSetSeed()` followed by `PetscRandomSeed()`.

    119: .seealso: `PetscRandomCreate()`, `PetscRandomSetType()`, `PETSCRAND`, `PETSCRAND48`, `PETSCRANDER48`, `PETSCSPRNG`, `PetscRandomSetSeed()`,
    120:           `PetscRandomSeed()`, `PetscRandomSetFromOptions()`
    121: M*/

    123: PETSC_EXTERN PetscErrorCode PetscRandomCreate_Rander48(PetscRandom r)
    124: {
    125:   PetscRandom_Rander48 *r48;

    127:   PetscFunctionBegin;
    128:   PetscCall(PetscNew(&r48));
    129:   /* r48 does not need to be initialized because PetscRandomSeed() is always called before use and sets the needed values */
    130:   r->data   = r48;
    131:   r->ops[0] = PetscRandomOps_Values;
    132:   PetscCall(PetscObjectChangeTypeName((PetscObject)r, PETSCRANDER48));
    133:   PetscFunctionReturn(PETSC_SUCCESS);
    134: }