📄 zrand.c
字号:
* a = 6316878969928993981 * c = 1363042948800878693 * * As we stated before, we must map 0 ==> 0. The linear congruence * generator would normally map as follows: * * 0 ==> 1363042948800878693 (0 ==> c) * * We can determine which 0<=y<m will produce a given value z by inverting the * linear congruence generator: * * z = (a*y + c) % m * * z = a*y % m + c % m * * z-c % m = a*y % m * * (z-c % m) * minv(a,m) = (a*y % m) * minv(a,m) * [minv(a,m) is the multiplicative inverse of a % m] * * ((z-c % m) * minv(a,m)) % m = ((a*y % m) * minv(a,m)) % m * * ((z-c % m) * minv(a,m)) % m = y % m * [a % m * minv(a,m) = 1 % m by definition] * * ((z-c) * minv(a,m)) % m = y % m * * ((z-c) * minv(a,m)) % m = y * [we defined y to be 0<=y<m] * * To determine which value maps back into 0, we let z = 0 and compute: * * ((0-c) * minv(a,m)) % m ==> 10239951819489363767 * * and thus we find that the congruence generator would also normally map: * * 10239951819489363767 ==> 0 * * To overcome this, and preserve the 1-to-1 and onto map, we force: * * 0 ==> 0 * 10239951819489363767 ==> 1363042948800878693 * * To repeat, this function converts a values into a seed value. With the * except of 'seed == 0', every value is mapped into a unique seed value. * This mapping need not be complex, random or secure. All we attempt * to do here is to allow humans who pick small or successive seed values * to obtain reasonably different sequences from the generators below. * * NOTE: This is NOT a pseudo random number generator. This function is * intended to be used internally by ss100rand() and sshufrand(). */static voidrandreseed64(ZVALUE seed, ZVALUE *res){ ZVALUE t; /* temp value */ ZVALUE chunk; /* processed 64 bit chunk value */ ZVALUE seed64; /* seed mod 2^64 */ HALF *v64; /* 64 bit array of HALFs */ long chunknum; /* 64 bit chunk number */ /* * quickly return 0 if seed is 0 */ if (ziszero(seed) || seed.len <= 0) { itoz(0, res); return; } /* * allocate result */ seed.sign = 0; /* use the value of seed */ res->len = (int)(((seed.len+SHALFS-1) / SHALFS) * SHALFS); res->v = alloc(res->len); res->sign = 0; memset(res->v, 0, res->len*sizeof(HALF)); /* default value is 0 */ /* * process 64 bit chunks until done */ chunknum = 0; while (!zislezero(seed)) { /* * grab the lower 64 bits of seed */ if (zge64b(seed)) { v64 = alloc(SHALFS); memcpy(v64, seed.v, SHALFS*sizeof(HALF)); seed64.v = v64; seed64.len = SHALFS; seed64.sign = 0; } else { zcopy(seed, &seed64); } zshiftr(seed, SBITS); ztrim(&seed); ztrim(&seed64); /* * do nothing if chunk is zero */ if (ziszero(seed64)) { ++chunknum; zfree(seed64); continue; } /* * Compute the linear congruence generator map: * * X1 <-- (a*X0 + c) mod m * * in other words: * * chunk == (a_val*seed + c_val) mod 2^64 */ zmul(seed64, a_val, &t); zfree(seed64); zadd(t, c_val, &chunk); zfree(t); /* * form chunk mod 2^64 */ if (chunk.len > (SB32)SHALFS) { /* result is too large, reduce to 64 bits */ v64 = alloc(SHALFS); memcpy(v64, chunk.v, SHALFS*sizeof(HALF)); free(chunk.v); chunk.v = v64; chunk.len = SHALFS; ztrim(&chunk); } /* * Normally, the above equation would map: * * f(0) == 1363042948800878693 * f(10239951819489363767) == 0 * * However, we have already forced f(0) == 0. To preserve the * 1-to-1 and onto map property, we force: * * f(10239951819489363767) ==> 1363042948800878693 */ if (ziszero(chunk)) { /* load 1363042948800878693 instead of 0 */ zcopy(c_val, &chunk); memcpy(res->v+(chunknum*SHALFS), c_val.v, c_val.len*sizeof(HALF)); /* * load the 64 bit chunk into the result */ } else { memcpy(res->v+(chunknum*SHALFS), chunk.v, chunk.len*sizeof(HALF)); } ++chunknum; zfree(chunk); } ztrim(res);}/* * zsrand - seed the s100 generator * * given: * pseed - ptr to seed of the generator or NULL * pmat100 - subtractive 100 state table or NULL * * returns: * previous s100 state */RAND *zsrand(CONST ZVALUE *pseed, CONST MATRIX *pmat100){ RAND *ret; /* previous s100 state */ CONST VALUE *v; /* value from a passed matrix */ ZVALUE zscram; /* scrambled 64 bit seed */ ZVALUE ztmp; /* temp holding value for zscram */ ZVALUE seed; /* to hold *pseed */ FULL shufxor[SLEN]; /* zshufxor as an 64 bit array of FULLs */ long indx; /* index to shuffle slots for seeding */ int i; /* * firewall */ if (pseed != NULL && zisneg(*pseed)) { math_error("neg seeds for srand reserved for future use"); /*NOTREACHED*/ } /* * initialize state if first call */ if (!s100.seeded) { s100 = init_s100; } /* * save the current state to return later */ ret = (RAND *)malloc(sizeof(RAND)); if (ret == NULL) { math_error("cannot allocate RAND state"); /*NOTREACHED*/ } *ret = s100; /* * if call was srand(), just return current state */ if (pseed == NULL && pmat100 == NULL) { return ret; } /* * if call is srand(0), initialize and return quickly */ if (pmat100 == NULL && ziszero(*pseed)) { s100 = init_s100; return ret; } /* * clear buffered bits, initialize pointers */ s100.seeded = 0; /* not seeded now */ s100.j = INIT_J; s100.k = INIT_K; s100.bits = 0; memset(s100.buffer, 0, sizeof(s100.buffer)); /* * load subtractive table * * We will load the default subtractive table unless we are passed a * matrix. If we are passed a matrix, we will load the first 100 * values mod 2^64 instead. */ if (pmat100 == NULL) { memcpy(s100.slot, def_subtract, sizeof(def_subtract)); } else { /* * use the first 100 entries from the matrix arg */ if (pmat100->m_size < S100) { math_error("matrix for srand has < 100 elements"); /*NOTREACHED*/ } for (v=pmat100->m_table, i=0; i < S100; ++i, ++v) { /* reject if not integer */ if (v->v_type != V_NUM || qisfrac(v->v_num)) { math_error("matrix for srand must contain ints"); /*NOTREACHED*/ } /* load table element from matrix element mod 2^64 */ SLOAD(s100, i, v->v_num->num); } } /* * scramble the seed in 64 bit chunks */ if (pseed != NULL) { seed.sign = pseed->sign; seed.len = pseed->len; seed.v = alloc(seed.len); zcopyval(*pseed, seed); randreseed64(seed, &zscram); zfree(seed); } /* * xor subtractive table with the rehashed lower 64 bits of seed */ if (pseed != NULL && !ziszero(zscram)) { /* xor subtractive table with lower 64 bits of seed */ SMOD64(shufxor, zscram); for (i=0; i < S100; ++i) { SXOR(s100, i, shufxor); } } /* * shuffle subtractive 100 table according to seed, if passed */ if (pseed != NULL && zge64b(zscram)) { /* prepare the seed for subtractive slot shuffling */ zshiftr(zscram, 64); ztrim(&zscram); /* shuffle subtractive table */ for (i=S100-1; i > 0 && !zislezero(zscram); --i) { /* determine what we will swap with */ indx = zdivi(zscram, i+1, &ztmp); zfree(zscram); zscram = ztmp; /* do nothing if swap with itself */ if (indx == i) { continue; } /* swap slot[i] with slot[indx] */ SSWAP(s100, i, indx); } zfree(zscram); } else if (pseed != NULL) { zfree(zscram); } /* * load the shuffle table * * We will generate SHUFCNT entries from the subtractive 100 slots * and fill the shuffle table in consecutive order.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -