pub(super) fn f64_trunc(x: f64) -> f64 {
if x.is_nan() || x.is_infinite() {
return x;
}
if x >= 9_007_199_254_740_992.0 || x <= -9_007_199_254_740_992.0 {
return x;
}
(x as i64) as f64
}
const PRNG_SENTINEL: u64 = 0x2545_F491_4F6C_DD1D;
#[cfg(feature = "std")]
extern crate std;
#[cfg(not(feature = "std"))]
static PRNG_STATE: core::sync::atomic::AtomicU64 =
core::sync::atomic::AtomicU64::new(PRNG_SENTINEL);
#[cfg(feature = "std")]
std::thread_local! {
static PRNG_TL: core::cell::Cell<u64> = const { core::cell::Cell::new(0) };
}
#[cfg(feature = "std")]
static PRNG_THREAD_SALT: core::sync::atomic::AtomicU64 =
core::sync::atomic::AtomicU64::new(0x9E37_79B9_7F4A_7C15);
fn xorshift(mut x: u64) -> u64 {
if x == 0 {
x = PRNG_SENTINEL;
}
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
if x == 0 { PRNG_SENTINEL } else { x }
}
pub(super) fn prng_next_u64() -> u64 {
#[cfg(feature = "std")]
{
PRNG_TL.with(|c| {
let mut x = c.get();
if x == 0 {
use core::sync::atomic::Ordering;
x = PRNG_SENTINEL
^ PRNG_THREAD_SALT.fetch_add(0x9E37_79B9_7F4A_7C15, Ordering::Relaxed);
}
let next = xorshift(x);
c.set(next);
next
})
}
#[cfg(not(feature = "std"))]
{
use core::sync::atomic::Ordering;
let mut x = PRNG_STATE.load(Ordering::Relaxed);
loop {
let next = xorshift(x);
match PRNG_STATE.compare_exchange_weak(x, next, Ordering::Relaxed, Ordering::Relaxed) {
Ok(_) => return next,
Err(seen) => x = seen,
}
}
}
}
fn prng_set_state(state: u64) {
let state = if state == 0 { PRNG_SENTINEL } else { state };
#[cfg(feature = "std")]
PRNG_TL.with(|c| c.set(state));
#[cfg(not(feature = "std"))]
{
use core::sync::atomic::Ordering;
PRNG_STATE.store(state, Ordering::Relaxed);
}
}
static UUIDV7_MONO: core::sync::atomic::AtomicU64 = core::sync::atomic::AtomicU64::new(0);
pub(super) fn uuidv7_monotonic(base_ms: u64) -> (u64, u16) {
use core::sync::atomic::Ordering;
let mut packed = UUIDV7_MONO.load(Ordering::Relaxed);
loop {
let last_ms = packed >> 12;
let last_ctr = (packed & 0xFFF) as u16;
let (ms, ctr) = if base_ms > last_ms {
(base_ms, 0)
} else if last_ctr < 0xFFF {
(last_ms, last_ctr + 1)
} else {
(last_ms + 1, 0)
};
let next = (ms << 12) | u64::from(ctr);
match UUIDV7_MONO.compare_exchange_weak(packed, next, Ordering::Relaxed, Ordering::Relaxed)
{
Ok(_) => return (ms, ctr),
Err(seen) => packed = seen,
}
}
}
pub(super) fn prng_seed(seed: f64) {
prng_set_state(seed.to_bits());
}
pub(crate) fn prng_install_seed(seed: u64) {
prng_set_state(seed);
}
pub(super) fn prng_next_f64() -> f64 {
let mantissa = prng_next_u64() >> 11;
let denom = (1u64 << 53) as f64;
mantissa as f64 / denom
}
pub(crate) fn f64_sqrt(x: f64) -> f64 {
libm::sqrt(x)
}
#[cfg(feature = "std")]
mod plat {
pub fn exp(x: f64) -> f64 {
x.exp()
}
pub fn ln(x: f64) -> f64 {
x.ln()
}
pub fn pow(x: f64, y: f64) -> f64 {
x.powf(y)
}
pub fn sinh(x: f64) -> f64 {
x.sinh()
}
pub fn cosh(x: f64) -> f64 {
x.cosh()
}
pub fn tanh(x: f64) -> f64 {
x.tanh()
}
pub fn asinh(x: f64) -> f64 {
x.asinh()
}
pub fn acosh(x: f64) -> f64 {
x.acosh()
}
pub fn atanh(x: f64) -> f64 {
x.atanh()
}
}
#[cfg(not(feature = "std"))]
mod plat {
pub fn exp(x: f64) -> f64 {
libm::exp(x)
}
pub fn ln(x: f64) -> f64 {
libm::log(x)
}
pub fn pow(x: f64, y: f64) -> f64 {
libm::pow(x, y)
}
pub fn sinh(x: f64) -> f64 {
libm::sinh(x)
}
pub fn cosh(x: f64) -> f64 {
libm::cosh(x)
}
pub fn tanh(x: f64) -> f64 {
libm::tanh(x)
}
pub fn asinh(x: f64) -> f64 {
libm::asinh(x)
}
pub fn acosh(x: f64) -> f64 {
libm::acosh(x)
}
pub fn atanh(x: f64) -> f64 {
libm::atanh(x)
}
}
pub(crate) fn f64_exp(x: f64) -> f64 {
plat::exp(x)
}
pub(crate) fn f64_ln(x: f64) -> f64 {
if x < 0.0 {
return f64::NAN;
}
plat::ln(x)
}
pub(crate) fn f64_pow(x: f64, y: f64) -> f64 {
plat::pow(x, y)
}
pub(crate) fn f64_sinh(x: f64) -> f64 {
plat::sinh(x)
}
pub(crate) fn f64_cosh(x: f64) -> f64 {
plat::cosh(x)
}
pub(crate) fn f64_tanh(x: f64) -> f64 {
plat::tanh(x)
}
pub(crate) fn f64_asinh(x: f64) -> f64 {
plat::asinh(x)
}
pub(crate) fn f64_acosh(x: f64) -> f64 {
plat::acosh(x)
}
pub(crate) fn f64_atanh(x: f64) -> f64 {
plat::atanh(x)
}
pub(super) fn f64_powi(base: f64, exp: i32) -> f64 {
if exp == 0 {
return 1.0;
}
let mut result = 1.0;
let mut b = if exp > 0 { base } else { 1.0 / base };
let mut e = exp.unsigned_abs();
while e > 0 {
if e & 1 == 1 {
result *= b;
}
e >>= 1;
if e > 0 {
b *= b;
}
}
result
}
pub(super) fn f64_round_half_away(x: f64) -> f64 {
if x.is_nan() || x.is_infinite() {
return x;
}
if x >= 0.0 {
f64_floor(x + 0.5)
} else {
f64_ceil(x - 0.5)
}
}
pub(crate) fn f64_round_half_even(x: f64) -> f64 {
if x.is_nan() || x.is_infinite() {
return x;
}
let fl = f64_floor(x);
let diff = x - fl;
if diff < 0.5 {
fl
} else if diff > 0.5 {
fl + 1.0
} else {
let half = fl / 2.0;
if half == f64_floor(half) {
fl
} else {
fl + 1.0
}
}
}
pub(crate) fn f64_ceil(x: f64) -> f64 {
if x.is_nan() || x.is_infinite() {
return x;
}
if x >= 9_007_199_254_740_992.0 || x <= -9_007_199_254_740_992.0 {
return x;
}
let trunc = (x as i64) as f64;
if x > 0.0 && x != trunc {
trunc + 1.0
} else {
trunc
}
}
pub(crate) fn f64_floor(x: f64) -> f64 {
if x.is_nan() || x.is_infinite() {
return x;
}
if x >= 9_007_199_254_740_992.0 || x <= -9_007_199_254_740_992.0 {
return x;
}
let trunc = (x as i64) as f64;
if x < 0.0 && x != trunc {
trunc - 1.0
} else {
trunc
}
}