85 lines
2.8 KiB
C
85 lines
2.8 KiB
C
/*
|
|
* Copyright (c) 2017, Alliance for Open Media. All rights reserved.
|
|
*
|
|
* This source code is subject to the terms of the BSD 2 Clause License and
|
|
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
|
* was not distributed with this source code in the LICENSE file, you can
|
|
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
|
* Media Patent License 1.0 was not distributed with this source code in the
|
|
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
|
*/
|
|
|
|
#ifndef AOM_AV1_ENCODER_RANDOM_H_
|
|
#define AOM_AV1_ENCODER_RANDOM_H_
|
|
|
|
#include <stdint.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
// Advance the generator to its next state, and generate the next 32-bit output.
|
|
// Note that the low bits of this output are comparatively low-quality, so users
|
|
// of this function should ensure that the high bits factor through to their
|
|
// outputs.
|
|
static inline uint32_t lcg_next(uint32_t *state) {
|
|
*state = (uint32_t)(*state * 1103515245ULL + 12345);
|
|
return *state;
|
|
}
|
|
|
|
// Generate a random number in the range [0, 32768).
|
|
static inline uint32_t lcg_rand16(uint32_t *state) {
|
|
return (lcg_next(state) / 65536) % 32768;
|
|
}
|
|
|
|
// Generate a random number in the range [0, n)
|
|
// This is implemented as (rand() * n) / <range of RNG> rather than
|
|
// rand() % n, for a few reasons: This implementation is faster and less biased,
|
|
// and if is a power of 2, this uses the higher-quality top bits from the RNG
|
|
// output rather than the lower-quality bottom bits.
|
|
static inline uint32_t lcg_randint(uint32_t *state, uint32_t n) {
|
|
uint64_t v = ((uint64_t)lcg_next(state) * n) >> 32;
|
|
return (uint32_t)v;
|
|
}
|
|
|
|
// Generate a random number in the range [lo, hi)
|
|
static inline uint32_t lcg_randrange(uint32_t *state, uint32_t lo,
|
|
uint32_t hi) {
|
|
assert(lo < hi);
|
|
return lo + lcg_randint(state, hi - lo);
|
|
}
|
|
|
|
// Pick k distinct numbers from the set {0, ..., n-1}
|
|
// All possible sets of k numbers, and all possible orderings of those numbers,
|
|
// are equally likely.
|
|
//
|
|
// Note: The algorithm used here uses resampling to avoid choosing repeated
|
|
// values. This works well as long as n >> k, but can potentially lead to many
|
|
// resampling attempts if n is equal to or only slightly larger than k.
|
|
static inline void lcg_pick(int n, int k, int *out, unsigned int *seed) {
|
|
assert(0 <= k && k <= n);
|
|
for (int i = 0; i < k; i++) {
|
|
int v;
|
|
|
|
// Inner resampling loop
|
|
// We have to use a goto here because C does not have a multi-level continue
|
|
// statement
|
|
resample:
|
|
v = (int)lcg_randint(seed, n);
|
|
for (int j = 0; j < i; j++) {
|
|
if (v == out[j]) {
|
|
// Repeated v, resample
|
|
goto resample;
|
|
}
|
|
}
|
|
|
|
// New v, accept
|
|
out[i] = v;
|
|
}
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
} // extern "C"
|
|
#endif
|
|
|
|
#endif // AOM_AV1_ENCODER_RANDOM_H_
|