xref: /aosp_15_r20/external/arm-optimized-routines/math/test/rtest/random.c (revision 412f47f9e737e10ed5cc46ec6a8d7fa2264f8a14)
1*412f47f9SXin Li /*
2*412f47f9SXin Li  * random.c - random number generator for producing mathlib test cases
3*412f47f9SXin Li  *
4*412f47f9SXin Li  * Copyright (c) 1998-2019, Arm Limited.
5*412f47f9SXin Li  * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
6*412f47f9SXin Li  */
7*412f47f9SXin Li 
8*412f47f9SXin Li #include "types.h"
9*412f47f9SXin Li #include "random.h"
10*412f47f9SXin Li 
11*412f47f9SXin Li static uint32 seedbuf[55];
12*412f47f9SXin Li static int seedptr;
13*412f47f9SXin Li 
seed_random(uint32 seed)14*412f47f9SXin Li void seed_random(uint32 seed) {
15*412f47f9SXin Li     int i;
16*412f47f9SXin Li 
17*412f47f9SXin Li     seedptr = 0;
18*412f47f9SXin Li     for (i = 0; i < 55; i++) {
19*412f47f9SXin Li         seed = seed % 44488 * 48271 - seed / 44488 * 3399;
20*412f47f9SXin Li         seedbuf[i] = seed - 1;
21*412f47f9SXin Li     }
22*412f47f9SXin Li }
23*412f47f9SXin Li 
base_random(void)24*412f47f9SXin Li uint32 base_random(void) {
25*412f47f9SXin Li     seedptr %= 55;
26*412f47f9SXin Li     seedbuf[seedptr] += seedbuf[(seedptr+31)%55];
27*412f47f9SXin Li     return seedbuf[seedptr++];
28*412f47f9SXin Li }
29*412f47f9SXin Li 
random32(void)30*412f47f9SXin Li uint32 random32(void) {
31*412f47f9SXin Li     uint32 a, b, b1, b2;
32*412f47f9SXin Li     a = base_random();
33*412f47f9SXin Li     b = base_random();
34*412f47f9SXin Li     for (b1 = 0x80000000, b2 = 1; b1 > b2; b1 >>= 1, b2 <<= 1) {
35*412f47f9SXin Li         uint32 b3 = b1 | b2;
36*412f47f9SXin Li         if ((b & b3) != 0 && (b & b3) != b3)
37*412f47f9SXin Li             b ^= b3;
38*412f47f9SXin Li     }
39*412f47f9SXin Li     return a ^ b;
40*412f47f9SXin Li }
41*412f47f9SXin Li 
42*412f47f9SXin Li /*
43*412f47f9SXin Li  * random_upto: generate a uniformly randomised number in the range
44*412f47f9SXin Li  * 0,...,limit-1. (Precondition: limit > 0.)
45*412f47f9SXin Li  *
46*412f47f9SXin Li  * random_upto_biased: generate a number in the same range, but with
47*412f47f9SXin Li  * the probability skewed towards the high end by means of taking the
48*412f47f9SXin Li  * maximum of 8*bias+1 samples from the uniform distribution on the
49*412f47f9SXin Li  * same range. (I don't know why bias is given in that curious way -
50*412f47f9SXin Li  * historical reasons, I expect.)
51*412f47f9SXin Li  *
52*412f47f9SXin Li  * For speed, I separate the implementation of random_upto into the
53*412f47f9SXin Li  * two stages of (a) generate a bitmask which reduces a 32-bit random
54*412f47f9SXin Li  * number to within a factor of two of the right range, (b) repeatedly
55*412f47f9SXin Li  * generate numbers in that range until one is small enough. Splitting
56*412f47f9SXin Li  * it up like that means that random_upto_biased can do (a) only once
57*412f47f9SXin Li  * even when it does (b) lots of times.
58*412f47f9SXin Li  */
59*412f47f9SXin Li 
random_upto_makemask(uint32 limit)60*412f47f9SXin Li static uint32 random_upto_makemask(uint32 limit) {
61*412f47f9SXin Li     uint32 mask = 0xFFFFFFFF;
62*412f47f9SXin Li     int i;
63*412f47f9SXin Li     for (i = 16; i > 0; i >>= 1)
64*412f47f9SXin Li         if ((limit & (mask >> i)) == limit)
65*412f47f9SXin Li             mask >>= i;
66*412f47f9SXin Li     return mask;
67*412f47f9SXin Li }
68*412f47f9SXin Li 
random_upto_internal(uint32 limit,uint32 mask)69*412f47f9SXin Li static uint32 random_upto_internal(uint32 limit, uint32 mask) {
70*412f47f9SXin Li     uint32 ret;
71*412f47f9SXin Li     do {
72*412f47f9SXin Li         ret = random32() & mask;
73*412f47f9SXin Li     } while (ret > limit);
74*412f47f9SXin Li     return ret;
75*412f47f9SXin Li }
76*412f47f9SXin Li 
random_upto(uint32 limit)77*412f47f9SXin Li uint32 random_upto(uint32 limit) {
78*412f47f9SXin Li     uint32 mask = random_upto_makemask(limit);
79*412f47f9SXin Li     return random_upto_internal(limit, mask);
80*412f47f9SXin Li }
81*412f47f9SXin Li 
random_upto_biased(uint32 limit,int bias)82*412f47f9SXin Li uint32 random_upto_biased(uint32 limit, int bias) {
83*412f47f9SXin Li     uint32 mask = random_upto_makemask(limit);
84*412f47f9SXin Li 
85*412f47f9SXin Li     uint32 ret = random_upto_internal(limit, mask);
86*412f47f9SXin Li     while (bias--) {
87*412f47f9SXin Li         uint32 tmp;
88*412f47f9SXin Li         tmp = random_upto_internal(limit, mask); if (tmp < ret) ret = tmp;
89*412f47f9SXin Li         tmp = random_upto_internal(limit, mask); if (tmp < ret) ret = tmp;
90*412f47f9SXin Li         tmp = random_upto_internal(limit, mask); if (tmp < ret) ret = tmp;
91*412f47f9SXin Li         tmp = random_upto_internal(limit, mask); if (tmp < ret) ret = tmp;
92*412f47f9SXin Li         tmp = random_upto_internal(limit, mask); if (tmp < ret) ret = tmp;
93*412f47f9SXin Li         tmp = random_upto_internal(limit, mask); if (tmp < ret) ret = tmp;
94*412f47f9SXin Li         tmp = random_upto_internal(limit, mask); if (tmp < ret) ret = tmp;
95*412f47f9SXin Li         tmp = random_upto_internal(limit, mask); if (tmp < ret) ret = tmp;
96*412f47f9SXin Li     }
97*412f47f9SXin Li 
98*412f47f9SXin Li     return ret;
99*412f47f9SXin Li }
100