mirror of
https://github.com/lcn2/calc.git
synced 2025-08-19 01:13:27 +03:00
2111 lines
60 KiB
C
2111 lines
60 KiB
C
/*
|
|
* zrand - subtractive 100 shuffle generator
|
|
*
|
|
* Copyright (C) 1999 Landon Curt Noll
|
|
*
|
|
* Calc is open software; you can redistribute it and/or modify it under
|
|
* the terms of the version 2.1 of the GNU Lesser General Public License
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* Calc is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
|
|
* Public License for more details.
|
|
*
|
|
* A copy of version 2.1 of the GNU Lesser General Public License is
|
|
* distributed with calc under the filename COPYING-LGPL. You should have
|
|
* received a copy with calc; if not, write to Free Software Foundation, Inc.
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* @(#) $Revision: 29.5 $
|
|
* @(#) $Id: zrand.c,v 29.5 2003/01/14 00:54:24 chongo Exp $
|
|
* @(#) $Source: /usr/local/src/cmd/calc/RCS/zrand.c,v $
|
|
*
|
|
* Under source code control: 1995/01/07 09:45:25
|
|
* File existed as early as: 1994
|
|
*
|
|
* chongo <was here> /\oo/\ http://www.isthe.com/chongo/
|
|
* Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
|
|
*/
|
|
|
|
/*
|
|
* AN OVERVIEW OF THE FUNCTIONS:
|
|
*
|
|
* This module contains an Subtractive 100 shuffle generator wrapped inside
|
|
* of a shuffle generator.
|
|
*
|
|
* We refer to this generator as the s100 generator.
|
|
*
|
|
* rand - s100 shuffle generator
|
|
* srand - seed the s100 shuffle generator
|
|
*
|
|
* This generator has two distinct parts, the s100 generator
|
|
* and the shuffle generator.
|
|
*
|
|
* The subtractive 100 generator is described in Knuth's "The Art of
|
|
* Computer Programming - Seminumerical Algorithms", Vol 2, 3rd edition
|
|
* (1998), Section 3.6, page 186, formula (2).
|
|
*
|
|
* The "use only the first 100 our of every 1009" is described in
|
|
* Knuth's "The Art of Computer Programming - Seminumerical Algorithms",
|
|
* Vol 2, 3rd edition (1998), Section 3.6, page 188".
|
|
*
|
|
* The period and other properties of this generator make it very
|
|
* useful to 'seed' other generators.
|
|
*
|
|
* The shuffle generator is described in Knuth's "The Art of Computer
|
|
* Programming - Seminumerical Algorithms", Vol 2, 3rd edition (1998),
|
|
* Section 3.2.2, page 34, Algorithm B.
|
|
*
|
|
* The shuffle generator is fast and serves as a fairly good standard
|
|
* pseudo-random generator. If you need a fast generator and do not
|
|
* need a cryptographically strong one, this generator is likely to do
|
|
* the job.
|
|
*
|
|
* The shuffle generator is feed values by the subtractive 100 process.
|
|
*
|
|
******************************************************************************
|
|
*
|
|
* GOALS:
|
|
*
|
|
* The goals of this package are:
|
|
*
|
|
* all magic numbers are explained
|
|
*
|
|
* I distrust systems with constants (magic numbers) and tables
|
|
* that have no justification (e.g., DES). I believe that I have
|
|
* done my best to justify all of the magic numbers used.
|
|
*
|
|
* full documentation
|
|
*
|
|
* You have this source file, plus background publications,
|
|
* what more could you ask?
|
|
*
|
|
* large selection of seeds
|
|
*
|
|
* Seeds are not limited to a small number of bits. A seed
|
|
* may be of any size.
|
|
*
|
|
* the strength of the generators may be tuned to meet the need
|
|
*
|
|
* By using the appropriate seed and other arguments, one may
|
|
* increase the strength of the generator to suit the need of
|
|
* the application. One does not have just a few levels.
|
|
*
|
|
* Even though I have done my best to implement a good system, you still
|
|
* must use these routines your own risk.
|
|
*
|
|
* Share and enjoy! :-)
|
|
*/
|
|
|
|
/*
|
|
* ON THE GENERATORS:
|
|
*
|
|
* The subtractive 100 generator has a good period, and is fast. It is
|
|
* reasonable as generators go, though there are better ones available.
|
|
* The shuffle generator has a very good period, and is fast. It is
|
|
* fairly good as generators go, particularly when it is feed reasonably
|
|
* random numbers. Because of this, we use feed values from the subtractive
|
|
* 100 process into the shuffle generator.
|
|
*
|
|
* The s100 generator uses 2 tables:
|
|
*
|
|
* subtractive table - 100 entries of 64 bits used by the subtractive 100
|
|
* part of the s100 generator
|
|
*
|
|
* shuffle table - 256 entries of 64 bits used by the shuffle
|
|
* part of the s100 generator and feed by the
|
|
* subtractive table.
|
|
*
|
|
* Casual direct use of the shuffle generator may be acceptable. If one
|
|
* desires cryptographically strong random numbers, or if one is paranoid,
|
|
* one should use the Blum generator instead (see zrandom.c).
|
|
*
|
|
* The s100 generator as the following calc interfaces:
|
|
*
|
|
* rand(min,max) (where min < max)
|
|
*
|
|
* Print an s100 generator random value over interval [a,b).
|
|
*
|
|
* rand()
|
|
*
|
|
* Same as rand(0, 2^64). Print 64 bits.
|
|
*
|
|
* rand(lim) (where 0 > lim)
|
|
*
|
|
* Same as rand(0, lim).
|
|
*
|
|
* randbit(x) (where x > 0)
|
|
*
|
|
* Same as rand(0, 2^x). Print x bits.
|
|
*
|
|
* randbit(skip) (where skip < 0)
|
|
*
|
|
* Skip random bits and return the bit skip count (-skip).
|
|
*/
|
|
|
|
/*
|
|
* INITIALIZATION AND SEEDS:
|
|
*
|
|
* All generators come already seeded with precomputed initial constants.
|
|
* Thus, it is not required to seed a generator before using it.
|
|
*
|
|
* The s100 generator may be initialized and seeded via srand().
|
|
*
|
|
* Using a seed of '0' will reload generators with their initial states.
|
|
*
|
|
* srand(0) restore subtractive 100 generator to the initial state
|
|
*
|
|
* The above single arg calls are fairly fast.
|
|
*
|
|
* Optimal seed range for the s100 generator:
|
|
*
|
|
* There is no limit on the size of a seed. On the other hand,
|
|
* extremely large seeds require large tables and long seed times.
|
|
* Using a seed in the range of [2^64, 2^64 * 100!) should be
|
|
* sufficient for most purposes. An easy way to stay within this
|
|
* range to to use seeds that are between 21 and 178 digits, or
|
|
* 64 to 588 bits long.
|
|
*
|
|
* To help make the generator produced by seed S, significantly
|
|
* different from S+1, seeds are scrambled prior to use. The
|
|
* function randreseed64() maps [0,2^64) into [0,2^64) in a 1-to-1
|
|
* and onto fashion.
|
|
*
|
|
* The purpose of the randreseed64() is not to add security. It
|
|
* simply helps remove the human perception of the relationship
|
|
* between the seed and the production of the generator.
|
|
*
|
|
* The randreseed64() process does not reduce the security of the
|
|
* generators. Every seed is converted into a different unique seed.
|
|
* No seed is ignored or favored.
|
|
*
|
|
******************************************************************************
|
|
*
|
|
* srand(seed)
|
|
*
|
|
* Seed the s100 generator.
|
|
*
|
|
* seed != 0:
|
|
* ---------
|
|
* Any buffered random bits are flushed. The subtractive table is loaded
|
|
* with the default subtractive table. The low order 64 bits of seed is
|
|
* xor-ed against each table value. The subtractive table is shuffled
|
|
* according to seed/2^64.
|
|
*
|
|
* The following calc code produces the same effect:
|
|
*
|
|
* (* reload default subtractive table xored with low 64 seed bits *)
|
|
* seed_xor = seed & ((1<<64)-1);
|
|
* for (i=0; i < 100; ++i) {
|
|
* subtractive[i] = xor(default_subtractive[i], seed_xor);
|
|
* }
|
|
*
|
|
* (* shuffle the subtractive table *)
|
|
* seed >>= 64;
|
|
* for (i=100; seed > 0 && i > 0; --i) {
|
|
* quomod(seed, i+1, seed, j);
|
|
* swap(subtractive[i], subtractive[j]);
|
|
* }
|
|
*
|
|
* Seed must be >= 0. All seed values < 0 are reserved for future use.
|
|
*
|
|
* The subtractive 100 pointers are reset to subtractive[36] and
|
|
* subtractive[99]. Last the shuffle table is loaded with successive
|
|
* values from the subtractive 100 generator.
|
|
*
|
|
* seed == 0:
|
|
* ---------
|
|
* Restore the initial state and modulus of the s100 generator.
|
|
* After this call, the s100 generator is restored to its initial
|
|
* state after calc started.
|
|
*
|
|
* The subtractive 100 pointers are reset to subtractive[36] and
|
|
* subtractive[99]. Last the shuffle table is loaded with successive
|
|
* values from the subtractive 100 generator.
|
|
*
|
|
******************************************************************************
|
|
*
|
|
* srand(mat100)
|
|
*
|
|
* Seed the s100 generator.
|
|
*
|
|
* Any buffered random bits are flushed. The subtractive table with the
|
|
* first 100 entries of the array mat100, mod 2^64.
|
|
*
|
|
* The subtractive 100 pointers are reset to subtractive[36] and
|
|
* subtractive[99]. Last the shuffle table is loaded with successive
|
|
* values from the subtractive 100 generator.
|
|
*
|
|
******************************************************************************
|
|
*
|
|
* srand()
|
|
*
|
|
* Return current s100 generator state. This call does not alter
|
|
* the generator state.
|
|
*
|
|
******************************************************************************
|
|
*
|
|
* srand(state)
|
|
*
|
|
* Restore the s100 state and return the previous state. Note that
|
|
* the argument state is a rand state value (isrand(state) is true).
|
|
* Any internally buffered random bits are restored.
|
|
*
|
|
* The states of the s100 generators can be saved by calling the seed
|
|
* function with no arguments, and later restored by calling the seed
|
|
* functions with that same return value.
|
|
*
|
|
* rand_state = srand();
|
|
* ... generate random bits ...
|
|
* prev_rand_state = srand(rand_state);
|
|
* ... generate the same random bits ...
|
|
* srand() == prev_rand_state; (* is true *)
|
|
*
|
|
* Saving the state just after seeding a generator and restoring it later
|
|
* as a very fast way to reseed a generator.
|
|
*/
|
|
|
|
/*
|
|
* TRUTH IN ADVERTISING:
|
|
*
|
|
* A "truth in advertising" issue is the use of the term
|
|
* 'pseudo-random'. All deterministic generators are pseudo random.
|
|
* This is opposed to true random generators based on some special
|
|
* physical device.
|
|
*
|
|
* A final "truth in advertising" issue deals with how the magic numbers
|
|
* found in this file were generated. Detains can be found in the
|
|
* various functions, while a overview can be found in the "SOURCE FOR
|
|
* MAGIC NUMBERS" section below.
|
|
*/
|
|
|
|
/*
|
|
* SOURCE OF MAGIC NUMBERS:
|
|
*
|
|
* Most of the magic constants used on this file ultimately are
|
|
* based on LavaRnd. LavaRnd produced them via a cryprographic
|
|
* of the digitization of chaotic system that consisted of a noisy
|
|
* digital camera and 6 Lava Lite(R) lamps.
|
|
*
|
|
* BTW: Lava Lite(R) is a trademark of Haggerty Enterprises, Inc.
|
|
*
|
|
* The first 100 groups of 64 bit bits were used to initialize init_s100.slot.
|
|
*
|
|
* The function, randreseed64(), uses 2 primes to scramble 64 bits
|
|
* into 64 bits. These primes were also extracted from the Rand
|
|
* Book of Random Numbers. See randreseed64() for details.
|
|
*
|
|
* The shuffle table size is longer than the 100 entries recommended
|
|
* by Knuth. We use a power of 2 shuffle table length so that the
|
|
* shuffle process can select a table entry from a new subtractive 100
|
|
* value by extracting its low order bits. The value 256 is convenient
|
|
* in that it is the size of a byte which allows for easy extraction.
|
|
*
|
|
* We use the upper byte of the subtractive 100 value to select the shuffle
|
|
* table entry because it allows all of 64 bits to play a part in the
|
|
* entry selection. If we were to select a lower 8 bits in the 64 bit
|
|
* value, carries that propagate above our 8 bits would not impact the
|
|
* s100 generator output.
|
|
*
|
|
******************************************************************************
|
|
*
|
|
* FOR THE PARANOID:
|
|
*
|
|
* The truly paranoid might suggest that my claims in the MAGIC NUMBERS
|
|
* section are a lie intended to entrap people. Well they are not, but
|
|
* if you that paranoid why would you use a non-cryprographically strong
|
|
* pseudo-random number generator in the first place? You would be
|
|
* better off using the random() builtin function.
|
|
*
|
|
* The two constants that were picked from the Rand Book of Random Numbers
|
|
* The random numbers from the Rand Book of Random Numbers can be
|
|
* verified by anyone who obtains the book. As these numbers were
|
|
* created before I (Landon Curt Noll) was born (you can look up
|
|
* my birth record if you want), I claim to have no possible influence
|
|
* on their generation.
|
|
*
|
|
* There is a very slight chance that the electronic copy of the
|
|
* Rand Book of Random Numbers that I was given access to differs
|
|
* from the printed text. I am willing to provide access to this
|
|
* electronic copy should anyone wants to compare it to the printed text.
|
|
*
|
|
* When using the s100 generator, one may select your own 100 subtractive
|
|
* values by calling:
|
|
*
|
|
* srand(mat100)
|
|
*
|
|
* and avoid using my magic numbers. The randreseed64 process is NOT
|
|
* applied to the matrix values. Of course, you must pick good subtractive
|
|
* 100 values yourself!
|
|
*
|
|
* One might object to the complexity of the seed scramble/mapping
|
|
* via the randreseed64() function. The randreseed64() function maps:
|
|
*
|
|
* 0 ==> 0
|
|
* 10239951819489363767 ==> 1363042948800878693
|
|
*
|
|
* so that srand(0) does the default action and randreseed64() remains
|
|
* an 1-to-1 and onto map. Thus calling srand(0) with the randreseed64()
|
|
* process would be the same as calling srand(4967126403401436567) without
|
|
* it. No extra security is gained or reduced by using the randreseed64()
|
|
* process. The meaning of seeds are exchanged, but not lost or favored
|
|
* (used by more than one input seed).
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "zrand.h"
|
|
#include "have_const.h"
|
|
|
|
|
|
/*
|
|
* default s100 generator state
|
|
*
|
|
* This is the state of the s100 generator after initialization, or srand(0),
|
|
* or srand(0) is called. The init_s100 value is never changed, only copied.
|
|
*/
|
|
static CONST RAND init_s100 = {
|
|
1, /* seeded */
|
|
0, /* no buffered bits */
|
|
#if FULL_BITS == SBITS /* buffer */
|
|
{0},
|
|
#elif 2*FULL_BITS == SBITS
|
|
{0, 0},
|
|
#else
|
|
/\../\ BASEB is assumed to be 16 or 32 /\../\ !!!
|
|
#endif
|
|
INIT_J, /* j */
|
|
INIT_K, /* k */
|
|
RAND_CONSEQ_USE, /* use this many before skipping values */
|
|
/* NOTE: Due to a SunOS cc bug, don't put spaces in the SVAL call! */
|
|
{ /* subtractive 100 table */
|
|
SVAL(c8c0370c,7db7dc19), SVAL(738e33b9,40a06fbb),
|
|
SVAL(481abb76,a859ed2b), SVAL(74106bb3,9ccdccb5),
|
|
SVAL(05a8eeb5,c3173bfc), SVAL(efd5100d,5a02e577),
|
|
SVAL(a69271f7,4030b24a), SVAL(641282fc,16fe22c5),
|
|
SVAL(7aa7267c,40438da3), SVAL(1fdf4abd,c2d878d1),
|
|
SVAL(d9899e7a,95702379), SVAL(5ea8e217,d02d7f08),
|
|
SVAL(770587fe,4d47a353), SVAL(de7d1bdd,0a33a2b8),
|
|
SVAL(4378c3c5,900e7c45), SVAL(77c94478,19a514f9),
|
|
SVAL(fc5edb22,843d1d32), SVAL(4fc42ce5,e8ee5e6e),
|
|
SVAL(c938713c,8488013e), SVAL(6a318f03,20ab0cac),
|
|
SVAL(73e6d1a3,ffc8bff3), SVAL(0cd3232a,8ca96aa7),
|
|
SVAL(605c8036,905f770d), SVAL(4d037b00,8b8d04a2),
|
|
SVAL(1ed81965,cb277294), SVAL(408d9c47,7a254ff3),
|
|
SVAL(8b68587a,e26c7377), SVAL(cff191a4,8a48832f),
|
|
SVAL(12d3df1d,8aeb6fe6), SVAL(b2bf907e,1feda37a),
|
|
SVAL(4e5f7719,3bb5f39f), SVAL(33ebcf6f,8f5d1581),
|
|
SVAL(203c8e48,d33654eb), SVAL(68d3656e,f19c8a4e),
|
|
SVAL(3ec20b04,986eb2af), SVAL(5d73a03b,062c3841),
|
|
SVAL(836ce709,5d4e49eb), SVAL(2310bc40,c3f49221),
|
|
SVAL(3868ee48,a6d0cbf6), SVAL(67578aa6,4a43deb1),
|
|
SVAL(6e3426c1,150dfc26), SVAL(c541ccaa,3131be30),
|
|
SVAL(f7e57432,cec7aab2), SVAL(2b35de99,8cb3c873),
|
|
SVAL(7b9f7764,8663a5d7), SVAL(23b00e6a,a771e5a6),
|
|
SVAL(859c775c,a9985d05), SVAL(99636ea1,6b692f1f),
|
|
SVAL(8700ac70,3730800d), SVAL(46142502,4298a753),
|
|
SVAL(ea4a411b,809e955f), SVAL(3119ad40,33709dfb),
|
|
SVAL(b76a6c6e,5f01cb7c), SVAL(6109dc8a,15984eaf),
|
|
SVAL(5d686db9,a5ca9505), SVAL(8e80d761,3b7e6add),
|
|
SVAL(79cbd718,de6f6fd3), SVAL(40e9cd15,1da0f699),
|
|
SVAL(e82158ba,b24f312d), SVAL(79a4c927,f5e5c36b),
|
|
SVAL(c25247c9,a0039333), SVAL(93687116,1766d81d),
|
|
SVAL(3c6a03b4,a6741327), SVAL(c8a7b6e8,c002f29a),
|
|
SVAL(0e2a67c6,7bbd5ea3), SVAL(0929042d,441eabc1),
|
|
SVAL(7dbe232a,25e82085), SVAL(8cfb26e5,44fbac3d),
|
|
SVAL(8e40384d,388ab983), SVAL(48dc1230,554632f8),
|
|
SVAL(ab405048,ab492397), SVAL(21c9e2f5,a118e387),
|
|
SVAL(484d1a8c,343b61b5), SVAL(d49e3dec,ab256f26),
|
|
SVAL(e615c7fd,78f2d2e3), SVAL(8442cc33,ce6cc2ed),
|
|
SVAL(0a3b93d8,44d4bbf6), SVAL(2d7e4efe,9301de77),
|
|
SVAL(33711b76,d8790d8a), SVAL(c07dc30e,44df77e7),
|
|
SVAL(b9132ed0,9ddd508f), SVAL(45d06cf8,c6fb43cc),
|
|
SVAL(22bed18a,d585dd7b), SVAL(61c6cced,10799ffa),
|
|
SVAL(d7f2393b,e4bd9aa9), SVAL(706753fb,cfd55094),
|
|
SVAL(f65a6713,ede6e446), SVAL(8bf6dfae,47c0d5c3),
|
|
SVAL(fb4dfc17,9f7927d6), SVAL(12ebbc16,e212c297),
|
|
SVAL(43c71283,a00a954c), SVAL(8957087a,e7bd40a5),
|
|
SVAL(b0859d71,08344837), SVAL(fbf4b9a3,aeb313f5),
|
|
SVAL(5e66e5be,ce81823a), SVAL(09a11c6e,58ad6da1),
|
|
SVAL(c76f4316,c608054f), SVAL(b5821361,46084099),
|
|
SVAL(4210008f,17a725ed), SVAL(e5ff8912,d347c481)
|
|
},
|
|
/* NOTE: Due to a SunOS cc bug, don't put spaces in the SVAL call! */
|
|
{ /* shuffle table */
|
|
SVAL(69a2296c,ec8abd57), SVAL(867e1869,99a6df81),
|
|
SVAL(c05ab96b,d849a48a), SVAL(7eb3ce0c,fa00554b),
|
|
SVAL(520d01f6,5a5a9acd), SVAL(d4ef1e33,36022d81),
|
|
SVAL(af44772b,c6f84f70), SVAL(647e85a6,a7c55173),
|
|
SVAL(26746cf1,959df8d1), SVAL(98681a90,4db28abd),
|
|
SVAL(b146c969,744c5cd2), SVAL(8ce69d1f,706f88c2),
|
|
SVAL(fd12eac4,21b4a748), SVAL(f12e70fe,2710eea5),
|
|
SVAL(0b8f7805,5901f2b5), SVAL(48860a76,4f2c115e),
|
|
SVAL(0edf6d2a,30767e2c), SVAL(8a6d7dc5,fce2713b),
|
|
SVAL(46a362ea,4e0e2346), SVAL(6c369a0a,359f5aa7),
|
|
SVAL(dfca81fe,41def54e), SVAL(4b733819,96c2bc4e),
|
|
SVAL(659e8b99,6f3f14f9), SVAL(8b97b934,93d47e6f),
|
|
SVAL(a73a8704,dfa10a55), SVAL(8d9eafe9,b06503da),
|
|
SVAL(2556fb88,f32336b0), SVAL(e71e9f75,1002a161),
|
|
SVAL(27a7be6e,200af907), SVAL(1b9b734e,d028e9a3),
|
|
SVAL(950cfeed,4c0be0d3), SVAL(f4c41694,2536d275),
|
|
SVAL(f05a58e8,5687b76e), SVAL(ba53ac01,71a62d54),
|
|
SVAL(4b14cbcb,285adc96), SVAL(fdf66edd,b00a5557),
|
|
SVAL(bb43d58d,185b6ea1), SVAL(905db9cd,f355c9a6),
|
|
SVAL(fc3a07fc,04429c8a), SVAL(65d7e365,aa3a4f7e),
|
|
SVAL(2d284c18,b243ac65), SVAL(72fba65d,44e417fd),
|
|
SVAL(422d50b4,5c934805), SVAL(b62a6053,d1587441),
|
|
SVAL(a5e71ce9,6f7ae035), SVAL(93abca2e,595c8dd8),
|
|
SVAL(534231af,e39afad5), SVAL(08d26cac,12eaad56),
|
|
SVAL(ec18bf8d,7fb1b1c2), SVAL(3d28ea16,faf6f09b),
|
|
SVAL(ea357a78,16697dd6), SVAL(51471ea1,420f3f51),
|
|
SVAL(5e051aeb,7f8946b4), SVAL(881be097,0cf0524c),
|
|
SVAL(d558b25b,1b31489e), SVAL(707d1a94,3a8b065c),
|
|
SVAL(37017e66,568ff836), SVAL(b9cd627c,24c2f747),
|
|
SVAL(1485549f,fb1d9ff6), SVAL(308d32d9,bdf2dc6f),
|
|
SVAL(4d4142ca,d543818a), SVAL(5d9c7aee,87ebba43),
|
|
SVAL(81c5bdd8,e17adb2f), SVAL(3dc9752e,c8d8677a),
|
|
SVAL(66b086e6,c34e4212), SVAL(3af7a90d,c62b25e3),
|
|
SVAL(f8349f79,35539315), SVAL(6bcfd9d5,a22917f0),
|
|
SVAL(8639bb76,5f5ee517), SVAL(d3c5e369,8095b092),
|
|
SVAL(8a33851e,7eb44748), SVAL(5e29d443,ea54bbcf),
|
|
SVAL(0f84651f,4d59a834), SVAL(85040bea,f1a5f951),
|
|
SVAL(3dba1c74,98002078), SVAL(5d70712b,f0b2cc15),
|
|
SVAL(fa3af8eb,cce8e5a7), SVAL(fb3e2237,04bba57d),
|
|
SVAL(5d3b8785,8a950434), SVAL(ce3112bd,ba3f8dcf),
|
|
SVAL(44904f55,860d3051), SVAL(cec8fed4,4ed3e98b),
|
|
SVAL(4581698d,25d01ea4), SVAL(11eb6828,9a9548e0),
|
|
SVAL(796cb4c6,e911fac8), SVAL(2164cf26,b5fd813e),
|
|
SVAL(4ac8e0f5,d5de640f), SVAL(e9e757d7,8802ab4e),
|
|
SVAL(3c97de26,f49dfcbd), SVAL(c604881b,6ee6dbe6),
|
|
SVAL(a7c22a6e,57d6154e), SVAL(234e2370,877b3cc7),
|
|
SVAL(c0bdb72b,df1f8358), SVAL(6522e0fc,a95b7b55),
|
|
SVAL(ba174c90,22344162), SVAL(712c9b2d,75d48867),
|
|
SVAL(240f7e92,e59f3700), SVAL(e83cc2d4,ad95d763),
|
|
SVAL(8509445a,4336d717), SVAL(f1e572c5,dfff1804),
|
|
SVAL(ed10eb5d,623232dd), SVAL(9205ea1b,d4f957e8),
|
|
SVAL(4973a54f,2ff062f5), SVAL(26b018f1,e8c48cd5),
|
|
SVAL(56908401,d1c7ed9f), SVAL(2e48937b,df89a247),
|
|
SVAL(9d53069b,2be47129), SVAL(98069e3b,c048a2b0),
|
|
SVAL(f25b7d65,1cd83f93), SVAL(2b004e6c,e6f886c8),
|
|
SVAL(f618442a,5c635935), SVAL(a502ab5c,7198e052),
|
|
SVAL(c14241a4,a6c41b0b), SVAL(720e845a,7db9b18e),
|
|
SVAL(2abb13e9,4b713918), SVAL(90fc0c20,7f52467d),
|
|
SVAL(799c8ccd,7868d348), SVAL(f4817ced,912a0ea4),
|
|
SVAL(d68c0f4c,c4903a57), SVAL(a3171f29,e2b7934c),
|
|
SVAL(b1158baa,0b4ccc22), SVAL(f5d85553,49a29eda),
|
|
SVAL(59d1a078,959442ef), SVAL(db9b4a96,a67fd518),
|
|
SVAL(cc7ca9ee,d2870636), SVAL(548f021c,ecf59920),
|
|
SVAL(25b7f4b6,571bc8c5), SVAL(4fa52747,3a44f536),
|
|
SVAL(b246845f,df0ebdc2), SVAL(dd8d68ae,42058793),
|
|
SVAL(3ba13328,9f6c39fb), SVAL(8bfdfbf3,7b6b42af),
|
|
SVAL(fb34c5ca,7fb2b3b0), SVAL(2345dcec,d428e32a),
|
|
SVAL(6891e850,ad42b63e), SVAL(930642c8,362c1381),
|
|
SVAL(13871e9b,1886aff5), SVAL(d0cf2407,482bda55),
|
|
SVAL(125b5fc9,5069bc31), SVAL(9b71d0a9,f07dfa5d),
|
|
SVAL(55c044cc,6712e524), SVAL(f0377358,bb601978),
|
|
SVAL(152ad5f8,7fa51e8b), SVAL(e5ebf478,9fcdd9af),
|
|
SVAL(3d78e18c,66ebce7e), SVAL(8246db72,f36aa83f),
|
|
SVAL(cc6ddc6d,2c64c0a3), SVAL(a758d687,0d91851e),
|
|
SVAL(24b20a6f,9488ee36), SVAL(be11ccdf,09798197),
|
|
SVAL(11aca015,99c1f4e3), SVAL(40e89e36,6437ac05),
|
|
SVAL(c8bfc762,5af675f8), SVAL(6367c578,b577e759),
|
|
SVAL(00380346,615f0b74), SVAL(ee964cc4,8de07d81),
|
|
SVAL(17f6ac16,859d9261), SVAL(092f4a17,3a6e2f6c),
|
|
SVAL(79981a3d,b9024b95), SVAL(36db1660,04f7f540),
|
|
SVAL(c36252cf,65a2f1c8), SVAL(705b6fde,124c9bd2),
|
|
SVAL(31e58dda,85db40ce), SVAL(6342b1a5,9f5e8d6d),
|
|
SVAL(5c2c67d0,bd6d1d4d), SVAL(1fe5b46f,ba7e069d),
|
|
SVAL(21c46c6c,ac72e13c), SVAL(b80c5fd5,9eb8f52a),
|
|
SVAL(56c3aebf,a74c92bc), SVAL(c1aff1fc,bf8c4196),
|
|
SVAL(2b1df645,754ad208), SVAL(5c734600,d46eeb50),
|
|
SVAL(e0ff1b12,6a70a765), SVAL(d5416497,7a94547c),
|
|
SVAL(67b59d7c,4ea35206), SVAL(53be7146,779203b4),
|
|
SVAL(6b589fe5,414026b8), SVAL(9e81016c,3083bfee),
|
|
SVAL(b23526b9,3b4b7671), SVAL(4fa9ffb1,7ee300ba),
|
|
SVAL(6217e212,ad05fb21), SVAL(f5b3fcd3,b294e6c2),
|
|
SVAL(ac040bbe,216beb2a), SVAL(1f8d8a54,71d0e78c),
|
|
SVAL(b6d15b41,9cfec96b), SVAL(c5477845,d0508c78),
|
|
SVAL(5b486e81,b4bba621), SVAL(90c35c94,ef4c4121),
|
|
SVAL(efce7346,f6a6bc55), SVAL(a27828d9,25bdb9bb),
|
|
SVAL(e3a53095,a1f0b205), SVAL(1bfa6093,d9f208ab),
|
|
SVAL(fb078f6a,6842cdf4), SVAL(07806d72,97133a38),
|
|
SVAL(2c6c901b,a3ce9592), SVAL(1f0ab2cf,ebc1b789),
|
|
SVAL(2ce81415,e2d03d5e), SVAL(7da45d5b,aa9f2417),
|
|
SVAL(3be4f76d,dd800682), SVAL(dbf4e4a3,364d72d3),
|
|
SVAL(b538cccf,4fc59da5), SVAL(b0aa39d5,487f66ec),
|
|
SVAL(2fd28dfd,87927d3d), SVAL(d14e77f0,5900c6b1),
|
|
SVAL(2523fad2,5330c7b4), SVAL(991b5938,d82368a4),
|
|
SVAL(b7c11443,2b9c1302), SVAL(db842db6,1394b116),
|
|
SVAL(3641548d,78ed26d8), SVAL(274fa8ef,0a61dacf),
|
|
SVAL(a554ba63,112df6f1), SVAL(7b7fe985,6b50438d),
|
|
SVAL(c9fa0042,bb63bbad), SVAL(3abf45d0,e27f00da),
|
|
SVAL(d95faa15,9f87aabb), SVAL(4a95012e,3488e7ae),
|
|
SVAL(1be2bdb9,0c642d04), SVAL(145c8881,8b4abf3e),
|
|
SVAL(7f9fb635,544cf17f), SVAL(b8ab2f62,cc78db70),
|
|
SVAL(8ee64bcd,b4242f9a), SVAL(abd52858,95dad129),
|
|
SVAL(be722c2f,ccf31141), SVAL(7c330703,575e26a9),
|
|
SVAL(45d3e3b3,361b79e4), SVAL(241163a7,54b2e6a6),
|
|
SVAL(8f678d7d,f7cacb77), SVAL(988a68a4,83211d19),
|
|
SVAL(79599598,ba7836f6), SVAL(4850c887,eeda68bf),
|
|
SVAL(afa69a71,8052ce25), SVAL(8b21efc6,bdd73573),
|
|
SVAL(89dbae18,d0972493), SVAL(560776bf,537d9454),
|
|
SVAL(3c009f78,165310f2), SVAL(a3680021,0160c3af),
|
|
SVAL(3353ec3c,a643bd40), SVAL(7e593f99,911dab02),
|
|
SVAL(72d1ddd9,4f676e89), SVAL(fd18b8bd,6b43c0ea),
|
|
SVAL(43cacef2,ddbd697d), SVAL(2868a4d0,acefe884),
|
|
SVAL(5f377b63,a506f013), SVAL(eaa0975e,05ca662b),
|
|
SVAL(3740e6b8,eb433931), SVAL(ce85df00,08557948),
|
|
SVAL(784745fb,547e33f9), SVAL(4a1fc5d4,e5c6f598),
|
|
SVAL(85fa6fec,768430a7), SVAL(990d0c24,d2332a51),
|
|
SVAL(55245c2c,33b676d5), SVAL(b1091519,e2bcfa71),
|
|
SVAL(38521478,d23a28d8), SVAL(9b794f89,9a573010),
|
|
SVAL(61d225e8,699bb486), SVAL(21476d24,1c2158b0)
|
|
}
|
|
};
|
|
|
|
/*
|
|
* default subtractive 100 table
|
|
*
|
|
* The subtractive 100 table in init_s100 has been processed 256 times in order
|
|
* to preload the shuffle table. The array below is the table before
|
|
* this processing. These values have came from LavaRnd.
|
|
*
|
|
* This array is never changed, only copied.
|
|
*/
|
|
static CONST FULL def_subtract[SCNT] = {
|
|
/* NOTE: Due to a SunOS cc bug, don't put spaces in the SVAL call! */
|
|
SVAL(c8c0370c,7db7dc19), SVAL(738e33b9,40a06fbb),
|
|
SVAL(481abb76,a859ed2b), SVAL(74106bb3,9ccdccb5),
|
|
SVAL(05a8eeb5,c3173bfc), SVAL(efd5100d,5a02e577),
|
|
SVAL(a69271f7,4030b24a), SVAL(641282fc,16fe22c5),
|
|
SVAL(7aa7267c,40438da3), SVAL(1fdf4abd,c2d878d1),
|
|
SVAL(d9899e7a,95702379), SVAL(5ea8e217,d02d7f08),
|
|
SVAL(770587fe,4d47a353), SVAL(de7d1bdd,0a33a2b8),
|
|
SVAL(4378c3c5,900e7c45), SVAL(77c94478,19a514f9),
|
|
SVAL(fc5edb22,843d1d32), SVAL(4fc42ce5,e8ee5e6e),
|
|
SVAL(c938713c,8488013e), SVAL(6a318f03,20ab0cac),
|
|
SVAL(73e6d1a3,ffc8bff3), SVAL(0cd3232a,8ca96aa7),
|
|
SVAL(605c8036,905f770d), SVAL(4d037b00,8b8d04a2),
|
|
SVAL(1ed81965,cb277294), SVAL(408d9c47,7a254ff3),
|
|
SVAL(8b68587a,e26c7377), SVAL(cff191a4,8a48832f),
|
|
SVAL(12d3df1d,8aeb6fe6), SVAL(b2bf907e,1feda37a),
|
|
SVAL(4e5f7719,3bb5f39f), SVAL(33ebcf6f,8f5d1581),
|
|
SVAL(203c8e48,d33654eb), SVAL(68d3656e,f19c8a4e),
|
|
SVAL(3ec20b04,986eb2af), SVAL(5d73a03b,062c3841),
|
|
SVAL(836ce709,5d4e49eb), SVAL(2310bc40,c3f49221),
|
|
SVAL(3868ee48,a6d0cbf6), SVAL(67578aa6,4a43deb1),
|
|
SVAL(6e3426c1,150dfc26), SVAL(c541ccaa,3131be30),
|
|
SVAL(f7e57432,cec7aab2), SVAL(2b35de99,8cb3c873),
|
|
SVAL(7b9f7764,8663a5d7), SVAL(23b00e6a,a771e5a6),
|
|
SVAL(859c775c,a9985d05), SVAL(99636ea1,6b692f1f),
|
|
SVAL(8700ac70,3730800d), SVAL(46142502,4298a753),
|
|
SVAL(ea4a411b,809e955f), SVAL(3119ad40,33709dfb),
|
|
SVAL(b76a6c6e,5f01cb7c), SVAL(6109dc8a,15984eaf),
|
|
SVAL(5d686db9,a5ca9505), SVAL(8e80d761,3b7e6add),
|
|
SVAL(79cbd718,de6f6fd3), SVAL(40e9cd15,1da0f699),
|
|
SVAL(e82158ba,b24f312d), SVAL(79a4c927,f5e5c36b),
|
|
SVAL(c25247c9,a0039333), SVAL(93687116,1766d81d),
|
|
SVAL(3c6a03b4,a6741327), SVAL(c8a7b6e8,c002f29a),
|
|
SVAL(0e2a67c6,7bbd5ea3), SVAL(0929042d,441eabc1),
|
|
SVAL(7dbe232a,25e82085), SVAL(8cfb26e5,44fbac3d),
|
|
SVAL(8e40384d,388ab983), SVAL(48dc1230,554632f8),
|
|
SVAL(ab405048,ab492397), SVAL(21c9e2f5,a118e387),
|
|
SVAL(484d1a8c,343b61b5), SVAL(d49e3dec,ab256f26),
|
|
SVAL(e615c7fd,78f2d2e3), SVAL(8442cc33,ce6cc2ed),
|
|
SVAL(0a3b93d8,44d4bbf6), SVAL(2d7e4efe,9301de77),
|
|
SVAL(33711b76,d8790d8a), SVAL(c07dc30e,44df77e7),
|
|
SVAL(b9132ed0,9ddd508f), SVAL(45d06cf8,c6fb43cc),
|
|
SVAL(22bed18a,d585dd7b), SVAL(61c6cced,10799ffa),
|
|
SVAL(d7f2393b,e4bd9aa9), SVAL(706753fb,cfd55094),
|
|
SVAL(f65a6713,ede6e446), SVAL(8bf6dfae,47c0d5c3),
|
|
SVAL(fb4dfc17,9f7927d6), SVAL(12ebbc16,e212c297),
|
|
SVAL(43c71283,a00a954c), SVAL(8957087a,e7bd40a5),
|
|
SVAL(b0859d71,08344837), SVAL(fbf4b9a3,aeb313f5),
|
|
SVAL(5e66e5be,ce81823a), SVAL(09a11c6e,58ad6da1),
|
|
SVAL(c76f4316,c608054f), SVAL(b5821361,46084099),
|
|
SVAL(4210008f,17a725ed), SVAL(e5ff8912,d347c481)
|
|
};
|
|
|
|
|
|
/*
|
|
* Linear Congruential Constants
|
|
*
|
|
* a = 6316878969928993981 = 0x57aa0ff473c0ccbd
|
|
* c = 1363042948800878693 = 0x12ea805718e09865
|
|
*
|
|
* These constants are used in the randreseed64(). See below.
|
|
*/
|
|
/* NOTE: Due to a SunOS cc bug, don't put spaces in the SHVAL call! */
|
|
static CONST HALF a_vec[SHALFS] = {SHVAL(57aa,0ff4,73c0,ccbd)};
|
|
static CONST HALF c_vec[SHALFS] = {SHVAL(12ea,8057,18e0,9865)};
|
|
static CONST ZVALUE a_val = {(HALF *)a_vec, SHALFS, 0};
|
|
static CONST ZVALUE c_val = {(HALF *)c_vec, SHALFS, 0};
|
|
|
|
|
|
/*
|
|
* current s100 generator state
|
|
*/
|
|
static RAND s100;
|
|
|
|
|
|
/*
|
|
* declare static functions
|
|
*/
|
|
static void randreseed64(ZVALUE seed, ZVALUE *res);
|
|
static int slotcp(BITSTR *bitstr, FULL *src, int count);
|
|
static void slotcp64(BITSTR *bitstr, FULL *src);
|
|
|
|
|
|
/*
|
|
* randreseed64 - scramble seed in 64 bit chunks
|
|
*
|
|
* given:
|
|
* a seed
|
|
*
|
|
* returns:
|
|
* a scrambled seed, or 0 if seed was 0
|
|
*
|
|
* It is 'nice' when a seed of "n" produces a 'significantly different'
|
|
* sequence than a seed of "n+1". Generators, by convention, assign
|
|
* special significance to the seed of '0'. It is an unfortunate that
|
|
* people often pick small seed values, particularly when large seed
|
|
* are of significance to the generators found in this file.
|
|
*
|
|
* We will process seed 64 bits at a time until the entire seed has been
|
|
* exhausted. If a 64 bit chunk is 0, then 0 is returned. If the 64 bit
|
|
* chunk is non-zero, we will produce a different and unique new scrambled
|
|
* chunk. In particular, if the seed is 0 we will return 0. If the seed
|
|
* is non-zero, we will return a different value (though chunks of 64
|
|
* zeros will remain zero). This scrambling will effectively eliminate
|
|
* the human perceptions that are noted above.
|
|
*
|
|
* It should be noted that the purpose of this process is to scramble a seed
|
|
* ONLY. We do not care if these generators produce good random numbers.
|
|
* We only want to help eliminate the human factors and perceptions
|
|
* noted above.
|
|
*
|
|
* This function scrambles all 64 bit chunks of a seed, by mapping [0,2^64)
|
|
* into [0,2^64). This map is one-to-one and onto. Mapping is performed
|
|
* using a linear congruence generator of the form:
|
|
*
|
|
* X1 <-- (a*X0 + c) % m
|
|
*
|
|
* with the exception that:
|
|
*
|
|
* 0 ==> 0 (so that srand(0) acts as default)
|
|
* randreseed64() is an 1-to-1 and onto map
|
|
*
|
|
* The generator are based on the linear congruential generators found in
|
|
* Knuth's "The Art of Computer Programming - Seminumerical Algorithms",
|
|
* vol 2, 2nd edition (1981), Section 3.6, pages 170-171.
|
|
*
|
|
* Because we process 64 bits we will take:
|
|
*
|
|
* m = 2^64 (based on note ii)
|
|
*
|
|
* We will scan the Rand Book of Random Numbers to look for an 'a' such that:
|
|
*
|
|
* a mod 8 == 5 (based on note iii)
|
|
* 0.01*m < a < 0.99*m (based on note iv)
|
|
* 0.01*2^64 < a < 0.99*2^64
|
|
*
|
|
* To help keep the generators independent, we want:
|
|
*
|
|
* a is prime
|
|
*
|
|
* The choice of an adder 'c' is considered immaterial according (based
|
|
* in note v). Knuth suggests 'c==1' or 'c==a'. We elect to select 'c'
|
|
* using the same process as we used to select 'a'. The choice is
|
|
* 'immaterial' after all, and as long as:
|
|
*
|
|
* gcd(c, m) == 1 (based on note v)
|
|
* gcd(c, 2^64) == 1
|
|
*
|
|
* the concerns are met. It can be shown that if we have:
|
|
*
|
|
* gcd(a, c) == 1
|
|
*
|
|
* then the adders and multipliers will be more independent.
|
|
*
|
|
* We will obtain the values 'a' and 'c for our generator from the
|
|
* Rand Book of Random Numbers. Because m=2^64 is 20 decimal digits long,
|
|
* we will search the Rand Book of Random Numbers 20 at a time. We will
|
|
* skip any of the 100 values that were used to initialize the subtractive 100
|
|
* generators. The values obtained from the Rand Book of Random Numbers are:
|
|
*
|
|
* 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 void
|
|
randreseed64(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 > 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.
|
|
*/
|
|
for (i=0; i < SHUFCNT; ++i) {
|
|
|
|
/*
|
|
* skip values if required
|
|
*
|
|
* See:
|
|
* Knuth's "The Art of Computer Programming -
|
|
* Seminumerical Algorithms", Vol 2, 3rd edition (1998),
|
|
* Section 3.6, page 188".
|
|
*/
|
|
if (s100.need_to_skip <= 0) {
|
|
int sk;
|
|
|
|
/* skip the require number of values */
|
|
for (sk=0; sk < RAND_SKIP; ++sk) {
|
|
|
|
/* bump j and k */
|
|
if (++s100.j >= S100) {
|
|
s100.j = 0;
|
|
}
|
|
if (++s100.k >= S100) {
|
|
s100.k = 0;
|
|
}
|
|
|
|
/* slot[k] -= slot[j] */
|
|
SSUB(s100, s100.k, s100.j);
|
|
|
|
/* NOTE: don't shuffle, no shuffle table yet */
|
|
}
|
|
|
|
/* reset the skip count */
|
|
s100.need_to_skip = RAND_CONSEQ_USE;
|
|
if (conf->calc_debug & CALCDBG_RAND) {
|
|
printf("rand: skipped %d states\n", RAND_SKIP);
|
|
}
|
|
|
|
/* no skip, just descrment use counter */
|
|
} else {
|
|
--s100.need_to_skip;
|
|
}
|
|
|
|
/* bump j and k */
|
|
if (++s100.j >= S100) {
|
|
s100.j = 0;
|
|
}
|
|
if (++s100.k >= S100) {
|
|
s100.k = 0;
|
|
}
|
|
|
|
/* slot[k] -= slot[j] */
|
|
SSUB(s100, s100.k, s100.j);
|
|
|
|
/* shuf[i] = slot[k] */
|
|
SSHUF(s100, i, s100.k);
|
|
}
|
|
|
|
/*
|
|
* note that we are seeded
|
|
*/
|
|
s100.seeded = 1;
|
|
|
|
/*
|
|
* return the previous state
|
|
*/
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* zsetrand - set the s100 generator state
|
|
*
|
|
* given:
|
|
* state - the state to copy
|
|
*
|
|
* returns:
|
|
* previous s100 state
|
|
*/
|
|
RAND *
|
|
zsetrand(CONST RAND *state)
|
|
{
|
|
RAND *ret; /* previous s100 state */
|
|
|
|
/*
|
|
* initialize state if first call
|
|
*/
|
|
if (!s100.seeded) {
|
|
s100 = init_s100;
|
|
}
|
|
|
|
/*
|
|
* save the current state to return later
|
|
*/
|
|
ret = randcopy(&s100);
|
|
|
|
/*
|
|
* load the new state
|
|
*/
|
|
s100 = *state;
|
|
|
|
/*
|
|
* return the previous state
|
|
*/
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* slotcp - copy up to 64 bits from a 64 bit array of FULLs to some HALFs
|
|
*
|
|
* We will copy data from an array of FULLs into an array of HALFs.
|
|
* The destination within the HALFs is some bit location found in bitstr.
|
|
* We will attempt to copy 64 bits, but if there is not enough room
|
|
* (bits not yet loaded) in the destination bit string we will transfer
|
|
* what we can.
|
|
*
|
|
* The src slot is 64 bits long and is stored as an array of FULLs.
|
|
* When FULL_BITS is 64 the element is 1 FULL, otherwise FULL_BITS
|
|
* is 32 bits and the element is 2 FULLs. The most significant bit
|
|
* in the array (highest bit in the last FULL of the array) is to
|
|
* be transfered to the most significant bit in the destination.
|
|
*
|
|
* given:
|
|
* bitstr - most significant destination bit in a bit string
|
|
* src - low order FULL in a 64 bit slot
|
|
* count - number of bits to transfer (must be 0 < count <= 64)
|
|
*
|
|
* returns:
|
|
* number of bits transfered
|
|
*/
|
|
static int
|
|
slotcp(BITSTR *bitstr, FULL *src, int count)
|
|
{
|
|
HALF *dh; /* most significant HALF in dest */
|
|
int dnxtbit; /* next bit beyond most signif in dh */
|
|
int need; /* number of bits we need to transfer */
|
|
int ret; /* bits transfered */
|
|
|
|
/*
|
|
* determine how many bits we actually need to transfer
|
|
*/
|
|
dh = bitstr->loc;
|
|
dnxtbit = bitstr->bit+1;
|
|
count &= (SBITS-1);
|
|
need = (bitstr->len < count) ? bitstr->len : count;
|
|
|
|
/*
|
|
* prepare for the return
|
|
*
|
|
* Note the final bitstr location after we have moved the
|
|
* position down 'need' bits.
|
|
*/
|
|
bitstr->len -= need;
|
|
bitstr->loc -= need / BASEB;
|
|
bitstr->bit -= need % BASEB;
|
|
if (bitstr->bit < 0) {
|
|
--bitstr->loc;
|
|
bitstr->bit += BASEB;
|
|
}
|
|
ret = need;
|
|
|
|
/*
|
|
* deal with aligned copies quickly
|
|
*/
|
|
if (dnxtbit == BASEB) {
|
|
if (need == SBITS) {
|
|
#if 2*FULL_BITS == SBITS
|
|
*dh-- = (HALF)(src[SLEN-1] >> BASEB);
|
|
*dh-- = (HALF)(src[SLEN-1]);
|
|
#endif
|
|
*dh-- = (HALF)(src[0] >> BASEB);
|
|
*dh = (HALF)(src[0]);
|
|
#if 2*FULL_BITS == SBITS
|
|
} else if (need > FULL_BITS+BASEB) {
|
|
*dh-- = (HALF)(src[SLEN-1] >> BASEB);
|
|
*dh-- = (HALF)(src[SLEN-1]);
|
|
*dh-- = (HALF)(src[0] >> BASEB);
|
|
*dh = ((HALF)src[0] &
|
|
highhalf[need-FULL_BITS-BASEB]);
|
|
} else if (need > FULL_BITS) {
|
|
*dh-- = (HALF)(src[SLEN-1] >> BASEB);
|
|
*dh-- = (HALF)(src[SLEN-1]);
|
|
*dh = ((HALF)(src[0] >> BASEB) &
|
|
highhalf[need-FULL_BITS]);
|
|
#endif
|
|
} else if (need > BASEB) {
|
|
*dh-- = (HALF)(src[SLEN-1] >> BASEB);
|
|
*dh = ((HALF)(src[SLEN-1]) & highhalf[need-BASEB]);
|
|
} else {
|
|
*dh = ((HALF)(src[SLEN-1] >> BASEB) & highhalf[need]);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* load the most significant HALF
|
|
*/
|
|
if (need >= dnxtbit) {
|
|
/* fill up the most significant HALF */
|
|
*dh-- |= (HALF)(src[SLEN-1] >> (FULL_BITS-dnxtbit));
|
|
need -= dnxtbit;
|
|
} else if (need > 0) {
|
|
/* we exhaust our need before 1st half is filled */
|
|
*dh |= (HALF)((src[SLEN-1] >> (FULL_BITS-need)) <<
|
|
(dnxtbit-need));
|
|
return ret; /* our need has been filled */
|
|
} else {
|
|
return ret; /* our need has been filled */
|
|
}
|
|
|
|
/*
|
|
* load the 2nd most significant HALF
|
|
*/
|
|
if (need > BASEB) {
|
|
/* fill up the 2nd most significant HALF */
|
|
*dh-- = (HALF)(src[SLEN-1] >> (BASEB-dnxtbit));
|
|
need -= BASEB;
|
|
} else if (need > 0) {
|
|
/* we exhaust our need before 2nd half is filled */
|
|
*dh |= ((HALF)(src[SLEN-1] >> (BASEB-dnxtbit)) &
|
|
highhalf[need]);
|
|
return ret; /* our need has been filled */
|
|
} else {
|
|
return ret; /* our need has been filled */
|
|
}
|
|
|
|
/*
|
|
* load the 3rd most significant HALF
|
|
*
|
|
* At this point we know that our 3rd HALF will force us
|
|
* to cross into a second FULL for systems with 32 bit FULLs.
|
|
* We know this because the aligned case has been previously
|
|
* taken care of above.
|
|
*
|
|
* For systems that have 64 bit FULLs (and 32 bit HALFs) this
|
|
* is will be our least significant HALF. We also know that
|
|
* the need must be < BASEB.
|
|
*/
|
|
#if FULL_BITS == SBITS
|
|
*dh |= (((HALF)src[0] & highhalf[dnxtbit+need]) << dnxtbit);
|
|
#else
|
|
if (need > BASEB) {
|
|
/* load the remaining bits from the most signif FULL */
|
|
*dh-- = ((((HALF)src[SLEN-1] & lowhalf[BASEB-dnxtbit])
|
|
<< dnxtbit) | (HALF)(src[0] >> (FULL_BITS-dnxtbit)));
|
|
need -= BASEB;
|
|
} else if (need > 0) {
|
|
/* load the remaining bits from the most signif FULL */
|
|
*dh-- |= (((((HALF)src[SLEN-1] & lowhalf[BASEB-dnxtbit])
|
|
<< dnxtbit) | (HALF)(src[0] >> (FULL_BITS-dnxtbit))) &
|
|
highhalf[need]);
|
|
return ret; /* our need has been filled */
|
|
} else {
|
|
return ret; /* our need has been filled */
|
|
}
|
|
|
|
/*
|
|
* load the 4th most significant HALF
|
|
*
|
|
* At this point, only 32 bit FULLs are operating.
|
|
*/
|
|
if (need > BASEB) {
|
|
/* fill up the 2nd most significant HALF */
|
|
*dh-- = (HALF)(src[0] >> (BASEB-dnxtbit));
|
|
/* no need todo: need -= BASEB, because we are nearly done */
|
|
} else if (need > 0) {
|
|
/* we exhaust our need before 2nd half is filled */
|
|
*dh |= ((HALF)(src[0] >> (BASEB-dnxtbit)) &
|
|
highhalf[need]);
|
|
return ret; /* our need has been filled */
|
|
} else {
|
|
return ret; /* our need has been filled */
|
|
}
|
|
|
|
/*
|
|
* load the 5th and least significant HALF
|
|
*
|
|
* At this point we know that the need will be satisfied.
|
|
*/
|
|
*dh |= (((HALF)src[0] & lowhalf[BASEB-dnxtbit]) << dnxtbit);
|
|
#endif
|
|
return ret; /* our need has been filled */
|
|
}
|
|
|
|
|
|
/*
|
|
* slotcp64 - copy 64 bits from a 64 bit array of FULLs to some HALFs
|
|
*
|
|
* We will copy data from an array of FULLs into an array of HALFs.
|
|
* The destination within the HALFs is some bit location found in bitstr.
|
|
* Unlike slotcp(), this function will always copy 64 bits.
|
|
*
|
|
* The src slot is 64 bits long and is stored as an array of FULLs.
|
|
* When FULL_BITS is 64 this array is 1 FULL, otherwise FULL_BITS
|
|
* is 32 bits and the array is 2 FULLs. The most significant bit
|
|
* in the array (highest bit in the last FULL of the array) is to
|
|
* be transfered to the most significant bit in the destination.
|
|
*
|
|
* given:
|
|
* bitstr - most significant destination bit in a bit string
|
|
* src - low order FULL in a 64 bit slot
|
|
*
|
|
* returns:
|
|
* number of bits transfered
|
|
*/
|
|
static void
|
|
slotcp64(BITSTR *bitstr, FULL *src)
|
|
{
|
|
HALF *dh = bitstr->loc; /* most significant HALF in dest */
|
|
int dnxtbit = bitstr->bit+1; /* next bit beyond most signif in dh */
|
|
|
|
/*
|
|
* prepare for the return
|
|
*
|
|
* Since we are moving the point 64 bits down, we know that
|
|
* the bit location (bitstr->bit) will remain the same.
|
|
*/
|
|
bitstr->len -= SBITS;
|
|
bitstr->loc -= SBITS/BASEB;
|
|
|
|
/*
|
|
* deal with aligned copies quickly
|
|
*/
|
|
if (dnxtbit == BASEB) {
|
|
#if 2*FULL_BITS == SBITS
|
|
*dh-- = (HALF)(src[SLEN-1] >> BASEB);
|
|
*dh-- = (HALF)(src[SLEN-1]);
|
|
#endif
|
|
*dh-- = (HALF)(src[0] >> BASEB);
|
|
*dh = (HALF)(src[0]);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* load the most significant HALF
|
|
*/
|
|
*dh-- |= (HALF)(src[SLEN-1] >> (FULL_BITS-dnxtbit));
|
|
|
|
/*
|
|
* load the 2nd most significant HALF
|
|
*/
|
|
*dh-- = (HALF)(src[SLEN-1] >> (BASEB-dnxtbit));
|
|
|
|
/*
|
|
* load the 3rd most significant HALF
|
|
*
|
|
* At this point we know that our 3rd HALF will force us
|
|
* to cross into a second FULL for systems with 32 bit FULLs.
|
|
* We know this because the aligned case has been previously
|
|
* taken care of above.
|
|
*
|
|
* For systems that have 64 bit FULLs (and 32 bit HALFs) this
|
|
* is will be our least significant HALF.
|
|
*/
|
|
#if FULL_BITS == SBITS
|
|
*dh |= (((HALF)src[0] & lowhalf[BASEB-dnxtbit]) << dnxtbit);
|
|
#else
|
|
/* load the remaining bits from the most signif FULL */
|
|
*dh-- = ((((HALF)src[SLEN-1] & lowhalf[BASEB-dnxtbit])
|
|
<< dnxtbit) | (HALF)(src[0] >> (FULL_BITS-dnxtbit)));
|
|
|
|
/*
|
|
* load the 4th most significant HALF
|
|
*
|
|
* At this point, only 32 bit FULLs are operating.
|
|
*/
|
|
*dh-- = (HALF)(src[0] >> (BASEB-dnxtbit));
|
|
|
|
/*
|
|
* load the 5th and least significant HALF
|
|
*
|
|
* At this point we know that the need will be satisfied.
|
|
*/
|
|
*dh |= (((HALF)src[0] & lowhalf[BASEB-dnxtbit]) << dnxtbit);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
* zrandskip - skip s s100 bits
|
|
*
|
|
* given:
|
|
* count - number of bits to be skipped
|
|
*/
|
|
void
|
|
zrandskip(long cnt)
|
|
{
|
|
int indx; /* shuffle entry index */
|
|
|
|
/*
|
|
* initialize state if first call
|
|
*/
|
|
if (!s100.seeded) {
|
|
s100 = init_s100;
|
|
}
|
|
|
|
/*
|
|
* skip required bits in the buffer
|
|
*/
|
|
if (s100.bits > 0 && s100.bits <= cnt) {
|
|
|
|
/* just toss the buffer bits */
|
|
cnt -= s100.bits;
|
|
s100.bits = 0;
|
|
memset(s100.buffer, 0, sizeof(s100.buffer));
|
|
|
|
} else if (s100.bits > 0 && s100.bits > cnt) {
|
|
|
|
/* buffer contains more bits than we need to toss */
|
|
#if FULL_BITS == SBITS
|
|
s100.buffer[0] <<= cnt;
|
|
#else
|
|
if (cnt >= FULL_BITS) {
|
|
s100.buffer[SLEN-1] = (s100.buffer[0] << cnt);
|
|
s100.buffer[0] = 0;
|
|
} else {
|
|
s100.buffer[SLEN-1] =
|
|
((s100.buffer[SLEN-1] << cnt) |
|
|
(s100.buffer[0] >> (FULL_BITS-cnt)));
|
|
s100.buffer[0] <<= cnt;
|
|
}
|
|
#endif
|
|
s100.bits -= cnt;
|
|
return; /* skip need satisfied */
|
|
}
|
|
|
|
/*
|
|
* skip 64 bits at a time
|
|
*/
|
|
while (cnt >= SBITS) {
|
|
|
|
/*
|
|
* skip values if required
|
|
*
|
|
* NOTE: This skip loop is part of the algorithm, not part
|
|
* of the builtin function request.
|
|
*
|
|
* See:
|
|
* Knuth's "The Art of Computer Programming -
|
|
* Seminumerical Algorithms", Vol 2, 3rd edition (1998),
|
|
* Section 3.6, page 188".
|
|
*/
|
|
if (s100.need_to_skip <= 0) {
|
|
int sk;
|
|
|
|
/* skip the require number of values */
|
|
for (sk=0; sk < RAND_SKIP; ++sk) {
|
|
/* bump j and k */
|
|
if (++s100.j >= S100) {
|
|
s100.j = 0;
|
|
}
|
|
if (++s100.k >= S100) {
|
|
s100.k = 0;
|
|
}
|
|
|
|
/* slot[k] -= slot[j] */
|
|
SSUB(s100, s100.k, s100.j);
|
|
|
|
/* store s100.k into s100.slot[indx] */
|
|
indx = SINDX(s100, s100.k);
|
|
SSHUF(s100, indx, s100.k);
|
|
}
|
|
|
|
/* reset the skip count */
|
|
s100.need_to_skip = RAND_CONSEQ_USE;
|
|
if (conf->calc_debug & CALCDBG_RAND) {
|
|
printf("rand: skipped %d states\n", RAND_SKIP);
|
|
}
|
|
|
|
/* no skip, just descrment use counter */
|
|
} else {
|
|
--s100.need_to_skip;
|
|
}
|
|
|
|
/* bump j and k */
|
|
if (++s100.j >= S100) {
|
|
s100.j = 0;
|
|
}
|
|
if (++s100.k >= S100) {
|
|
s100.k = 0;
|
|
}
|
|
|
|
/* slot[k] -= slot[j] */
|
|
SSUB(s100, s100.k, s100.j);
|
|
|
|
/* we will ignore the output value of s100.slot[indx] */
|
|
indx = SINDX(s100, s100.k);
|
|
cnt -= SBITS;
|
|
|
|
/* store s100.k into s100.slot[indx] */
|
|
SSHUF(s100, indx, s100.k);
|
|
}
|
|
|
|
/*
|
|
* skip the final bits
|
|
*/
|
|
if (cnt > 0) {
|
|
|
|
/*
|
|
* skip values if required
|
|
*
|
|
* NOTE: This skip loop is part of the algorithm, not part
|
|
* of the builtin function request.
|
|
*
|
|
* See:
|
|
* Knuth's "The Art of Computer Programming -
|
|
* Seminumerical Algorithms", Vol 2, 3rd edition (1998),
|
|
* Section 3.6, page 188".
|
|
*/
|
|
if (s100.need_to_skip <= 0) {
|
|
int sk;
|
|
|
|
/* skip the require number of values */
|
|
for (sk=0; sk < RAND_SKIP; ++sk) {
|
|
|
|
/* bump j and k */
|
|
if (++s100.j >= S100) {
|
|
s100.j = 0;
|
|
}
|
|
if (++s100.k >= S100) {
|
|
s100.k = 0;
|
|
}
|
|
|
|
/* slot[k] -= slot[j] */
|
|
SSUB(s100, s100.k, s100.j);
|
|
|
|
/* store s100.k into s100.slot[indx] */
|
|
indx = SINDX(s100, s100.k);
|
|
SSHUF(s100, indx, s100.k);
|
|
}
|
|
|
|
/* reset the skip count */
|
|
s100.need_to_skip = RAND_CONSEQ_USE;
|
|
if (conf->calc_debug & CALCDBG_RAND) {
|
|
printf("rand: skipped %d states\n", RAND_SKIP);
|
|
}
|
|
|
|
/* no skip, just descrment use counter */
|
|
} else {
|
|
--s100.need_to_skip;
|
|
}
|
|
|
|
/* bump j and k */
|
|
if (++s100.j >= S100) {
|
|
s100.j = 0;
|
|
}
|
|
if (++s100.k >= S100) {
|
|
s100.k = 0;
|
|
}
|
|
|
|
/* slot[k] -= slot[j] */
|
|
SSUB(s100, s100.k, s100.j);
|
|
|
|
/* we will ignore the output value of s100.slot[indx] */
|
|
indx = SINDX(s100, s100.k);
|
|
|
|
/*
|
|
* We know the buffer is empty, so fill it
|
|
* with any unused bits. Copy SBITS-trans bits
|
|
* from slot[indx] into buffer.
|
|
*/
|
|
s100.bits = (int)(SBITS-cnt);
|
|
memcpy(s100.buffer, &s100.shuf[indx*SLEN],
|
|
sizeof(s100.buffer));
|
|
|
|
/*
|
|
* shift the buffer bits all the way up to
|
|
* the most significant bit
|
|
*/
|
|
#if FULL_BITS == SBITS
|
|
s100.buffer[0] <<= cnt;
|
|
#else
|
|
if (cnt >= FULL_BITS) {
|
|
s100.buffer[SLEN-1] = (s100.buffer[0] << cnt);
|
|
s100.buffer[0] = 0;
|
|
} else {
|
|
s100.buffer[SLEN-1] =
|
|
((s100.buffer[SLEN-1] << cnt) |
|
|
(s100.buffer[0] >> (FULL_BITS-cnt)));
|
|
s100.buffer[0] <<= cnt;
|
|
}
|
|
#endif
|
|
|
|
/* store s100.k into s100.slot[indx] */
|
|
SSHUF(s100, indx, s100.k);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* zrand - crank the s100 generator for some bits
|
|
*
|
|
* We will load the ZVALUE with random bits starting from the
|
|
* most significant and ending with the lowest bit in the
|
|
* least significant HALF.
|
|
*
|
|
* given:
|
|
* count - number of bits required
|
|
* res - where to place the random bits as ZVALUE
|
|
*/
|
|
void
|
|
zrand(long cnt, ZVALUE *res)
|
|
{
|
|
BITSTR dest; /* destination bit string */
|
|
int trans; /* bits transfered */
|
|
int indx; /* shuffle entry index */
|
|
|
|
/*
|
|
* firewall
|
|
*/
|
|
if (cnt <= 0) {
|
|
if (cnt == 0) {
|
|
/* zero length random number is always 0 */
|
|
itoz(0, res);
|
|
return;
|
|
} else {
|
|
math_error("negative zrand bit count");
|
|
/*NOTREACHED*/
|
|
}
|
|
#if LONG_BITS > 32
|
|
} else if (cnt > (1L<<31)) {
|
|
math_error("huge rand bit count in internal zrand function");
|
|
/*NOTREACHED*/
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* initialize state if first call
|
|
*/
|
|
if (!s100.seeded) {
|
|
s100 = init_s100;
|
|
}
|
|
|
|
/*
|
|
* allocate storage
|
|
*/
|
|
res->len = (LEN)((cnt+BASEB-1)/BASEB);
|
|
res->v = alloc((LEN)((cnt+BASEB-1)/BASEB));
|
|
|
|
/*
|
|
* dest bit string
|
|
*/
|
|
dest.len = (int)cnt;
|
|
dest.loc = res->v + (((cnt+BASEB-1)/BASEB)-1);
|
|
dest.bit = (int)((cnt-1) % BASEB);
|
|
memset(res->v, 0, (LEN)((cnt+BASEB-1)/BASEB)*sizeof(HALF));
|
|
|
|
/*
|
|
* load from buffer first
|
|
*/
|
|
if (s100.bits > 0) {
|
|
|
|
/*
|
|
* We know there are only s100.bits in the buffer, so
|
|
* transfer as much as we can (treating it as a slot)
|
|
* and return the bit transfer count.
|
|
*/
|
|
trans = slotcp(&dest, s100.buffer, s100.bits);
|
|
|
|
/*
|
|
* If we need to keep bits in the buffer,
|
|
* shift the buffer bits all the way up to
|
|
* the most significant unused bit.
|
|
*/
|
|
if (trans < s100.bits) {
|
|
#if FULL_BITS == SBITS
|
|
s100.buffer[0] <<= trans;
|
|
#else
|
|
if (trans >= FULL_BITS) {
|
|
s100.buffer[SLEN-1] =
|
|
(s100.buffer[0] << (trans-FULL_BITS));
|
|
s100.buffer[0] = 0;
|
|
} else {
|
|
s100.buffer[SLEN-1] =
|
|
((s100.buffer[SLEN-1] << trans) |
|
|
(s100.buffer[0] >> (FULL_BITS-trans)));
|
|
s100.buffer[0] <<= trans;
|
|
}
|
|
#endif
|
|
}
|
|
/* note that we have fewer bits in the buffer */
|
|
s100.bits -= trans;
|
|
}
|
|
|
|
/*
|
|
* spin the generator until we need less than 64 bits
|
|
*
|
|
* The buffer did not contain enough bits, so we crank the
|
|
* s100 generator and load then 64 bits at a time.
|
|
*/
|
|
while (dest.len >= SBITS) {
|
|
|
|
/*
|
|
* skip values if required
|
|
*
|
|
* See:
|
|
* Knuth's "The Art of Computer Programming -
|
|
* Seminumerical Algorithms", Vol 2, 3rd edition (1998),
|
|
* Section 3.6, page 188".
|
|
*/
|
|
if (s100.need_to_skip <= 0) {
|
|
int sk;
|
|
|
|
/* skip the require number of values */
|
|
for (sk=0; sk < RAND_SKIP; ++sk) {
|
|
|
|
/* bump j and k */
|
|
if (++s100.j >= S100) {
|
|
s100.j = 0;
|
|
}
|
|
if (++s100.k >= S100) {
|
|
s100.k = 0;
|
|
}
|
|
|
|
/* slot[k] -= slot[j] */
|
|
SSUB(s100, s100.k, s100.j);
|
|
|
|
/* select slot index to output */
|
|
indx = SINDX(s100, s100.k);
|
|
|
|
/* store s100.k into s100.slot[indx] */
|
|
SSHUF(s100, indx, s100.k);
|
|
}
|
|
|
|
/* reset the skip count */
|
|
s100.need_to_skip = RAND_CONSEQ_USE;
|
|
if (conf->calc_debug & CALCDBG_RAND) {
|
|
printf("rand: skipped %d states\n", RAND_SKIP);
|
|
}
|
|
|
|
/* no skip, just descrment use counter */
|
|
} else {
|
|
--s100.need_to_skip;
|
|
}
|
|
|
|
/* bump j and k */
|
|
if (++s100.j >= S100) {
|
|
s100.j = 0;
|
|
}
|
|
if (++s100.k >= S100) {
|
|
s100.k = 0;
|
|
}
|
|
|
|
/* slot[k] -= slot[j] */
|
|
SSUB(s100, s100.k, s100.j);
|
|
|
|
/* select slot index to output */
|
|
indx = SINDX(s100, s100.k);
|
|
|
|
/* move up to 64 bits from slot[indx] to dest */
|
|
slotcp64(&dest, &s100.shuf[indx*SLEN]);
|
|
|
|
/* store s100.k into s100.slot[indx] */
|
|
SSHUF(s100, indx, s100.k);
|
|
}
|
|
|
|
/*
|
|
* spin the generator one last time to fill out the remaining need
|
|
*/
|
|
if (dest.len > 0) {
|
|
|
|
/*
|
|
* skip values if required
|
|
*
|
|
* See:
|
|
* Knuth's "The Art of Computer Programming -
|
|
* Seminumerical Algorithms", Vol 2, 3rd edition (1998),
|
|
* Section 3.6, page 188".
|
|
*/
|
|
if (s100.need_to_skip <= 0) {
|
|
int sk;
|
|
|
|
/* skip the require number of values */
|
|
for (sk=0; sk < RAND_SKIP; ++sk) {
|
|
/* bump j and k */
|
|
if (++s100.j >= S100) {
|
|
s100.j = 0;
|
|
}
|
|
if (++s100.k >= S100) {
|
|
s100.k = 0;
|
|
}
|
|
|
|
/* slot[k] -= slot[j] */
|
|
SSUB(s100, s100.k, s100.j);
|
|
|
|
/* select slot index to output */
|
|
indx = SINDX(s100, s100.k);
|
|
|
|
/* store s100.k into s100.slot[indx] */
|
|
SSHUF(s100, indx, s100.k);
|
|
}
|
|
|
|
/* reset the skip count */
|
|
s100.need_to_skip = RAND_CONSEQ_USE;
|
|
if (conf->calc_debug & CALCDBG_RAND) {
|
|
printf("rand: skipped %d states\n", RAND_SKIP);
|
|
}
|
|
|
|
/* no skip, just descrment use counter */
|
|
} else {
|
|
--s100.need_to_skip;
|
|
}
|
|
|
|
/* bump j and k */
|
|
if (++s100.j >= S100) {
|
|
s100.j = 0;
|
|
}
|
|
if (++s100.k >= S100) {
|
|
s100.k = 0;
|
|
}
|
|
|
|
/* slot[k] -= slot[j] */
|
|
SSUB(s100, s100.k, s100.j);
|
|
|
|
/* select slot index to output */
|
|
indx = SINDX(s100, s100.k);
|
|
|
|
/* move up to 64 bits from slot[indx] to dest */
|
|
trans = slotcp(&dest, &s100.shuf[indx*SLEN], dest.len);
|
|
|
|
/* buffer up unused bits if we are done */
|
|
if (trans != SBITS) {
|
|
|
|
/*
|
|
* We know the buffer is empty, so fill it
|
|
* with any unused bits. Copy SBITS-trans bits
|
|
* from slot[indx] into buffer.
|
|
*/
|
|
s100.bits = SBITS-trans;
|
|
memcpy(s100.buffer, &s100.shuf[indx*SLEN],
|
|
sizeof(s100.buffer));
|
|
|
|
/*
|
|
* shift the buffer bits all the way up to
|
|
* the most significant bit
|
|
*/
|
|
#if FULL_BITS == SBITS
|
|
s100.buffer[0] <<= trans;
|
|
#else
|
|
if (trans >= FULL_BITS) {
|
|
s100.buffer[SLEN-1] =
|
|
(s100.buffer[0] << (trans-FULL_BITS));
|
|
s100.buffer[0] = 0;
|
|
} else {
|
|
s100.buffer[SLEN-1] =
|
|
((s100.buffer[SLEN-1] << trans) |
|
|
(s100.buffer[0] >> (FULL_BITS-trans)));
|
|
s100.buffer[0] <<= trans;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* store s100.k into s100.slot[indx] */
|
|
SSHUF(s100, indx, s100.k);
|
|
}
|
|
res->sign = 0;
|
|
ztrim(res);
|
|
}
|
|
|
|
|
|
/*
|
|
* zrandrange - generate an s100 random value in the range [low, high)
|
|
*
|
|
* given:
|
|
* low - low value of range
|
|
* high - beyond end of range
|
|
* res - where to place the random bits as ZVALUE
|
|
*/
|
|
void
|
|
zrandrange(CONST ZVALUE low, CONST ZVALUE high, ZVALUE *res)
|
|
{
|
|
ZVALUE range; /* high-low */
|
|
ZVALUE rval; /* random value [0, 2^bitlen) */
|
|
ZVALUE rangem1; /* range - 1 */
|
|
long bitlen; /* smallest power of 2 >= diff */
|
|
|
|
/*
|
|
* firewall
|
|
*/
|
|
if (zrel(low, high) >= 0) {
|
|
math_error("srand low range >= high range");
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
/*
|
|
* determine the size of the random number needed
|
|
*/
|
|
zsub(high, low, &range);
|
|
if (zisone(range)) {
|
|
zfree(range);
|
|
*res = low;
|
|
return;
|
|
}
|
|
zsub(range, _one_, &rangem1);
|
|
bitlen = 1+zhighbit(rangem1);
|
|
zfree(rangem1);
|
|
|
|
/*
|
|
* generate a random value between [0, diff)
|
|
*
|
|
* We will not fall into the trap of thinking that we can simply take
|
|
* a value mod 'range'. Consider the case where 'range' is '80'
|
|
* and we are given pseudo-random numbers [0,100). If we took them
|
|
* mod 80, then the numbers [0,20) would be produced more frequently
|
|
* because the numbers [81,100) mod 80 wrap back into [0,20).
|
|
*/
|
|
rval.v = NULL;
|
|
do {
|
|
if (rval.v != NULL) {
|
|
zfree(rval);
|
|
}
|
|
zrand(bitlen, &rval);
|
|
} while (zrel(rval, range) >= 0);
|
|
|
|
/*
|
|
* add in low value to produce the range [0+low, diff+low)
|
|
* which is the range [low, high)
|
|
*/
|
|
zadd(rval, low, res);
|
|
zfree(rval);
|
|
zfree(range);
|
|
}
|
|
|
|
|
|
/*
|
|
* irand - generate an s100 random long in the range [0, s)
|
|
*
|
|
* given:
|
|
* s - limit of the range
|
|
*
|
|
* returns:
|
|
* random long in the range [0, s)
|
|
*/
|
|
long
|
|
irand(long s)
|
|
{
|
|
ZVALUE z1, z2;
|
|
long res;
|
|
|
|
if (s <= 0) {
|
|
math_error("Non-positive argument for irand()");
|
|
/*NOTREACHED*/
|
|
}
|
|
if (s == 1)
|
|
return 0;
|
|
itoz(s, &z1);
|
|
zrandrange(_zero_, z1, &z2);
|
|
res = ztoi(z2);
|
|
zfree(z1);
|
|
zfree(z2);
|
|
return res;
|
|
}
|
|
|
|
|
|
/*
|
|
* randcopy - make a copy of an s100 state
|
|
*
|
|
* given:
|
|
* state - the state to copy
|
|
*
|
|
* returns:
|
|
* a malloced copy of the state
|
|
*/
|
|
RAND *
|
|
randcopy(CONST RAND *state)
|
|
{
|
|
RAND *ret; /* return copy of state */
|
|
|
|
/*
|
|
* malloc state
|
|
*/
|
|
ret = (RAND *)malloc(sizeof(RAND));
|
|
if (ret == NULL) {
|
|
math_error("can't allocate RAND state");
|
|
/*NOTREACHED*/
|
|
}
|
|
memcpy(ret, state, sizeof(RAND));
|
|
|
|
/*
|
|
* return copy
|
|
*/
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* randfree - free an s100 state
|
|
*
|
|
* given:
|
|
* state - the state to free
|
|
*/
|
|
void
|
|
randfree(RAND *state)
|
|
{
|
|
/* free it */
|
|
free(state);
|
|
}
|
|
|
|
|
|
/*
|
|
* randcmp - compare two s100 states
|
|
*
|
|
* given:
|
|
* s1 - first state to compare
|
|
* s2 - second state to compare
|
|
*
|
|
* return:
|
|
* TRUE if states differ
|
|
*/
|
|
BOOL
|
|
randcmp(CONST RAND *s1, CONST RAND *s2)
|
|
{
|
|
/*
|
|
* assume uninitialized state == the default seeded state
|
|
*/
|
|
if (!s1->seeded) {
|
|
if (!s2->seeded) {
|
|
/* uninitialized == uninitialized */
|
|
return FALSE;
|
|
} else {
|
|
/* uninitialized only equals default state */
|
|
return randcmp(s2, &init_s100);
|
|
}
|
|
} else if (!s2->seeded) {
|
|
/* uninitialized only equals default state */
|
|
return randcmp(s1, &init_s100);
|
|
}
|
|
|
|
/* compare states */
|
|
return (BOOL)(memcmp(s1, s2, sizeof(RAND)) != 0);
|
|
}
|
|
|
|
|
|
/*
|
|
* randprint - print an s100 state
|
|
*
|
|
* given:
|
|
* state - state to print
|
|
* flags - print flags passed from printvalue() in value.c
|
|
*/
|
|
/*ARGSUSED*/
|
|
void
|
|
randprint(CONST RAND *state, int flags)
|
|
{
|
|
math_str("RAND state");
|
|
}
|