#![allow(
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
clippy::cast_sign_loss
)]
#[must_use]
#[inline]
pub fn ftol(f: f32) -> i32 {
f.round_ties_even() as i64 as i32
}
#[must_use]
pub fn mulshr16(a: i32, d: i32) -> i32 {
let prod = i64::from(a) * i64::from(d);
(prod >> 16) as i32
}
#[must_use]
pub fn shldiv16(a: i32, b: i32) -> i32 {
let num = i64::from(a) << 16;
(num / i64::from(b)) as i32
}
#[must_use]
pub fn isshldiv16safe(a: i32, b: i32) -> i32 {
let mut edx = a;
if edx >= 0 {
edx = edx.wrapping_neg();
}
edx >>= 14;
let mut eax = b;
if eax >= 0 {
eax = eax.wrapping_neg();
}
eax = eax.wrapping_sub(edx);
((eax as u32) >> 31) as i32
}
#[must_use]
pub fn lbound0(a: i32, b: i32) -> i32 {
debug_assert!(b >= 0, "lbound0: b must be >= 0");
if (a as u32) <= (b as u32) {
return a;
}
(!(a >> 31)) & b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mulshr16_smoke() {
assert_eq!(mulshr16(256, 256), 1);
assert_eq!(mulshr16(65536, 65536), 65536);
assert_eq!(mulshr16(32768, 32768), 16384);
assert_eq!(
mulshr16(i32::MAX, 2),
((i64::from(i32::MAX) * 2) >> 16) as i32
);
assert_eq!(mulshr16(-65536, 256), -256);
}
#[test]
fn shldiv16_smoke() {
assert_eq!(shldiv16(1, 1), 65536);
assert_eq!(shldiv16(1, 65536), 1);
assert_eq!(shldiv16(-100, 200), -32768);
}
#[test]
fn isshldiv16safe_returns_one_when_safe() {
assert_eq!(isshldiv16safe(1, 100), 1);
assert_eq!(isshldiv16safe(-100, -100), 1);
assert_eq!(isshldiv16safe(0, 1), 1);
}
#[test]
fn isshldiv16safe_returns_zero_when_unsafe() {
assert_eq!(isshldiv16safe(i32::MAX, 1), 0);
assert_eq!(isshldiv16safe(i32::MAX, 2), 0);
}
#[test]
fn isshldiv16safe_handles_int_min() {
let _ = isshldiv16safe(i32::MIN, 1);
let _ = isshldiv16safe(1, i32::MIN);
}
#[test]
fn lbound0_in_range_passes_through() {
assert_eq!(lbound0(0, 100), 0);
assert_eq!(lbound0(50, 100), 50);
assert_eq!(lbound0(100, 100), 100);
}
#[test]
fn lbound0_below_zero_clamps_to_zero() {
assert_eq!(lbound0(-1, 100), 0);
assert_eq!(lbound0(-1_000_000, 100), 0);
assert_eq!(lbound0(i32::MIN, 100), 0);
}
#[test]
fn lbound0_above_b_clamps_to_b() {
assert_eq!(lbound0(101, 100), 100);
assert_eq!(lbound0(i32::MAX, 100), 100);
}
#[test]
fn ftol_rounds_ties_to_even_in_range() {
assert_eq!(ftol(0.5), 0);
assert_eq!(ftol(1.5), 2);
assert_eq!(ftol(2.5), 2);
assert_eq!(ftol(-0.5), 0);
assert_eq!(ftol(-1.5), -2);
assert_eq!(ftol(1.4), 1);
assert_eq!(ftol(1.6), 2);
}
#[test]
fn ftol_wraps_modulo_2_to_32_on_overflow() {
assert_eq!(ftol(2_147_483_648.0_f32), i32::MIN);
assert_eq!(ftol(4_294_967_296.0_f32), 0);
let f = 3.9e10_f32;
let want = f.round_ties_even() as i64 as i32;
assert_eq!(ftol(f), want);
assert_ne!(ftol(f), i32::MAX);
}
}