use super::float_fixed;
use ::fixed::FixedI8;
use ::fixed::types::extra::{U0, U1, U2, U3, U4, U6, U7, U8, Unsigned};
const fn q000i008_fwd(q: FixedI8<U0>) -> i8 {
q.to_bits()
}
const fn q000i008_bk(i: i8) -> FixedI8<U0> {
FixedI8::<U0>::from_bits(i)
}
const fn q007i008_fwd(q: FixedI8<U7>) -> i8 {
q.to_bits()
}
const fn q007i008_bk(i: i8) -> FixedI8<U7> {
FixedI8::<U7>::from_bits(i)
}
crate::iso! {
pub Q000I008 : FixedI8<U0> => i8 {
forward: q000i008_fwd,
back: q000i008_bk,
}
}
crate::iso! {
pub Q007I008 : FixedI8<U7> => i8 {
forward: q007i008_fwd,
back: q007i008_bk,
}
}
pub type I000 = FixedI8<U0>;
pub type I001 = FixedI8<U1>;
pub type I002 = FixedI8<U2>;
pub type I003 = FixedI8<U3>;
pub type I004 = FixedI8<U4>;
pub type I006 = FixedI8<U6>;
pub type I008 = FixedI8<U8>;
macro_rules! fix_fix_i8 {
($const_name:ident, $FineFrac:ty, $CoarseFrac:ty) => {
#[rustfmt::skip]
#[doc = concat!(
"`FixedI8<",
stringify!($FineFrac),
"> → FixedI8<",
stringify!($CoarseFrac),
">` frac-level convert (i8-backed)."
)]
pub const $const_name: $crate::conn::Conn<FixedI8<$FineFrac>, FixedI8<$CoarseFrac>> = {
const SHIFT: u32 = <$FineFrac as Unsigned>::U32 - <$CoarseFrac as Unsigned>::U32;
const RATIO: i16 = 1_i16 << SHIFT;
const FINE_MIN: i8 = i8::MIN;
const FINE_MAX: i8 = i8::MAX;
fn ceil(x: FixedI8<$FineFrac>) -> FixedI8<$CoarseFrac> {
if x.to_bits() == FINE_MIN {
return FixedI8::<$CoarseFrac>::from_bits(i8::MIN);
}
let bits = x.to_bits() as i16;
let q = bits.div_euclid(RATIO);
let r = bits.rem_euclid(RATIO);
let res = if r != 0 { q + 1 } else { q };
FixedI8::<$CoarseFrac>::from_bits(res as i8)
}
fn inner(x: FixedI8<$CoarseFrac>) -> FixedI8<$FineFrac> {
let res = (x.to_bits() as i16) * RATIO;
let saturated = if res > FINE_MAX as i16 {
FINE_MAX
} else if res < FINE_MIN as i16 {
FINE_MIN
} else {
res as i8
};
FixedI8::<$FineFrac>::from_bits(saturated)
}
$crate::conn::Conn::new_l(ceil, inner)
};
};
}
fix_fix_i8!(Q001Q000, U1, U0);
fix_fix_i8!(Q002Q000, U2, U0);
fix_fix_i8!(Q003Q000, U3, U0);
fix_fix_i8!(Q004Q000, U4, U0);
fix_fix_i8!(Q006Q000, U6, U0);
fix_fix_i8!(Q008Q000, U8, U0);
fix_fix_i8!(Q002Q001, U2, U1);
fix_fix_i8!(Q003Q001, U3, U1);
fix_fix_i8!(Q004Q001, U4, U1);
fix_fix_i8!(Q006Q001, U6, U1);
fix_fix_i8!(Q008Q001, U8, U1);
fix_fix_i8!(Q003Q002, U3, U2);
fix_fix_i8!(Q004Q002, U4, U2);
fix_fix_i8!(Q006Q002, U6, U2);
fix_fix_i8!(Q008Q002, U8, U2);
fix_fix_i8!(Q004Q003, U4, U3);
fix_fix_i8!(Q006Q003, U6, U3);
fix_fix_i8!(Q008Q003, U8, U3);
fix_fix_i8!(Q006Q004, U6, U4);
fix_fix_i8!(Q008Q004, U8, U4);
fix_fix_i8!(Q008Q006, U8, U6);
float_fixed!(pub F032Q000, f32, FixedI8, U0, i8);
float_fixed!(pub F032Q001, f32, FixedI8, U1, i8);
float_fixed!(pub F032Q002, f32, FixedI8, U2, i8);
float_fixed!(pub F032Q003, f32, FixedI8, U3, i8);
float_fixed!(pub F032Q004, f32, FixedI8, U4, i8);
float_fixed!(pub F032Q006, f32, FixedI8, U6, i8);
float_fixed!(pub F032Q008, f32, FixedI8, U8, i8);
float_fixed!(pub F064Q000, f64, FixedI8, U0, i8);
float_fixed!(pub F064Q001, f64, FixedI8, U1, i8);
float_fixed!(pub F064Q002, f64, FixedI8, U2, i8);
float_fixed!(pub F064Q003, f64, FixedI8, U3, i8);
float_fixed!(pub F064Q004, f64, FixedI8, U4, i8);
float_fixed!(pub F064Q006, f64, FixedI8, U6, i8);
float_fixed!(pub F064Q008, f64, FixedI8, U8, i8);
#[cfg(feature = "f16")]
float_fixed!(pub F016Q000, f16, FixedI8, U0, i8);
#[cfg(feature = "f16")]
float_fixed!(pub F016Q001, f16, FixedI8, U1, i8);
#[cfg(feature = "f16")]
float_fixed!(pub F016Q002, f16, FixedI8, U2, i8);
#[cfg(feature = "f16")]
float_fixed!(pub F016Q003, f16, FixedI8, U3, i8);
#[cfg(feature = "f16")]
float_fixed!(pub F016Q004, f16, FixedI8, U4, i8);
#[cfg(feature = "f16")]
float_fixed!(pub F016Q006, f16, FixedI8, U6, i8);
#[cfg(feature = "f16")]
float_fixed!(pub F016Q008, f16, FixedI8, U8, i8);
#[cfg(test)]
mod tests {
use super::*;
#[allow(unused_imports)]
use crate::conn::{ConnL, ConnR};
use crate::prop::conn as conn_laws;
use proptest::prelude::*;
#[test]
fn q000i008_round_trips_both_ways() {
for &v in &[i8::MIN, -1, 0, 1, 42, i8::MAX] {
let q = FixedI8::<U0>::from_bits(v);
assert_eq!(Q000I008.view_l().ceil(q), v);
assert_eq!(Q000I008.view_r().floor(q), v);
assert_eq!(Q000I008.view_l().upper(v), q);
assert_eq!(Q000I008.view_r().lower(v), q);
assert_eq!(Q000I008.view_l().ceil(Q000I008.view_l().upper(v)), v);
assert_eq!(Q000I008.view_l().upper(Q000I008.view_l().ceil(q)), q);
}
}
proptest! {
#[test]
fn q000i008_galois_l(a_bits in any::<i8>(), b in any::<i8>()) {
let a = FixedI8::<U0>::from_bits(a_bits);
prop_assert!(conn_laws::galois_l(&Q000I008.view_l(), a, b));
}
#[test]
fn q000i008_galois_r(a_bits in any::<i8>(), b in any::<i8>()) {
let a = FixedI8::<U0>::from_bits(a_bits);
prop_assert!(conn_laws::galois_r(&Q000I008.view_r(), a, b));
}
#[test]
fn q000i008_round_trip_both_directions(v in any::<i8>()) {
let q = FixedI8::<U0>::from_bits(v);
prop_assert_eq!(Q000I008.view_l().upper(Q000I008.view_l().ceil(q)), q);
prop_assert_eq!(Q000I008.view_l().ceil(Q000I008.view_l().upper(v)), v);
prop_assert_eq!(Q000I008.view_r().lower(Q000I008.view_r().floor(q)), q);
prop_assert_eq!(Q000I008.view_r().floor(Q000I008.view_r().lower(v)), v);
}
#[test]
fn q007i008_round_trip_both_directions(v in any::<i8>()) {
let q = FixedI8::<U7>::from_bits(v);
prop_assert_eq!(Q007I008.view_l().upper(Q007I008.view_l().ceil(q)), q);
prop_assert_eq!(Q007I008.view_l().ceil(Q007I008.view_l().upper(v)), v);
prop_assert_eq!(Q007I008.view_r().lower(Q007I008.view_r().floor(q)), q);
prop_assert_eq!(Q007I008.view_r().floor(Q007I008.view_r().lower(v)), v);
}
}
#[test]
fn spot_q004q000_on_grid() {
let q44 = FixedI8::<U4>::from_bits(24);
assert_eq!(Q004Q000.ceil(q44), FixedI8::<U0>::from_bits(2));
assert_eq!(
Q004Q000.upper(FixedI8::<U0>::from_bits(1)),
FixedI8::<U4>::from_bits(16)
);
}
#[test]
fn spot_q004q000_negative() {
let q44 = FixedI8::<U4>::from_bits(-24);
assert_eq!(Q004Q000.ceil(q44), FixedI8::<U0>::from_bits(-1));
}
#[test]
fn spot_q008q000_degenerate() {
assert_eq!(
Q008Q000.upper(FixedI8::<U0>::from_bits(0)),
FixedI8::<U8>::from_bits(0),
);
assert_eq!(
Q008Q000.upper(FixedI8::<U0>::from_bits(1)),
FixedI8::<U8>::from_bits(i8::MAX),
);
assert_eq!(
Q008Q000.upper(FixedI8::<U0>::from_bits(-1)),
FixedI8::<U8>::from_bits(i8::MIN),
);
}
#[test]
fn spot_boundary_fixups() {
let fmin = FixedI8::<U4>::from_bits(i8::MIN);
assert_eq!(Q004Q000.ceil(fmin), FixedI8::<U0>::from_bits(i8::MIN));
}
macro_rules! props_for_pair {
($mod_name:ident, $conn:ident, $FineFrac:ty, $CoarseFrac:ty) => {
$crate::law_battery! {
mod $mod_name,
conn: $conn,
fine: prop_oneof![
1 => Just(FixedI8::<$FineFrac>::from_bits(i8::MIN)),
1 => Just(FixedI8::<$FineFrac>::from_bits(i8::MAX)),
1 => Just(FixedI8::<$FineFrac>::from_bits(0)),
8 => any::<i8>().prop_map(FixedI8::<$FineFrac>::from_bits),
],
coarse: prop_oneof![
1 => Just(FixedI8::<$CoarseFrac>::from_bits(i8::MIN)),
1 => Just(FixedI8::<$CoarseFrac>::from_bits(i8::MAX)),
1 => Just(FixedI8::<$CoarseFrac>::from_bits(0)),
8 => any::<i8>().prop_map(FixedI8::<$CoarseFrac>::from_bits),
],
subset: l_only,
}
};
}
props_for_pair!(q001q000, Q001Q000, U1, U0);
props_for_pair!(q002q000, Q002Q000, U2, U0);
props_for_pair!(q003q000, Q003Q000, U3, U0);
props_for_pair!(q004q000, Q004Q000, U4, U0);
props_for_pair!(q006q000, Q006Q000, U6, U0);
props_for_pair!(q008q000, Q008Q000, U8, U0);
props_for_pair!(q002q001, Q002Q001, U2, U1);
props_for_pair!(q003q001, Q003Q001, U3, U1);
props_for_pair!(q004q001, Q004Q001, U4, U1);
props_for_pair!(q006q001, Q006Q001, U6, U1);
props_for_pair!(q008q001, Q008Q001, U8, U1);
props_for_pair!(q003q002, Q003Q002, U3, U2);
props_for_pair!(q004q002, Q004Q002, U4, U2);
props_for_pair!(q006q002, Q006Q002, U6, U2);
props_for_pair!(q008q002, Q008Q002, U8, U2);
props_for_pair!(q004q003, Q004Q003, U4, U3);
props_for_pair!(q006q003, Q006Q003, U6, U3);
props_for_pair!(q008q003, Q008Q003, U8, U3);
props_for_pair!(q006q004, Q006Q004, U6, U4);
props_for_pair!(q008q004, Q008Q004, U8, U4);
props_for_pair!(q008q006, Q008Q006, U8, U6);
}