blob: a164d4253b1d7d930dfe3c6107d94f5bc238d64e [file]
/* Pseudo random number generation functions derived from the drand48()
* function obtained from pysam source code.
*
* This functions are used in order to replace the default math.random()
* Lua implementation with something having exactly the same behavior
* across different systems (by default Lua uses libc's rand() that is not
* required to implement a specific PRNG generating the same sequence
* in different systems if seeded with the same integer).
*
* The original code appears to be under the public domain.
* I modified it removing the non needed functions and all the
* 1960-style C coding stuff...
*
* ----------------------------------------------------------------------------
*
* Copyright (c) 2010-2012, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Rewritten in C++ with constexprs and templates by @tanruixiang in
* https://github.com/apache/kvrocks/commit/900e0f44781d9459649e9864ba09abe6000ce987
*/
#include "rand.h"
#include <stdint.h>
namespace redis_rand_impl {
constexpr const int N = 16;
constexpr const int MASK = ((1 << (N - 1)) + (1 << (N - 1)) - 1);
template <typename T>
constexpr T LOW(const T x) {
return ((unsigned)(x)&MASK);
}
template <typename T>
constexpr T HIGH(const T x) {
return LOW(x >> N);
}
template <typename T>
constexpr void MUL(const T x, const T y, T *z) {
int32_t l = (int64_t)(x) * (int64_t)(y);
(z)[0] = LOW(l);
(z)[1] = HIGH(l);
}
template <typename T>
constexpr T CARRY(const T x, const T y) {
return ((int32_t)(x) + (int64_t)(y) > MASK);
}
template <typename T>
constexpr void ADDEQU(T &x, const T y, T &z) {
z = CARRY(x, (y)), x = LOW(x + (y));
}
constexpr const uint32_t X0 = 0x330E;
constexpr const uint32_t X1 = 0xABCD;
constexpr const uint32_t X2 = 0x1234;
constexpr const uint32_t A0 = 0xE66D;
constexpr const uint32_t A1 = 0xDEEC;
constexpr const uint32_t A2 = 0x5;
constexpr const uint32_t C = 0xB;
static uint32_t x[3] = {X0, X1, X2}, a[3] = {A0, A1, A2}, c = C;
template <typename T>
constexpr void SET3(T *x, const T x0, const T x1, const T x2) {
(x)[0] = (x0), (x)[1] = (x1), (x)[2] = (x2);
}
template <typename T>
constexpr void SETLOW(T *x, const T *y, const T n) {
SET3(x, LOW((y)[n]), LOW((y)[(n) + 1]), LOW((y)[(n) + 2]));
}
template <typename T>
constexpr void SEED(const T x0, const T x1, const T x2) {
SET3(x, x0, x1, x2), SET3(a, A0, A1, A2), c = C;
}
static void Next() {
uint32_t p[2], q[2], r[2], carry0 = 0, carry1 = 0;
MUL(a[0], x[0], p);
ADDEQU(p[0], c, carry0);
ADDEQU(p[1], carry0, carry1);
MUL(a[0], x[1], q);
ADDEQU(p[1], q[0], carry0);
MUL(a[1], x[0], r);
x[2] = LOW(carry0 + carry1 + CARRY(p[1], r[0]) + q[1] + r[1] + a[0] * x[2] + a[1] * x[1] + a[2] * x[0]);
x[1] = LOW(p[1] + r[0]);
x[0] = LOW(p[0]);
}
} // namespace redis_rand_impl
int32_t RedisLrand48() {
using namespace redis_rand_impl;
Next();
return static_cast<int32_t>(x[2] << (N - 1)) + static_cast<int32_t>(x[1] >> 1);
}
void RedisSrand48(int32_t seedval) {
using namespace redis_rand_impl;
SEED(X0, static_cast<uint32_t>(LOW(seedval)), static_cast<uint32_t>(HIGH(seedval)));
}