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