Alex Converse | 9d068c1 | 2017-08-03 11:48:19 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2017, Alliance for Open Media. All rights reserved |
| 3 | * |
| 4 | * This source code is subject to the terms of the BSD 2 Clause License and |
| 5 | * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License |
| 6 | * was not distributed with this source code in the LICENSE file, you can |
| 7 | * obtain it at www.aomedia.org/license/software. If the Alliance for Open |
| 8 | * Media Patent License 1.0 was not distributed with this source code in the |
| 9 | * PATENTS file, you can obtain it at www.aomedia.org/license/patent. |
| 10 | */ |
| 11 | |
James Zern | e1cbb13 | 2018-08-22 14:10:36 -0700 | [diff] [blame] | 12 | #ifndef AOM_AV1_ENCODER_RANDOM_H_ |
| 13 | #define AOM_AV1_ENCODER_RANDOM_H_ |
Alex Converse | 9d068c1 | 2017-08-03 11:48:19 -0700 | [diff] [blame] | 14 | |
Rachel Barker | 021f148 | 2023-02-22 22:32:06 +0000 | [diff] [blame] | 15 | #include <stdint.h> |
| 16 | |
Alex Converse | 9d068c1 | 2017-08-03 11:48:19 -0700 | [diff] [blame] | 17 | #ifdef __cplusplus |
| 18 | extern "C" { |
| 19 | #endif |
| 20 | |
Rachel Barker | 021f148 | 2023-02-22 22:32:06 +0000 | [diff] [blame] | 21 | // Advance the generator to its next state, and generate the next 32-bit output. |
| 22 | // Note that the low bits of this output are comparatively low-quality, so users |
| 23 | // of this function should ensure that the high bits factor through to their |
| 24 | // outputs. |
| 25 | static INLINE uint32_t lcg_next(uint32_t *state) { |
| 26 | *state = (uint32_t)(*state * 1103515245ULL + 12345); |
| 27 | return *state; |
| 28 | } |
| 29 | |
Alex Converse | 9d068c1 | 2017-08-03 11:48:19 -0700 | [diff] [blame] | 30 | // Generate a random number in the range [0, 32768). |
Rachel Barker | 021f148 | 2023-02-22 22:32:06 +0000 | [diff] [blame] | 31 | static INLINE uint32_t lcg_rand16(uint32_t *state) { |
| 32 | return (lcg_next(state) / 65536) % 32768; |
| 33 | } |
| 34 | |
| 35 | // Generate a random number in the range [0, n) |
| 36 | // This is implemented as (rand() * n) / <range of RNG> rather than |
| 37 | // rand() % n, for a few reasons: This implementation is faster and less biased, |
| 38 | // and if is a power of 2, this uses the higher-quality top bits from the RNG |
| 39 | // output rather than the lower-quality bottom bits. |
| 40 | static INLINE uint32_t lcg_randint(uint32_t *state, uint32_t n) { |
| 41 | uint64_t v = ((uint64_t)lcg_next(state) * n) >> 32; |
| 42 | return (uint32_t)v; |
| 43 | } |
| 44 | |
| 45 | // Generate a random number in the range [lo, hi) |
| 46 | static INLINE uint32_t lcg_randrange(uint32_t *state, uint32_t lo, |
| 47 | uint32_t hi) { |
| 48 | assert(lo < hi); |
| 49 | return lo + lcg_randint(state, hi - lo); |
Alex Converse | 9d068c1 | 2017-08-03 11:48:19 -0700 | [diff] [blame] | 50 | } |
| 51 | |
Rachel Barker | febe1a0 | 2023-03-07 15:10:17 +0000 | [diff] [blame] | 52 | // Pick k distinct numbers from the set {0, ..., n-1} |
| 53 | // All possible sets of k numbers, and all possible orderings of those numbers, |
| 54 | // are equally likely. |
| 55 | // |
| 56 | // Note: The algorithm used here uses resampling to avoid choosing repeated |
| 57 | // values. This works well as long as n >> k, but can potentially lead to many |
| 58 | // resampling attempts if n is equal to or only slightly larger than k. |
| 59 | static INLINE void lcg_pick(int n, int k, int *out, unsigned int *seed) { |
| 60 | assert(0 <= k && k <= n); |
| 61 | for (int i = 0; i < k; i++) { |
| 62 | int v; |
| 63 | |
| 64 | // Inner resampling loop |
| 65 | // We have to use a goto here because C does not have a multi-level continue |
| 66 | // statement |
| 67 | resample: |
| 68 | v = (int)lcg_randint(seed, n); |
| 69 | for (int j = 0; j < i; j++) { |
| 70 | if (v == out[j]) { |
| 71 | // Repeated v, resample |
| 72 | goto resample; |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | // New v, accept |
| 77 | out[i] = v; |
| 78 | } |
| 79 | } |
| 80 | |
Alex Converse | 9d068c1 | 2017-08-03 11:48:19 -0700 | [diff] [blame] | 81 | #ifdef __cplusplus |
| 82 | } // extern "C" |
| 83 | #endif |
| 84 | |
James Zern | e1cbb13 | 2018-08-22 14:10:36 -0700 | [diff] [blame] | 85 | #endif // AOM_AV1_ENCODER_RANDOM_H_ |