home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Portions stolen from 'xphoon' with grateful acknowledgement AND
- ** Portions written by Tim Bray are
- ** Copyright (C) 1988 by Jef Poskanzer and Craig Leres.
- **
- ** Permission to use, copy, modify, and distribute this software and its
- ** documentation for any purpose and without fee is hereby granted, provided
- ** that the above copyright notice appear in all copies and that both that
- ** copyright notice and this permission notice appear in supporting
- ** documentation. This software is provided "as is" without express or
- ** implied warranty.
- */
-
- #include <X11/Xos.h>
-
- /*
- * genbits(p, bytecount, bits) - fills the char array 'bits', which is of size
- * 'bytecount', with bits each of of which is on with probability not too far
- * from p.
- *
- * This is quite a lot of bits; at least a million. Calling random() this
- * many times is slow, sez the profiler. For this reason, the random bits
- * are generated eight at a time. It is easy to calculate the probability
- * of N bits in a byte being on as a function of p. An array of 1024 chars
- * is filled with numbers from 0 to 8 inclusive in numbers proportional to
- * the probability of a byte having that many bits on. Ten bits of random
- * number index this array and select the number of bits to be on in the next
- * byte. Once the number of on-bits is selected, another random number is
- * used to select which byte to use among all the bytes with that many bits
- * on. For fear that something might not be relatively prime with something
- * else, the same random number is not used for the two indexing operations -
- * this is almost certainly unnecessary caution.
- *
- * There is a slight loss due to quantizing the probability domain into
- * 1024 slots. For example if p is less than about .43, this will never
- * generate a byte of all 1's. An earlier version, which called random()
- * once per bit, would in fact do this a few times in a million, as the
- * combinatorics say it should. Note that the possible bit counts can be
- * encoded in 4 bits, so you could quantize into 2048 or 4096 chunks without
- * wasting too much memory. However, I went cross-eyed alternating my screen
- * back and forth between the two versions and couldn't convince myself that
- * there was a difference. And this version (with the tenbits() trick)
- * has 24 times fewer calls to random and is dramatically faster. Have to
- * show this to a real mathematician who understands what a random number is
- * and dodge the flying vomit.
- */
- /* Static precomputed data for genbits */
- /* bytes with this many bits on */
- static int BytesWithCount0[] = { 0 };
- static int BytesWithCount1[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
- static int BytesWithCount2[] =
- {
- 3, 5, 6, 9, 10, 12, 17, 18, 20, 24, 33, 34, 36, 40, 48, 65, 66, 68, 72, 80,
- 96, 129, 130, 132, 136, 144, 160, 192
- };
- static int BytesWithCount3[] =
- {
- 7, 11, 13, 14, 19, 21, 22, 25, 26, 28, 35, 37, 38, 41, 42, 44, 49, 50, 52,
- 56, 67, 69, 70, 73, 74, 76, 81, 82, 84, 88, 97, 98, 100, 104, 112, 131, 133,
- 134, 137, 138, 140, 145, 146, 148, 152, 161, 162, 164, 168, 176, 193, 194,
- 196, 200, 208, 224
- };
- static int BytesWithCount4[] =
- {
- 15, 23, 27, 29, 30, 39, 43, 45, 46, 51, 53, 54, 57, 58, 60, 71, 75, 77, 78,
- 83, 85, 86, 89, 90, 92, 99, 101, 102, 105, 106, 108, 113, 114, 116, 120, 135,
- 139, 141, 142, 147, 149, 150, 153, 154, 156, 163, 165, 166, 169, 170, 172,
- 177, 178, 180, 184, 195, 197, 198, 201, 202, 204, 209, 210, 212, 216, 225,
- 226, 228, 232, 240
- };
- static int BytesWithCount5[] =
- {
- 31, 47, 55, 59, 61, 62, 79, 87, 91, 93, 94, 103, 107, 109, 110, 115, 117,
- 118, 121, 122, 124, 143, 151, 155, 157, 158, 167, 171, 173, 174, 179, 181,
- 182, 185, 186, 188, 199, 203, 205, 206, 211, 213, 214, 217, 218, 220, 227,
- 229, 230, 233, 234, 236, 241, 242, 244, 248
- };
- static int BytesWithCount6[] =
- {
- 63, 95, 111, 119, 123, 125, 126, 159, 175, 183, 187, 189, 190, 207, 215, 219,
- 221, 222, 231, 235, 237, 238, 243, 245, 246, 249, 250, 252
- };
- static int BytesWithCount7[] = { 127, 191, 223, 239, 247, 251, 253, 254 };
- static int BytesWithCount8[] = { 255 };
-
- static int * BytesWithCount[] =
- {
- BytesWithCount0, BytesWithCount1, BytesWithCount2, BytesWithCount3,
- BytesWithCount4, BytesWithCount5, BytesWithCount6, BytesWithCount7,
- BytesWithCount8
- };
-
- /* Eight choose whatever - also the sizes of the BytesWith arrays */
- static int EightChoose[] = { 1, 8, 28, 56, 70, 56, 28, 8, 1 };
-
- extern time_t time();
- extern long random();
-
- void
- genbits(p, bytecount, bits)
- double p;
- int bytecount;
- register char * bits;
- {
- char bitcounts[1024];
- register int count;
- int i;
- int j;
- int k;
- register int last;
- int maxbitcount;
- int PartOfK[9];
- double PToThe[9];
- double probability;
- double QToThe[9];
- register int selector;
- register char * stop;
-
- /* Compute the probabilities of bit counts 0 through 8 */
- /* first, work out the powers of p and 1-p */
- PToThe[0] = QToThe[0] = 1.0;
- for (i = 1; i <= 8; i++)
- { /* for each bit count */
- PToThe[i] = PToThe[i - 1] * p;
- QToThe[i] = QToThe[i - 1] * (1.0 - p);
- } /* for each bit count */
-
- /* the probability of i bits being on is (8 choose i) * p**i * q**(8-i) */
- count = maxbitcount = 0;
- for (i = 0; i <= 8; i++)
- { /* for each bit count */
- probability = ((double) EightChoose[i]) * PToThe[i] * QToThe[8 - i];
- PartOfK[i] = (int) (1024.0 * probability);
- if (PartOfK[i] > PartOfK[maxbitcount])
- maxbitcount = i;
- count += PartOfK[i];
- } /* for each bit count */
-
- /* might not come to 1024 because of rounding error; correct largest */
- if (count != 1024)
- PartOfK[maxbitcount] += 1024 - count;
-
- /* Load up bitcount array with appropriate numbers of different counts */
- for(i = 0, j = 0; i <= 8; i++)
- for (k = 0; k < PartOfK[i]; k++)
- bitcounts[j++] = i;
-
- /* Set up and let 'er rip */
- srandom((int) time((time_t *) 0));
- last = tenbits();
- stop = bits + bytecount;
- while (bits < stop)
- { /* for each byte */
-
- /* select bit count depending on probability */
- selector = tenbits();
- count = bitcounts[selector];
-
- /* use a randomly selected byte with that many bits on */
- if (count == 0)
- count = 0;
- else if (count == 8)
- count = 0xff;
- else
- count = BytesWithCount[count][last % EightChoose[count]];
- *bits++ = count;
-
- /* remember the random number to re-use next time */
- last = selector;
-
- } /* for each byte */
- }
-
- /*
- * Returns ten random bits. Since it is expensive to call random(), and we
- * only need ten bits per, and random gives us 31 bits per call, why waste
- * the other 20?
- */
- static int
- tenbits()
- {
- static int onetwothree = 3;
- static int ranbits;
-
- /* use random() every third call; shift 10 bits over on the other two */
- if (onetwothree == 3)
- {
- ranbits = random();
- onetwothree = 1;
- }
- else
- {
- ranbits >>= 10;
- onetwothree++;
- }
-
- return ranbits & 1023;
- }
-