xref: /freebsd-src/contrib/arm-optimized-routines/math/test/rtest/random.c (revision 072a4ba82a01476eaee33781ccd241033eefcf0b)
131914882SAlex Richardson /*
231914882SAlex Richardson  * random.c - random number generator for producing mathlib test cases
331914882SAlex Richardson  *
431914882SAlex Richardson  * Copyright (c) 1998-2019, Arm Limited.
5*072a4ba8SAndrew Turner  * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
631914882SAlex Richardson  */
731914882SAlex Richardson 
831914882SAlex Richardson #include "types.h"
931914882SAlex Richardson #include "random.h"
1031914882SAlex Richardson 
1131914882SAlex Richardson static uint32 seedbuf[55];
1231914882SAlex Richardson static int seedptr;
1331914882SAlex Richardson 
seed_random(uint32 seed)1431914882SAlex Richardson void seed_random(uint32 seed) {
1531914882SAlex Richardson     int i;
1631914882SAlex Richardson 
1731914882SAlex Richardson     seedptr = 0;
1831914882SAlex Richardson     for (i = 0; i < 55; i++) {
1931914882SAlex Richardson         seed = seed % 44488 * 48271 - seed / 44488 * 3399;
2031914882SAlex Richardson         seedbuf[i] = seed - 1;
2131914882SAlex Richardson     }
2231914882SAlex Richardson }
2331914882SAlex Richardson 
base_random(void)2431914882SAlex Richardson uint32 base_random(void) {
2531914882SAlex Richardson     seedptr %= 55;
2631914882SAlex Richardson     seedbuf[seedptr] += seedbuf[(seedptr+31)%55];
2731914882SAlex Richardson     return seedbuf[seedptr++];
2831914882SAlex Richardson }
2931914882SAlex Richardson 
random32(void)3031914882SAlex Richardson uint32 random32(void) {
3131914882SAlex Richardson     uint32 a, b, b1, b2;
3231914882SAlex Richardson     a = base_random();
3331914882SAlex Richardson     b = base_random();
3431914882SAlex Richardson     for (b1 = 0x80000000, b2 = 1; b1 > b2; b1 >>= 1, b2 <<= 1) {
3531914882SAlex Richardson         uint32 b3 = b1 | b2;
3631914882SAlex Richardson         if ((b & b3) != 0 && (b & b3) != b3)
3731914882SAlex Richardson             b ^= b3;
3831914882SAlex Richardson     }
3931914882SAlex Richardson     return a ^ b;
4031914882SAlex Richardson }
4131914882SAlex Richardson 
4231914882SAlex Richardson /*
4331914882SAlex Richardson  * random_upto: generate a uniformly randomised number in the range
4431914882SAlex Richardson  * 0,...,limit-1. (Precondition: limit > 0.)
4531914882SAlex Richardson  *
4631914882SAlex Richardson  * random_upto_biased: generate a number in the same range, but with
4731914882SAlex Richardson  * the probability skewed towards the high end by means of taking the
4831914882SAlex Richardson  * maximum of 8*bias+1 samples from the uniform distribution on the
4931914882SAlex Richardson  * same range. (I don't know why bias is given in that curious way -
5031914882SAlex Richardson  * historical reasons, I expect.)
5131914882SAlex Richardson  *
5231914882SAlex Richardson  * For speed, I separate the implementation of random_upto into the
5331914882SAlex Richardson  * two stages of (a) generate a bitmask which reduces a 32-bit random
5431914882SAlex Richardson  * number to within a factor of two of the right range, (b) repeatedly
5531914882SAlex Richardson  * generate numbers in that range until one is small enough. Splitting
5631914882SAlex Richardson  * it up like that means that random_upto_biased can do (a) only once
5731914882SAlex Richardson  * even when it does (b) lots of times.
5831914882SAlex Richardson  */
5931914882SAlex Richardson 
random_upto_makemask(uint32 limit)6031914882SAlex Richardson static uint32 random_upto_makemask(uint32 limit) {
6131914882SAlex Richardson     uint32 mask = 0xFFFFFFFF;
6231914882SAlex Richardson     int i;
6331914882SAlex Richardson     for (i = 16; i > 0; i >>= 1)
6431914882SAlex Richardson         if ((limit & (mask >> i)) == limit)
6531914882SAlex Richardson             mask >>= i;
6631914882SAlex Richardson     return mask;
6731914882SAlex Richardson }
6831914882SAlex Richardson 
random_upto_internal(uint32 limit,uint32 mask)6931914882SAlex Richardson static uint32 random_upto_internal(uint32 limit, uint32 mask) {
7031914882SAlex Richardson     uint32 ret;
7131914882SAlex Richardson     do {
7231914882SAlex Richardson         ret = random32() & mask;
7331914882SAlex Richardson     } while (ret > limit);
7431914882SAlex Richardson     return ret;
7531914882SAlex Richardson }
7631914882SAlex Richardson 
random_upto(uint32 limit)7731914882SAlex Richardson uint32 random_upto(uint32 limit) {
7831914882SAlex Richardson     uint32 mask = random_upto_makemask(limit);
7931914882SAlex Richardson     return random_upto_internal(limit, mask);
8031914882SAlex Richardson }
8131914882SAlex Richardson 
random_upto_biased(uint32 limit,int bias)8231914882SAlex Richardson uint32 random_upto_biased(uint32 limit, int bias) {
8331914882SAlex Richardson     uint32 mask = random_upto_makemask(limit);
8431914882SAlex Richardson 
8531914882SAlex Richardson     uint32 ret = random_upto_internal(limit, mask);
8631914882SAlex Richardson     while (bias--) {
8731914882SAlex Richardson         uint32 tmp;
8831914882SAlex Richardson         tmp = random_upto_internal(limit, mask); if (tmp < ret) ret = tmp;
8931914882SAlex Richardson         tmp = random_upto_internal(limit, mask); if (tmp < ret) ret = tmp;
9031914882SAlex Richardson         tmp = random_upto_internal(limit, mask); if (tmp < ret) ret = tmp;
9131914882SAlex Richardson         tmp = random_upto_internal(limit, mask); if (tmp < ret) ret = tmp;
9231914882SAlex Richardson         tmp = random_upto_internal(limit, mask); if (tmp < ret) ret = tmp;
9331914882SAlex Richardson         tmp = random_upto_internal(limit, mask); if (tmp < ret) ret = tmp;
9431914882SAlex Richardson         tmp = random_upto_internal(limit, mask); if (tmp < ret) ret = tmp;
9531914882SAlex Richardson         tmp = random_upto_internal(limit, mask); if (tmp < ret) ret = tmp;
9631914882SAlex Richardson     }
9731914882SAlex Richardson 
9831914882SAlex Richardson     return ret;
9931914882SAlex Richardson }
100