#[allow(unused_imports)]
use rusty_h264_common::fmath::{F32Ext as _, F64Ext as _};
#[allow(unused_imports)]
use rusty_h264_common::once::OnceLock;
pub(crate) fn polytier_on() -> bool {
#[cfg(test)]
if let Some(v) = TEST_POLYTIER.with(|c| c.get()) {
return v;
}
rusty_h264_common::knob("RFF_POLYTIER")
.map(|v| v != "0")
.unwrap_or(true)
}
#[cfg(test)]
thread_local! {
pub(crate) static TEST_POLYTIER: core::cell::Cell<Option<bool>> =
const { core::cell::Cell::new(None) };
}
pub(crate) fn lambda_qp(qp: u8) -> f64 {
static TAB: OnceLock<[f64; 256]> = OnceLock::new();
TAB.get_or_init(|| {
core::array::from_fn(|q| rusty_h264_common::fmath::powf(2f64, (q as f64 - 12.0) / 3.0))
})[qp as usize]
}
pub(crate) fn qstep_qp(qp: u8) -> f64 {
static TAB: OnceLock<[f64; 256]> = OnceLock::new();
TAB.get_or_init(|| {
core::array::from_fn(|q| 0.625 * rusty_h264_common::fmath::powf(2f64, q as f64 / 6.0))
})[qp as usize]
}
pub(crate) fn log2_poly(x: f64) -> f64 {
let bits = x.to_bits();
let mut e = ((bits >> 52) & 0x7ff) as i64 - 1023;
let mut m = f64::from_bits((bits & 0x000f_ffff_ffff_ffff) | 0x3ff0_0000_0000_0000);
if m > core::f64::consts::SQRT_2 {
m *= 0.5;
e += 1;
}
let s = (m - 1.0) / (m + 1.0);
let s2 = s * s;
const TWO_OVER_LN2: f64 = 2.0 / core::f64::consts::LN_2;
let p = 1.0
+ s2 * (1.0 / 3.0
+ s2 * (1.0 / 5.0
+ s2 * (1.0 / 7.0 + s2 * (1.0 / 9.0 + s2 * (1.0 / 11.0 + s2 * (1.0 / 13.0))))));
e as f64 + TWO_OVER_LN2 * s * p
}
const MAGIC_F64: f64 = 6_755_399_441_055_744.0;
pub(crate) fn round_ties_even_fast(x: f64) -> f64 {
(x + MAGIC_F64) - MAGIC_F64
}
#[cfg(test)]
mod tests {
use super::*;
#[allow(unused_imports)]
use alloc::{
boxed::Box,
format,
string::{String, ToString},
vec,
vec::Vec,
};
#[allow(unused_imports)]
use rusty_h264_common::once::OnceLock;
#[test]
fn tables_match_the_site_expressions() {
for q in 0..=255u8 {
assert_eq!(
lambda_qp(q).to_bits(),
rusty_h264_common::fmath::powf(2f64, (q as f64 - 12.0) / 3.0).to_bits(),
"lambda_qp({q})"
);
assert_eq!(
qstep_qp(q).to_bits(),
(0.625 * rusty_h264_common::fmath::powf(2f64, q as f64 / 6.0)).to_bits(),
"qstep_qp({q})"
);
}
assert!((qstep_qp(28) / qstep_qp(22) - 2.0).abs() < 1e-9);
}
#[test]
fn log2_poly_oracle() {
for k in -40..=40i32 {
let x = (2f64).powi(k);
assert_eq!(log2_poly(x).to_bits(), (k as f64).to_bits(), "2^{k}");
}
let mut worst = 0.0f64;
let mut prev = f64::NEG_INFINITY;
let mut v = 1u64;
while v <= (1 << 24) + 3 {
let x = (v + 1) as f64;
let (a, b) = (log2_poly(x), x.log2());
let abs = (a - b).abs();
let err = if b.abs() > f64::MIN_POSITIVE {
(abs / b.abs()).min(abs)
} else {
abs
};
worst = worst.max(err);
assert!(a >= prev, "not monotone at v={v}");
prev = a;
v = v + 1 + v / 512; }
let mut st = 0x1234_5678u64;
for _ in 0..20_000 {
st = st
.wrapping_mul(6_364_136_223_846_793_005)
.wrapping_add(1_442_695_040_888_963_407);
let r = 1.0 + (st >> 11) as f64 / (1u64 << 53) as f64 * 4094.0; let (a, b) = (log2_poly(r), r.log2());
let abs = (a - b).abs();
let err = if b.abs() > f64::MIN_POSITIVE {
(abs / b.abs()).min(abs)
} else {
abs
};
worst = worst.max(err);
}
assert!(
worst < 1e-11,
"worst log2_poly error {worst:e} exceeds 1e-11"
);
}
#[test]
fn round_ties_even_fast_oracle() {
assert_eq!(MAGIC_F64.to_bits(), (1.5 * (2f64).powi(52)).to_bits());
let mut st = 0x9e37_79b9u64;
for i in 0..200_000u64 {
let x = if i % 4 == 0 {
(i as f64 / 4.0).copysign(if i % 8 == 0 { 1.0 } else { -1.0 }) + 0.5
} else {
st = st
.wrapping_mul(6_364_136_223_846_793_005)
.wrapping_add(1_442_695_040_888_963_407);
let m = (st >> 11) as f64 / (1u64 << 53) as f64; (m - 0.5) * (2f64).powi((i % 50) as i32) };
let (a, b) = (round_ties_even_fast(x), x.round_ties_even());
assert!(a == b, "x={x:e}: fast {a:e} vs libm {b:e}");
}
assert_eq!(round_ties_even_fast(-0.3).to_bits(), 0f64.to_bits());
assert_eq!((-0.3f64).round_ties_even().to_bits(), (-0.0f64).to_bits());
assert_eq!(round_ties_even_fast(2.5), 2.0);
assert_eq!((2.5f64).round(), 3.0);
assert_eq!(round_ties_even_fast(0.5), 0.0);
assert_eq!((0.5f64).round(), 1.0);
}
}