use super::float_fixed_l;
use ::fixed::FixedU64;
use ::fixed::types::extra::{
U0 as F0, U8 as F8, U16 as F16, U32 as F32, U48 as F48, U63 as F63, U64 as F64, Unsigned,
};
const fn q000u064_fwd(q: FixedU64<F0>) -> u64 {
q.to_bits()
}
const fn q000u064_bk(i: u64) -> FixedU64<F0> {
FixedU64::<F0>::from_bits(i)
}
crate::iso! {
pub Q000U064 : FixedU64<F0> => u64 {
forward: q000u064_fwd,
back: q000u064_bk,
}
}
pub type U000 = FixedU64<F0>;
pub type U008 = FixedU64<F8>;
pub type U016 = FixedU64<F16>;
pub type U032 = FixedU64<F32>;
pub type U048 = FixedU64<F48>;
pub type U063 = FixedU64<F63>;
pub type U064 = FixedU64<F64>;
macro_rules! fix_fix_u64 {
($const_name:ident, $FineFrac:ty, $CoarseFrac:ty) => {
#[rustfmt::skip]
#[doc = concat!(
"`FixedU64<",
stringify!($FineFrac),
"> → FixedU64<",
stringify!($CoarseFrac),
">` frac-level convert (u64-backed)."
)]
pub const $const_name: $crate::conn::Conn<FixedU64<$FineFrac>, FixedU64<$CoarseFrac>> = {
const SHIFT: u32 = <$FineFrac as Unsigned>::U32 - <$CoarseFrac as Unsigned>::U32;
const RATIO: u128 = 1_u128 << SHIFT;
const FINE_MAX: u64 = u64::MAX;
fn ceil(x: FixedU64<$FineFrac>) -> FixedU64<$CoarseFrac> {
let bits = x.to_bits() as u128;
let q = bits / RATIO;
let r = bits % RATIO;
let res = if r != 0 { q + 1 } else { q };
FixedU64::from_bits(res as u64)
}
fn inner(x: FixedU64<$CoarseFrac>) -> FixedU64<$FineFrac> {
let res = (x.to_bits() as u128) * RATIO;
let saturated = if res > FINE_MAX as u128 {
FINE_MAX
} else {
res as u64
};
FixedU64::from_bits(saturated)
}
$crate::conn::Conn::new_l(ceil, inner)
};
};
}
fix_fix_u64!(Q008Q000, F8, F0);
fix_fix_u64!(Q016Q000, F16, F0);
fix_fix_u64!(Q032Q000, F32, F0);
fix_fix_u64!(Q048Q000, F48, F0);
fix_fix_u64!(Q063Q000, F63, F0);
fix_fix_u64!(Q064Q000, F64, F0);
fix_fix_u64!(Q016Q008, F16, F8);
fix_fix_u64!(Q032Q008, F32, F8);
fix_fix_u64!(Q048Q008, F48, F8);
fix_fix_u64!(Q063Q008, F63, F8);
fix_fix_u64!(Q064Q008, F64, F8);
fix_fix_u64!(Q032Q016, F32, F16);
fix_fix_u64!(Q048Q016, F48, F16);
fix_fix_u64!(Q063Q016, F63, F16);
fix_fix_u64!(Q064Q016, F64, F16);
fix_fix_u64!(Q048Q032, F48, F32);
fix_fix_u64!(Q063Q032, F63, F32);
fix_fix_u64!(Q064Q032, F64, F32);
fix_fix_u64!(Q063Q048, F63, F48);
fix_fix_u64!(Q064Q048, F64, F48);
fix_fix_u64!(Q064Q063, F64, F63);
float_fixed_l!(pub F032Q000, f32, FixedU64, F0, u64);
float_fixed_l!(pub F032Q008, f32, FixedU64, F8, u64);
float_fixed_l!(pub F032Q016, f32, FixedU64, F16, u64);
float_fixed_l!(pub F032Q032, f32, FixedU64, F32, u64);
float_fixed_l!(pub F032Q048, f32, FixedU64, F48, u64);
float_fixed_l!(pub F032Q063, f32, FixedU64, F63, u64);
float_fixed_l!(pub F032Q064, f32, FixedU64, F64, u64);
float_fixed_l!(pub F064Q000, f64, FixedU64, F0, u64);
float_fixed_l!(pub F064Q008, f64, FixedU64, F8, u64);
float_fixed_l!(pub F064Q016, f64, FixedU64, F16, u64);
float_fixed_l!(pub F064Q032, f64, FixedU64, F32, u64);
float_fixed_l!(pub F064Q048, f64, FixedU64, F48, u64);
float_fixed_l!(pub F064Q063, f64, FixedU64, F63, u64);
float_fixed_l!(pub F064Q064, f64, FixedU64, F64, u64);
#[cfg(feature = "f16")]
float_fixed_l!(pub F016Q000, f16, FixedU64, F0, u64);
#[cfg(feature = "f16")]
float_fixed_l!(pub F016Q008, f16, FixedU64, F8, u64);
#[cfg(feature = "f16")]
float_fixed_l!(pub F016Q016, f16, FixedU64, F16, u64);
#[cfg(feature = "f16")]
float_fixed_l!(pub F016Q032, f16, FixedU64, F32, u64);
#[cfg(feature = "f16")]
float_fixed_l!(pub F016Q048, f16, FixedU64, F48, u64);
#[cfg(feature = "f16")]
float_fixed_l!(pub F016Q063, f16, FixedU64, F63, u64);
#[cfg(feature = "f16")]
float_fixed_l!(pub F016Q064, f16, FixedU64, F64, u64);
#[cfg(test)]
mod tests {
use super::*;
#[allow(unused_imports)]
use crate::conn::{ConnL, ConnR};
#[allow(unused_imports)]
use proptest::prelude::*;
#[test]
fn spot_q63_to_q64() {
let q63 = FixedU64::<F63>::from_bits(1 << 62);
let q64 = Q064Q063.upper(q63);
assert_eq!(q64, FixedU64::<F64>::from_bits(1 << 63));
assert_eq!(Q064Q063.ceil(q64), q63);
}
#[test]
fn spot_q032q016_on_grid() {
let q3232 = FixedU64::<F32>::from_bits(6_442_450_944);
assert_eq!(Q032Q016.ceil(q3232), FixedU64::<F16>::from_bits(98304));
assert_eq!(Q032Q016.upper(FixedU64::<F16>::from_bits(98304)), q3232);
}
#[test]
fn spot_q064q000_degenerate() {
assert_eq!(
Q064Q000.upper(FixedU64::<F0>::from_bits(0)),
FixedU64::<F64>::from_bits(0),
);
assert_eq!(
Q064Q000.upper(FixedU64::<F0>::from_bits(1)),
FixedU64::<F64>::from_bits(u64::MAX),
);
assert_eq!(
Q064Q000.ceil(FixedU64::<F64>::from_bits(0)),
FixedU64::<F0>::from_bits(0),
);
assert_eq!(
Q064Q000.ceil(FixedU64::<F64>::from_bits(1)),
FixedU64::<F0>::from_bits(1),
);
}
#[test]
fn spot_boundary_fixups() {
let fmin = FixedU64::<F32>::from_bits(0);
assert_eq!(Q032Q016.ceil(fmin), FixedU64::<F16>::from_bits(0));
}
#[test]
fn f064q000_above_max_to_posinf() {
let above_max = u64::MAX as f64; let v = crate::float::N5::new(above_max);
assert_eq!(F064Q000.ceil(v), crate::extended::Extended::PosInf);
}
#[test]
fn f064q008_above_max_to_posinf() {
let above_max = (u64::MAX as f64) / 256.0_f64; let v = crate::float::N5::new(above_max);
assert_eq!(F064Q008.ceil(v), crate::extended::Extended::PosInf);
}
}