#![doc = include_str!("../README.md")]
#![cfg_attr(not(feature = "std"), no_std)]
#![deny(non_ascii_idents)]
#![deny(unsafe_code)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![warn(trivial_casts, trivial_numeric_casts)]
#![allow(unused)]
#![allow(dead_code)]
#![warn(clippy::cast_possible_truncation)]
#![warn(clippy::cast_possible_wrap)]
#![warn(clippy::cast_precision_loss)]
#![warn(clippy::cast_sign_loss)]
#![warn(clippy::cognitive_complexity)]
#![warn(clippy::decimal_literal_representation)]
#![warn(clippy::enum_glob_use)]
#![warn(clippy::equatable_if_let)]
#![warn(clippy::fallible_impl_from)]
#![warn(clippy::if_not_else)]
#![warn(clippy::if_then_some_else_none)]
#![warn(clippy::implicit_clone)]
#![warn(clippy::integer_division)]
#![warn(clippy::manual_assert)]
#![warn(clippy::match_same_arms)]
#![warn(clippy::mismatching_type_param_order)]
#![warn(clippy::missing_const_for_fn)]
#![warn(clippy::missing_errors_doc)]
#![warn(clippy::missing_panics_doc)]
#![warn(clippy::multiple_crate_versions)]
#![warn(clippy::must_use_candidate)]
#![warn(clippy::needless_pass_by_value)]
#![warn(clippy::print_stderr)]
#![warn(clippy::print_stdout)]
#![warn(clippy::semicolon_if_nothing_returned)]
#![warn(clippy::str_to_string)]
#![warn(clippy::string_to_string)]
#![warn(clippy::undocumented_unsafe_blocks)]
#![warn(clippy::unicode_not_nfc)]
#![warn(clippy::unimplemented)]
#![warn(clippy::unseparated_literal_suffix)]
#![warn(clippy::unused_self)]
#![warn(clippy::unwrap_in_result)]
#![warn(clippy::use_self)]
#![warn(clippy::used_underscore_binding)]
#![warn(clippy::wildcard_imports)]
extern crate alloc;
extern crate core;
use crate::big_uint::{
BigUInt, DivRem, HiLo, Parity, U1024, U128, U256, U512,
};
use core::{cmp::Ordering, convert::Into, num::FpCategory, ops::Neg};
mod big_uint;
mod binops;
pub mod consts;
mod conv;
mod fused_ops;
mod math;
#[cfg(feature = "num-traits")]
mod num_traits;
pub(crate) const PREC_LEVEL: u32 = 8;
pub(crate) const TOTAL_BITS: u32 = 1_u32 << PREC_LEVEL;
pub(crate) const EXP_BITS: u32 = 4 * PREC_LEVEL - 13;
pub(crate) const SIGNIFICAND_BITS: u32 = TOTAL_BITS - EXP_BITS;
pub(crate) const FRACTION_BITS: u32 = SIGNIFICAND_BITS - 1;
pub(crate) const EXP_MAX: u32 = (1_u32 << EXP_BITS) - 1;
pub(crate) const EXP_BIAS: u32 = EXP_MAX >> 1;
#[allow(clippy::cast_possible_wrap)]
pub(crate) const EMAX: i32 = (EXP_MAX >> 1) as i32;
pub(crate) const EMIN: i32 = 1 - EMAX;
pub(crate) const HI_TOTAL_BITS: u32 = TOTAL_BITS >> 1;
pub(crate) const HI_SIGN_SHIFT: u32 = HI_TOTAL_BITS - 1;
pub(crate) const HI_FRACTION_BITS: u32 = FRACTION_BITS - HI_TOTAL_BITS;
pub(crate) const HI_FRACTION_BIAS: u128 = 1_u128 << HI_FRACTION_BITS;
pub(crate) const HI_FRACTION_MASK: u128 = HI_FRACTION_BIAS - 1;
pub(crate) const HI_EXP_MASK: u128 = (EXP_MAX as u128) << HI_FRACTION_BITS;
pub(crate) const HI_SIGN_MASK: u128 = 1_u128 << HI_SIGN_SHIFT;
pub(crate) const HI_ABS_MASK: u128 = !HI_SIGN_MASK;
pub(crate) const NAN_HI: u128 =
HI_EXP_MASK | (1_u128 << (HI_FRACTION_BITS - 1));
pub(crate) const INF_HI: u128 = HI_EXP_MASK;
pub(crate) const NEG_INF_HI: u128 = HI_SIGN_MASK | HI_EXP_MASK;
pub(crate) const EPSILON_HI: u128 =
((EXP_BIAS - FRACTION_BITS) as u128) << HI_FRACTION_BITS;
pub(crate) const MAX_HI: u128 =
(1_u128 << (u128::BITS - 1)) - (1_u128 << HI_FRACTION_BITS) - 1;
#[allow(clippy::cast_possible_wrap)]
pub(crate) const INT_EXP: i32 = -(FRACTION_BITS as i32);
pub(crate) const MIN_NO_FRACT_HI: u128 =
((EXP_BIAS + FRACTION_BITS) as u128) << HI_FRACTION_BITS;
pub(crate) const MIN_GT_ZERO_10_EXP: i32 = -78984;
pub(crate) const FIVE: f256 = f256::from_u64(5);
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Default)]
pub struct f256 {
pub(crate) bits: U256,
}
const EPSILON: f256 = f256 {
bits: U256::new(EPSILON_HI, 0),
};
const MAX: f256 = f256 {
bits: U256::new(MAX_HI, u128::MAX),
};
const MIN: f256 = MAX.negated();
const MIN_POSITIVE: f256 = f256 {
bits: U256::new(HI_FRACTION_BIAS, 0),
};
const MIN_GT_ZERO: f256 = f256 { bits: U256::ONE };
const NAN: f256 = f256 {
bits: U256::new(NAN_HI, 0),
};
const INFINITY: f256 = f256 {
bits: U256::new(INF_HI, 0),
};
const NEG_INFINITY: f256 = f256 {
bits: U256::new(NEG_INF_HI, 0),
};
const ZERO: f256 = f256 { bits: U256::ZERO };
const NEG_ZERO: f256 = ZERO.negated();
pub(crate) const ONE_HALF: f256 = f256 {
bits: U256::new((((EXP_BIAS - 1) as u128) << HI_FRACTION_BITS), 0),
};
const ONE: f256 = f256 {
bits: U256::new(((EXP_BIAS as u128) << HI_FRACTION_BITS), 0),
};
const NEG_ONE: f256 = ONE.negated();
const TWO: f256 = f256 {
bits: U256::new((((1 + EXP_BIAS) as u128) << HI_FRACTION_BITS), 0),
};
const TEN: f256 = f256::from_u64(10);
#[allow(clippy::multiple_inherent_impl)]
impl f256 {
pub const RADIX: u32 = 2;
pub const MANTISSA_DIGITS: u32 = SIGNIFICAND_BITS;
pub const SIGNIFICANT_DIGITS: u32 = SIGNIFICAND_BITS;
pub const DIGITS: u32 = 71;
pub const EPSILON: Self = EPSILON;
pub const MAX: Self = MAX;
pub const MIN: Self = MIN;
pub const MIN_POSITIVE: Self = MIN_POSITIVE;
pub const MIN_GT_ZERO: Self = MIN_GT_ZERO;
pub const MAX_EXP: i32 = EMAX + 1;
pub const MIN_EXP: i32 = EMIN + 1;
pub const MAX_10_EXP: i32 = 78913;
pub const MIN_10_EXP: i32 = -78912;
pub const NAN: Self = NAN;
pub const INFINITY: Self = INFINITY;
pub const NEG_INFINITY: Self = NEG_INFINITY;
pub const ZERO: Self = ZERO;
pub const NEG_ZERO: Self = NEG_ZERO;
pub const ONE: Self = ONE;
pub const NEG_ONE: Self = NEG_ONE;
pub const TWO: Self = TWO;
pub const TEN: Self = TEN;
#[allow(clippy::cast_possible_wrap)]
#[allow(clippy::cast_sign_loss)]
#[inline]
pub(crate) const fn new(
sign: u32,
exponent: i32,
significand: U256,
) -> Self {
debug_assert!(sign == 0 || sign == 1);
debug_assert!(exponent >= EMIN - 1 && exponent <= EMAX);
debug_assert!(!significand.is_zero());
debug_assert!((significand.hi.0 >> HI_FRACTION_BITS) <= 1_u128);
let biased_exp = (exponent + EXP_BIAS as i32) as u128;
Self {
bits: U256::new(
(significand.hi.0 & HI_FRACTION_MASK)
| (biased_exp << HI_FRACTION_BITS)
| ((sign as u128) << HI_SIGN_SHIFT),
significand.lo.0,
),
}
}
#[allow(clippy::cast_possible_wrap)]
#[allow(clippy::cast_sign_loss)]
pub(crate) fn encode(s: u32, mut t: i32, mut c: U256) -> Self {
debug_assert!(!c.is_zero());
t += FRACTION_BITS as i32;
let nlz = c.leading_zeros();
match nlz.cmp(&EXP_BITS) {
Ordering::Greater => {
let shift = (nlz - EXP_BITS);
if t >= EMIN + shift as i32 {
c <<= shift;
t -= shift as i32;
} else {
c <<= (t - EMIN) as u32;
t = EMIN - 1;
}
}
Ordering::Less => {
let mut shift = (EXP_BITS - nlz);
t += shift as i32;
c = c.rounding_div_pow2(shift);
if (c.hi.0 >> (HI_FRACTION_BITS + 1)) != 0 {
t += 1;
c >>= 1;
}
}
_ => {}
}
debug_assert!(
(EMIN - 1..=EMAX).contains(&t),
"Exponent limits exceeded: {t}"
);
Self::new(s, t, c)
}
#[allow(clippy::cast_possible_wrap)]
#[allow(clippy::cast_sign_loss)]
pub(crate) const fn power_of_two(n: i32) -> Self {
const LOW_LIM: i32 = EMIN - FRACTION_BITS as i32;
match n {
EMIN..=EMAX => Self {
bits: U256::new(
((n + EXP_BIAS as i32) as u128) << HI_FRACTION_BITS,
0_u128,
),
},
LOW_LIM..EMIN => Self {
bits: U256::power_of_two((n - LOW_LIM) as u32),
},
..LOW_LIM => Self::ZERO,
_ => Self::INFINITY,
}
}
#[doc(hidden)]
#[must_use]
pub fn from_sign_exp_signif(s: u32, t: i32, c: (u128, u128)) -> Self {
debug_assert!(s == 0 || s == 1);
let c = U256::new(c.0, c.1);
if c.is_zero() {
if t == 0 {
return [Self::ZERO, Self::NEG_ZERO][s as usize];
}
if t == EMAX + 1 {
return [Self::INFINITY, Self::NEG_INFINITY][s as usize];
}
}
Self::encode(s, t, c)
}
#[inline]
pub(crate) const fn sign(&self) -> u32 {
(self.bits.hi.0 >> HI_SIGN_SHIFT) as u32
}
#[inline]
pub(crate) const fn biased_exponent(&self) -> u32 {
((self.bits.hi.0 & HI_EXP_MASK) >> HI_FRACTION_BITS) as u32
}
#[inline]
#[allow(clippy::cast_possible_wrap)]
pub(crate) const fn quantum_exponent(&self) -> i32 {
debug_assert!(
self.is_finite(),
"Attempt to extract quantum exponent from Infinity or NaN."
);
const TOTAL_BIAS: i32 = EXP_BIAS as i32 + FRACTION_BITS as i32;
let mut exp = self.biased_exponent() as i32;
exp += (exp == 0) as i32; (!self.eq_zero() as i32) * (exp - TOTAL_BIAS)
}
#[inline]
#[allow(clippy::cast_possible_wrap)]
pub(crate) const fn exponent(&self) -> i32 {
debug_assert!(
self.is_finite(),
"Attempt to extract exponent from Infinity or NaN."
);
let mut exp = self.biased_exponent() as i32;
exp += (exp == 0) as i32; (!self.eq_zero() as i32) * (exp - EXP_BIAS as i32)
}
#[inline]
pub(crate) const fn fraction(&self) -> U256 {
U256::new(self.bits.hi.0 & HI_FRACTION_MASK, self.bits.lo.0)
}
#[inline]
pub(crate) const fn integral_significand(&self) -> U256 {
debug_assert!(
self.is_finite(),
"Attempt to extract integral significand from Infinity or NaN."
);
let hidden_one =
((self.biased_exponent() != 0) as u128) << HI_FRACTION_BITS;
U256::new(
(self.bits.hi.0 & HI_FRACTION_MASK) | hidden_one,
self.bits.lo.0,
)
}
pub(crate) fn significand(&self) -> Self {
debug_assert!(
self.is_finite(),
"Attempt to extract significand from Infinity or NaN."
);
if self.eq_zero() {
return *self;
}
let mut biased_exp = EXP_BIAS;
let mut bits =
U256::new((self.bits.hi.0 & HI_FRACTION_MASK), self.bits.lo.0);
if self.biased_exponent() == 0 {
let shift = (bits.leading_zeros() - EXP_BITS);
bits = bits.shift_left(shift);
biased_exp -= shift + 1;
}
bits.hi.0 += (biased_exp as u128) << HI_FRACTION_BITS;
Self { bits }
}
#[allow(clippy::cast_possible_wrap)]
pub(crate) fn decode(&self) -> (u32, i32, U256) {
debug_assert!(
self.is_finite(),
"Attempt to extract sign, exponent and significand from \
Infinity or NaN."
);
let (s, mut t, mut c) = split_f256_enc(self);
if !c.is_zero() {
let ntz = c.trailing_zeros();
c >>= ntz;
t += ntz as i32;
}
(s, t, c)
}
#[doc(hidden)]
#[must_use]
pub fn as_sign_exp_signif(&self) -> (u32, i32, (u128, u128)) {
let (s, t, c) = self.decode();
(s, t, (c.hi.0, c.lo.0))
}
#[must_use]
#[inline]
pub const fn is_nan(self) -> bool {
((self.bits.hi.0 & HI_ABS_MASK) | (self.bits.lo.0 != 0) as u128)
> HI_EXP_MASK
}
#[must_use]
#[inline]
pub const fn is_infinite(self) -> bool {
(self.bits.hi.0 & HI_ABS_MASK) == HI_EXP_MASK && self.bits.lo.0 == 0
}
#[must_use]
#[inline]
pub const fn is_finite(self) -> bool {
(self.bits.hi.0 & HI_EXP_MASK) != HI_EXP_MASK
}
#[must_use]
#[inline]
pub const fn is_subnormal(self) -> bool {
(self.bits.hi.0 & HI_EXP_MASK) == 0 && !self.eq_zero()
}
#[must_use]
#[inline]
pub const fn is_normal(self) -> bool {
self.biased_exponent().wrapping_sub(1) < EXP_MAX - 1
}
#[inline]
#[must_use]
#[allow(clippy::match_overlapping_arm)]
pub const fn classify(&self) -> FpCategory {
let abs_bits_sticky = abs_bits_sticky(&abs_bits(self));
match abs_bits_sticky {
0 => FpCategory::Zero,
INF_HI => FpCategory::Infinite,
NAN_HI => FpCategory::Nan,
..=HI_FRACTION_MASK => FpCategory::Subnormal,
_ => FpCategory::Normal,
}
}
#[must_use]
#[inline]
pub const fn eq_zero(self) -> bool {
(self.bits.hi.0 << 1) == 0 && self.bits.lo.0 == 0
}
#[must_use]
#[inline]
pub const fn is_special(self) -> bool {
(self.bits.hi.0 & HI_ABS_MASK | (self.bits.lo.0 != 0) as u128)
.wrapping_sub(1)
>= MAX_HI
}
#[must_use]
#[inline]
pub const fn is_sign_positive(self) -> bool {
self.bits.hi.0 < HI_SIGN_MASK
}
#[must_use]
#[inline]
pub const fn is_sign_negative(self) -> bool {
self.bits.hi.0 >= HI_SIGN_MASK
}
#[must_use]
#[inline]
pub(crate) fn is_integer(self) -> bool {
is_int(&abs_bits(&self))
}
#[allow(clippy::cast_possible_wrap)]
pub(crate) fn parity(&self) -> Option<Parity> {
if self.is_special() {
return [None, Some(Parity::Even)][self.eq_zero() as usize];
}
let (_, exp, signif) = split_f256_enc(self);
let ntz = signif.trailing_zeros();
const LIM: i32 = FRACTION_BITS as i32;
match exp + ntz as i32 {
..=-1 => None,
0..=LIM => Some((signif >> exp.unsigned_abs()).parity()),
_ => Some(Parity::Even),
}
}
#[must_use]
pub fn ulp(&self) -> Self {
let abs_bits_self = abs_bits(self);
let mut exp_bits = exp_bits(&abs_bits_self);
if exp_bits < EXP_MAX {
let mut bits = U256::new(HI_FRACTION_BIAS, 0_u128);
let sh = FRACTION_BITS
.saturating_sub(exp_bits - norm_bit(&abs_bits_self));
exp_bits = exp_bits.saturating_sub(FRACTION_BITS + 1);
bits >>= sh;
bits.hi.0 += (exp_bits as u128) << HI_FRACTION_BITS;
Self { bits }
} else {
NAN
}
}
#[must_use]
#[inline]
pub(crate) fn almost_eq(&self, other: &Self) -> bool {
(self - other).abs() <= self.ulp()
}
#[doc(hidden)]
#[must_use]
#[inline]
pub fn diff_within_n_bits(&self, other: &Self, n: u32) -> bool {
(self - other).abs() <= self.ulp().mul_pow2(n)
}
#[must_use]
#[inline]
pub fn recip(self) -> Self {
Self::ONE / self
}
#[must_use]
#[inline]
#[allow(clippy::cast_possible_wrap)]
pub fn to_degrees(self) -> Self {
const M: U256 = U256::new(
304636616676435425756912514760952666071,
69798147688063442975655060594812004816,
);
const SH: i32 = 250_i32;
let signif = self.integral_significand();
let exp = self.quantum_exponent();
let (lo, hi) = M.widening_mul(&signif);
let mut t = U512::from_hi_lo(hi, lo);
let sh = signif.msb() + 256 - SIGNIFICAND_BITS;
t = t.rounding_div_pow2(sh);
Self::encode(self.sign(), exp - SH + sh as i32, t.lo)
}
#[must_use]
#[inline]
#[allow(clippy::cast_possible_wrap)]
pub fn to_radians(self) -> Self {
const M: U256 = U256::new(
190049526055994088508387621895443694809,
953738875812114979603059177117484306,
);
const SH: i32 = 261_i32;
let signif = self.integral_significand();
let exp = self.quantum_exponent();
let (lo, hi) = M.widening_mul(&signif);
let mut t = U512::from_hi_lo(hi, lo);
let sh = signif.msb() + 256 - SIGNIFICAND_BITS;
t = t.rounding_div_pow2(sh);
Self::encode(self.sign(), exp - SH + sh as i32, t.lo)
}
#[must_use]
#[inline]
pub fn max(self, other: Self) -> Self {
if other > self || self.is_nan() {
return other;
}
self
}
#[must_use]
#[inline]
pub fn min(self, other: Self) -> Self {
if other < self || self.is_nan() {
return other;
}
self
}
#[inline]
#[must_use]
pub const fn to_bits(&self) -> (u128, u128) {
(self.bits.hi.0, self.bits.lo.0)
}
#[inline]
#[must_use]
pub const fn from_bits(bits: (u128, u128)) -> Self {
Self {
bits: U256::new(bits.0, bits.1),
}
}
#[must_use]
#[inline]
#[allow(unsafe_code)]
pub const fn to_be_bytes(self) -> [u8; 32] {
let bytes =
[self.bits.hi.0.to_be_bytes(), self.bits.lo.0.to_be_bytes()];
unsafe { core::mem::transmute(bytes) }
}
#[must_use]
#[inline]
#[allow(unsafe_code)]
pub const fn to_le_bytes(self) -> [u8; 32] {
let bytes =
[self.bits.lo.0.to_le_bytes(), self.bits.hi.0.to_le_bytes()];
unsafe { core::mem::transmute(bytes) }
}
#[must_use]
#[inline]
#[allow(unsafe_code)]
pub const fn to_ne_bytes(self) -> [u8; 32] {
let bits = self.to_bits();
unsafe { core::mem::transmute(bits) }
}
#[must_use]
#[inline]
#[allow(unsafe_code)]
pub const fn from_be_bytes(bytes: [u8; 32]) -> Self {
let bits: [[u8; 16]; 2] = unsafe { core::mem::transmute(bytes) };
Self {
bits: U256::new(
u128::from_be_bytes(bits[0]),
u128::from_be_bytes(bits[1]),
),
}
}
#[must_use]
#[inline]
#[allow(unsafe_code)]
pub const fn from_le_bytes(bytes: [u8; 32]) -> Self {
let bits: [[u8; 16]; 2] = unsafe { core::mem::transmute(bytes) };
Self {
bits: U256::new(
u128::from_le_bytes(bits[1]),
u128::from_le_bytes(bits[0]),
),
}
}
#[must_use]
#[inline]
#[allow(unsafe_code)]
pub const fn from_ne_bytes(bytes: [u8; 32]) -> Self {
let bits: (u128, u128) = unsafe { core::mem::transmute(bytes) };
Self::from_bits(bits)
}
#[must_use]
#[inline]
pub fn total_cmp(&self, other: &Self) -> Ordering {
self.negated().bits.cmp(&(*other).negated().bits)
}
#[must_use]
#[inline]
pub fn clamp(self, min: Self, max: Self) -> Self {
assert!(min <= max);
if self < min {
min
} else if self > max {
max
} else {
self
}
}
#[inline(always)]
#[must_use]
pub const fn abs(&self) -> Self {
Self {
bits: U256::new(self.bits.hi.0 & HI_ABS_MASK, self.bits.lo.0),
}
}
#[must_use]
fn as_integer(
&self,
lt1: fn(u32, U256) -> Self,
gt1: fn(u32, U256) -> Self,
) -> Self {
let mut abs_bits = abs_bits(self);
if is_int(&abs_bits) || abs_bits.is_special() {
*self
} else {
let sign = self.sign();
if abs_bits.hi.0 < ONE.bits.hi.0 {
lt1(sign, abs_bits)
} else {
gt1(sign, abs_bits)
}
}
}
#[must_use]
pub fn trunc(&self) -> Self {
self.as_integer(
|sign, abs_bits| Self::ZERO,
|sign, abs_bits| {
let n_fract_bits =
FRACTION_BITS - (exp_bits(&abs_bits) - EXP_BIAS);
let mut int_bits = (abs_bits >> n_fract_bits) << n_fract_bits;
int_bits.hi.0 |= (sign as u128) << HI_SIGN_SHIFT;
Self { bits: int_bits }
},
)
}
#[inline]
#[must_use]
pub fn fract(&self) -> Self {
self - self.trunc()
}
#[inline]
#[must_use]
pub fn split(&self) -> (Self, Self) {
let int_part = self.trunc();
(int_part, self - int_part)
}
#[must_use]
pub fn ceil(&self) -> Self {
self.as_integer(
|sign, abs_bits| [Self::ONE, Self::ZERO][sign as usize],
|sign, abs_bits| {
let n_fract_bits =
FRACTION_BITS - (exp_bits(&abs_bits) - EXP_BIAS);
let mut int_bits = abs_bits >> n_fract_bits;
int_bits += &U256::new(0, (sign == 0) as u128);
int_bits <<= n_fract_bits;
int_bits.hi.0 |= (sign as u128) << HI_SIGN_SHIFT;
Self { bits: int_bits }
},
)
}
#[must_use]
pub fn floor(&self) -> Self {
self.as_integer(
|sign, abs_bits| [Self::ZERO, Self::NEG_ONE][sign as usize],
|sign, abs_bits| {
let n_fract_bits =
FRACTION_BITS - (exp_bits(&abs_bits) - EXP_BIAS);
let mut int_bits = abs_bits >> n_fract_bits;
int_bits += &U256::new(0, sign as u128);
int_bits <<= n_fract_bits;
int_bits.hi.0 |= (sign as u128) << HI_SIGN_SHIFT;
Self { bits: int_bits }
},
)
}
#[must_use]
pub fn round(&self) -> Self {
self.as_integer(
|sign, abs_bits| {
if abs_bits.hi.0 < ONE_HALF.bits.hi.0 {
Self::ZERO
} else {
[Self::ONE, Self::NEG_ONE][sign as usize]
}
},
|sign, abs_bits| {
let n_fract_bits =
FRACTION_BITS - (exp_bits(&abs_bits) - EXP_BIAS);
let tie = U256::ONE << (n_fract_bits - 1);
let rem = abs_bits.rem_pow2(n_fract_bits);
let mut int_bits = abs_bits >> n_fract_bits;
if rem >= tie {
int_bits.incr();
}
int_bits <<= n_fract_bits;
int_bits.hi.0 |= (sign as u128) << HI_SIGN_SHIFT;
Self { bits: int_bits }
},
)
}
#[must_use]
pub fn round_tie_even(&self) -> Self {
self.as_integer(
|sign, abs_bits| {
if abs_bits.hi.0 <= ONE_HALF.bits.hi.0 {
Self::ZERO
} else {
[Self::ONE, Self::NEG_ONE][sign as usize]
}
},
|sign, abs_bits| {
let n_fract_bits =
FRACTION_BITS - (exp_bits(&abs_bits) - EXP_BIAS);
let mut int_bits = abs_bits.rounding_div_pow2(n_fract_bits);
int_bits <<= n_fract_bits;
int_bits.hi.0 |= (sign as u128) << HI_SIGN_SHIFT;
Self { bits: int_bits }
},
)
}
#[inline(always)]
pub(crate) const fn negated(&self) -> Self {
Self {
bits: U256::new(self.bits.hi.0 ^ HI_SIGN_MASK, self.bits.lo.0),
}
}
#[inline(always)]
#[must_use]
pub fn mul2(&self) -> Self {
self.mul_pow2(1)
}
#[must_use]
#[allow(clippy::cast_possible_wrap)]
pub fn mul_pow2(&self, n: u32) -> Self {
let abs_bits = abs_bits(self);
if abs_bits.is_special() {
return *self;
}
let exp_bits = exp_bits(&abs_bits);
if exp_bits.saturating_add(n) >= EXP_MAX {
return [Self::INFINITY, Self::NEG_INFINITY]
[self.sign() as usize];
}
if exp_bits == 0 {
const EXP: i32 = 1 - (EXP_BIAS as i32 + FRACTION_BITS as i32);
let fraction = fraction(&abs_bits);
let exp = EXP + n as i32;
return Self::from_sign_exp_signif(
self.sign(),
exp,
(fraction.hi.0, fraction.lo.0),
);
}
Self {
bits: U256::new(
self.bits.hi.0 + ((n as u128) << HI_FRACTION_BITS),
self.bits.lo.0,
),
}
}
#[inline(always)]
#[must_use]
pub fn mul_add(self, f: Self, a: Self) -> Self {
fused_ops::fma::fma(&self, &f, &a)
}
#[inline(always)]
#[must_use]
pub fn sum_of_squares(self, other: Self) -> Self {
fused_ops::sos::sos(&self, &other)
}
#[inline(always)]
#[must_use]
pub fn square(self) -> Self {
self * self
}
#[inline(always)]
#[must_use]
pub fn square_add(self, a: Self) -> Self {
fused_ops::fma::fma(&self, &self, &a)
}
#[inline(always)]
#[must_use]
pub fn div2(&self) -> Self {
self.div_pow2(1)
}
#[must_use]
#[allow(clippy::cast_possible_wrap)]
pub fn div_pow2(&self, n: u32) -> Self {
let abs_bits = abs_bits(self);
if abs_bits.is_special() {
return *self;
}
let exp_bits = exp_bits(&abs_bits);
if exp_bits <= n {
const EXP: i32 = 1 - (EXP_BIAS as i32 + FRACTION_BITS as i32);
let shr = n - exp_bits + norm_bit(&abs_bits);
if shr > self.bits.msb() {
return [Self::ZERO, Self::NEG_ZERO][self.sign() as usize];
}
let signif = signif(&abs_bits).rounding_div_pow2(shr);
if signif.is_zero() {
return [Self::ZERO, Self::NEG_ZERO][self.sign() as usize];
}
return Self::from_sign_exp_signif(
self.sign(),
EXP,
(signif.hi.0, signif.lo.0),
);
}
Self {
bits: U256::new(
self.bits.hi.0 - ((n as u128) << HI_FRACTION_BITS),
self.bits.lo.0,
),
}
}
}
impl Neg for f256 {
type Output = Self;
#[inline(always)]
fn neg(self) -> Self::Output {
self.negated()
}
}
impl Neg for &f256 {
type Output = <f256 as Neg>::Output;
#[inline(always)]
fn neg(self) -> Self::Output {
self.negated()
}
}
impl TryFrom<&f256> for i32 {
type Error = ();
#[allow(clippy::cast_possible_wrap)]
#[allow(clippy::cast_possible_truncation)]
fn try_from(value: &f256) -> Result<Self, Self::Error> {
let (sign, exp, signif) = split_f256_enc(value);
let ntz = signif.trailing_zeros();
match exp + ntz as Self {
n @ 0..=30 => {
let t = (signif >> exp.unsigned_abs()).lo_t().0 as Self;
Ok([t, -t][sign as usize])
}
31 => [Err(()), Ok(Self::MIN)][sign as usize],
256 => Ok(0),
_ => Err(()),
}
}
}
#[inline(always)]
pub(crate) const fn sign_bits_hi(f: &f256) -> u128 {
f.bits.hi.0 & HI_SIGN_MASK
}
#[inline(always)]
pub(crate) const fn abs_bits(f: &f256) -> U256 {
U256::new(f.bits.hi.0 & HI_ABS_MASK, f.bits.lo.0)
}
#[inline(always)]
pub(crate) const fn abs_bits_sticky(abs_bits: &U256) -> u128 {
abs_bits.hi.0 | (abs_bits.lo.0 != 0) as u128
}
#[allow(clippy::cast_possible_wrap)]
pub(crate) fn is_int(abs_bits: &U256) -> bool {
*abs_bits == U256::ZERO ||
abs_bits.hi.0 >= MIN_NO_FRACT_HI ||
exp(abs_bits) >=
FRACTION_BITS.saturating_sub(abs_bits.trailing_zeros()) as i32
}
pub(crate) trait BinEncSpecial {
fn is_special(&self) -> bool;
}
impl BinEncSpecial for u128 {
#[inline(always)]
fn is_special(&self) -> bool {
self.wrapping_sub(1) >= MAX_HI
}
}
impl BinEncSpecial for U256 {
#[inline(always)]
fn is_special(&self) -> bool {
abs_bits_sticky(self).is_special()
}
}
pub(crate) trait BinEncAnySpecial {
fn any_special(&self) -> bool;
fn any_subnormal(&self) -> bool;
fn any_non_normal(&self) -> bool;
}
impl BinEncAnySpecial for (u128, u128) {
#[inline(always)]
fn any_special(&self) -> bool {
self.0.wrapping_sub(1) >= MAX_HI || self.1.wrapping_sub(1) >= MAX_HI
}
#[inline(always)]
fn any_subnormal(&self) -> bool {
self.0 <= HI_FRACTION_MASK || self.1 <= HI_FRACTION_MASK
}
#[inline(always)]
fn any_non_normal(&self) -> bool {
self.any_special() || self.any_subnormal()
}
}
impl BinEncAnySpecial for (u128, u128, u128) {
#[inline(always)]
fn any_special(&self) -> bool {
self.0.wrapping_sub(1) >= MAX_HI
|| self.1.wrapping_sub(1) >= MAX_HI
|| self.2.wrapping_sub(1) >= MAX_HI
}
#[inline(always)]
fn any_subnormal(&self) -> bool {
self.0 <= HI_FRACTION_MASK
|| self.1 <= HI_FRACTION_MASK
|| self.2 <= HI_FRACTION_MASK
}
#[inline(always)]
fn any_non_normal(&self) -> bool {
self.any_special() || self.any_subnormal()
}
}
#[inline(always)]
pub(crate) const fn norm_bit(abs_bits: &U256) -> u32 {
(abs_bits.hi.0 >= HI_FRACTION_BIAS) as u32
}
#[inline(always)]
pub(crate) const fn exp_bits(abs_bits: &U256) -> u32 {
(abs_bits.hi.0 >> HI_FRACTION_BITS) as u32
}
#[inline(always)]
#[allow(clippy::cast_possible_wrap)]
pub(crate) const fn exp(abs_bits: &U256) -> i32 {
debug_assert!(!abs_bits.is_zero());
let mut exp = (abs_bits.hi.0 >> HI_FRACTION_BITS) as i32;
exp + (exp == 0) as i32 - EXP_BIAS as i32
}
#[inline(always)]
pub(crate) const fn fraction(abs_bits: &U256) -> U256 {
U256::new(abs_bits.hi.0 & HI_FRACTION_MASK, abs_bits.lo.0)
}
#[inline(always)]
pub(crate) const fn signif(abs_bits: &U256) -> U256 {
U256::new(
(((abs_bits.hi.0 >= HI_FRACTION_BIAS) as u128) << HI_FRACTION_BITS)
| (abs_bits.hi.0 & HI_FRACTION_MASK),
abs_bits.lo.0,
)
}
#[inline(always)]
pub(crate) fn norm_signif(abs_bits: &U256) -> (U256, u32) {
debug_assert!(!abs_bits.is_zero());
let signif = signif(abs_bits);
let shift = FRACTION_BITS - signif.msb();
(signif.shift_left(shift), shift)
}
#[inline(always)]
#[allow(clippy::cast_possible_wrap)]
pub(crate) fn norm_signif_exp(abs_bits: &U256) -> (U256, i32) {
let (signif, shift) = norm_signif(abs_bits);
let exp = exp(abs_bits) - shift as i32;
(signif, exp)
}
#[inline(always)]
pub(crate) fn left_adj_signif(abs_bits: &U256) -> (U256, u32) {
debug_assert!(!abs_bits.is_zero());
let signif = signif(abs_bits);
let shift = signif.leading_zeros();
(signif.shift_left(shift), shift)
}
#[allow(clippy::cast_possible_wrap)]
pub(crate) const fn split_f256_enc(f: &f256) -> (u32, i32, U256) {
const TOTAL_BIAS: i32 = EXP_BIAS as i32 + FRACTION_BITS as i32;
let sign = f.sign();
let abs_bits = abs_bits(f);
let exp_bits = exp_bits(&abs_bits);
let fraction = fraction(&abs_bits);
match (exp_bits, fraction) {
(0, U256::ZERO) => (sign, 0, U256::ZERO),
(0, _) => (sign, 1 - TOTAL_BIAS, fraction),
(EXP_MAX, _) => (sign, exp_bits as i32, fraction),
_ => (
sign,
exp_bits as i32 - TOTAL_BIAS,
U256::new(fraction.hi.0 | HI_FRACTION_BIAS, fraction.lo.0),
),
}
}
#[inline]
pub(crate) fn fast_sum(a: &f256, b: &f256) -> (f256, f256) {
debug_assert!(a.abs() >= b.abs());
let s = a + b;
let r = b - (s - a);
(s, r)
}
pub(crate) fn sum(a: &f256, b: &f256) -> (f256, f256) {
let s = a + b;
let ta = a - (s - b);
let tb = b - (s - ta);
let r = ta + tb;
(s, r)
}
#[inline]
pub(crate) fn fast_mul(a: &f256, b: &f256) -> (f256, f256) {
debug_assert!(a.biased_exponent() + b.biased_exponent() >= EXP_BIAS);
let p = a * b;
let r = a.mul_add(*b, -p);
(p, r)
}
#[cfg(test)]
mod repr_tests {
use super::*;
#[test]
fn test_zero() {
let z = f256::ZERO;
assert_eq!(z.sign(), 0);
assert_eq!(z.quantum_exponent(), 0);
assert_eq!(z.integral_significand(), U256::default());
assert_eq!(z.decode(), (0, 0, U256::default()));
assert_eq!(z.exponent(), 0);
assert_eq!(z.significand(), f256::ZERO);
assert!(z.is_integer());
let z = f256::NEG_ZERO;
assert_eq!(z.sign(), 1);
assert_eq!(z.quantum_exponent(), 0);
assert_eq!(z.integral_significand(), U256::default());
assert_eq!(z.decode(), (1, 0, U256::default()));
assert_eq!(z.exponent(), 0);
assert_eq!(z.significand(), f256::ZERO);
assert!(z.is_integer());
}
#[test]
fn test_one() {
let i = f256::ONE;
assert_eq!(i.sign(), 0);
assert_eq!(i.biased_exponent(), EXP_BIAS);
assert_eq!(i.quantum_exponent(), INT_EXP);
assert_eq!(
i.integral_significand(),
U256::new(1_u128 << HI_FRACTION_BITS, 0)
);
assert_eq!(i.decode(), (0, 0, U256::ONE));
assert_eq!(i.exponent(), 0);
assert_eq!(i.significand(), f256::ONE);
assert!(i.is_integer());
let i = f256::NEG_ONE;
assert_eq!(i.sign(), 1);
assert_eq!(i.biased_exponent(), EXP_BIAS);
assert_eq!(i.quantum_exponent(), INT_EXP);
assert_eq!(
i.integral_significand(),
U256::new(1_u128 << HI_FRACTION_BITS, 0)
);
assert_eq!(i.decode(), (1, 0, U256::ONE));
assert_eq!(i.exponent(), 0);
assert_eq!(i.significand(), f256::ONE);
assert!(i.is_integer());
}
#[test]
fn test_normal() {
let i = f256::TWO;
assert_eq!(i.sign(), 0);
assert_eq!(i.biased_exponent(), EXP_BIAS + 1);
assert_eq!(i.quantum_exponent(), INT_EXP + 1);
assert_eq!(
i.integral_significand(),
U256::new(1_u128 << HI_FRACTION_BITS, 0)
);
assert_eq!(i.decode(), (0, 1, U256::ONE));
assert_eq!(i.exponent(), 1);
assert_eq!(i.significand(), f256::ONE);
assert!(i.is_integer());
let f = f256::from(-3.5_f64);
assert_eq!(f.sign(), 1);
assert_eq!(f.quantum_exponent(), -235);
assert_eq!(
f.integral_significand(),
U256::new(567907468902246771870523036008448, 0)
);
assert_eq!(f.decode(), (1, -1, U256::new(0_u128, 7_u128)));
assert_eq!(f.exponent(), 1);
assert_eq!(f.significand(), f.abs() / f256::TWO);
assert!(!f.is_integer());
}
#[test]
#[allow(clippy::cast_possible_wrap)]
fn test_subnormal() {
let f = f256::MIN_GT_ZERO;
assert_eq!(f.sign(), 0);
assert_eq!(f.quantum_exponent(), EMIN - FRACTION_BITS as i32);
assert_eq!(f.integral_significand(), U256::ONE);
assert_eq!(f.decode(), (0, EMIN - FRACTION_BITS as i32, U256::ONE));
assert_eq!(f.exponent(), EMIN);
assert_eq!(
f.significand(),
f256::from_sign_exp_signif(0, -(FRACTION_BITS as i32), (0, 1))
);
let f = f256::from_sign_exp_signif(
1,
EMIN - FRACTION_BITS as i32 + 17,
(7, 29),
);
assert!(f.is_subnormal());
assert_eq!(f.exponent(), EMIN);
assert_eq!(
f.significand(),
f256::from_sign_exp_signif(
0,
17 - (FRACTION_BITS as i32),
(7, 29)
)
);
}
}
#[cfg(test)]
mod encode_decode_tests {
use super::*;
#[test]
fn test_normal() {
let sign = 1_u32;
let exponent = -23_i32;
let significand = U256::new(39, 10000730744);
let f = f256::encode(sign, exponent, significand);
let (s, t, c) = f.decode();
let g = f256::encode(s, t, c);
assert_eq!(f, g);
}
#[test]
fn test_subnormal() {
let sign = 0_u32;
let exponent = EMIN - 235_i32;
let significand = U256::new(u128::MAX >> (EXP_BITS + 2), 0);
let f = f256::encode(sign, exponent, significand);
assert!(f.is_subnormal());
let (s, t, c) = f.decode();
let g = f256::encode(s, t, c);
assert_eq!(f, g);
let f = f256::MIN_GT_ZERO;
let (s, t, c) = f.decode();
let g = f256::encode(s, t, c);
assert_eq!(f, g);
}
}
#[cfg(test)]
mod raw_bits_tests {
use super::*;
#[test]
fn test_to_from_bits() {
let f = f256::TEN;
let bits = f.to_bits();
assert_eq!(bits.0, f.bits.hi.0);
assert_eq!(bits.1, f.bits.lo.0);
let g = f256::from_bits(bits);
assert_eq!(f, g);
}
#[test]
fn test_to_from_ne_bytes() {
let f = f256::TEN;
let bytes = f.to_ne_bytes();
let g = f256::from_ne_bytes(bytes);
assert_eq!(f, g);
}
#[test]
fn test_to_from_be_bytes() {
let f = f256::TEN;
let bytes = f.to_be_bytes();
let g = f256::from_be_bytes(bytes);
assert_eq!(f, g);
}
#[test]
fn test_to_from_le_bytes() {
let f = f256::TEN;
let bytes = f.to_le_bytes();
let g = f256::from_le_bytes(bytes);
assert_eq!(f, g);
}
}
#[cfg(test)]
mod split_tests {
use super::*;
#[test]
fn test_normal() {
let f = f256::from(17);
let g = f256::from(17.625_f64);
let h = -g;
let (fi, ff) = f.split();
assert_eq!(fi, f);
assert_eq!(fi.quantum_exponent(), f.quantum_exponent());
assert_eq!(ff, f256::ZERO);
let (gi, gf) = g.split();
assert_eq!(gi, f);
assert_eq!(gi.quantum_exponent(), g.quantum_exponent());
assert_eq!(gf, g - f);
assert_eq!(h.split(), (-f, (f - g)));
}
#[test]
fn test_lt_1() {
let f = f256::from(0.99999_f64);
let (fi, ff) = f.split();
assert_eq!(fi, f256::ZERO);
assert_eq!(fi.quantum_exponent(), 0);
assert_eq!(ff, f);
assert_eq!(ff.quantum_exponent(), f.quantum_exponent());
}
#[test]
fn test_subnormal() {
let f = f256::MIN_GT_ZERO;
assert_eq!(f.split(), (f256::ZERO, f256::MIN_GT_ZERO));
}
}
#[cfg(test)]
mod ulp_tests {
use super::*;
#[test]
fn test_special() {
assert_eq!(f256::ZERO.ulp(), MIN_GT_ZERO);
assert!(f256::INFINITY.ulp().is_nan());
assert!(f256::NEG_INFINITY.ulp().is_nan());
assert!(f256::NAN.ulp().is_nan());
}
#[test]
fn test_normal() {
assert_eq!(f256::ONE.ulp(), f256::EPSILON);
assert_eq!(f256::TWO.ulp(), f256::TWO * f256::EPSILON);
assert_eq!(f256::from(3).ulp(), f256::TWO * f256::EPSILON);
assert_eq!(f256::TEN.ulp(), f256::from(8) * f256::EPSILON);
assert_eq!(f256::MIN_POSITIVE.ulp(), f256::MIN_GT_ZERO);
assert_eq!(
f256::MIN.ulp(),
f256::from_sign_exp_signif(
0,
EMAX - FRACTION_BITS as i32,
(0, 1),
)
);
}
#[test]
fn test_subnormal() {
let f = f256::MIN_POSITIVE - f256::MIN_GT_ZERO;
assert_eq!(f.ulp(), f256::MIN_GT_ZERO);
assert_eq!(f256::MIN_GT_ZERO.ulp(), f256::MIN_GT_ZERO);
}
}
#[cfg(test)]
mod to_i32_tests {
use super::*;
#[test]
fn test_ok() {
assert_eq!((&f256::ZERO).try_into(), Ok(0_i32));
assert_eq!((&f256::TWO).try_into(), Ok(2_i32));
assert_eq!((&f256::TEN.neg()).try_into(), Ok(-10_i32));
let max = f256::ONE.mul_pow2(31) - f256::ONE;
assert_eq!((&max).try_into(), Ok(i32::MAX));
let mut min = f256::ONE.mul_pow2(31).neg();
assert_eq!((&min).try_into(), Ok(i32::MIN));
assert_eq!((&(min + f256::ONE)).try_into(), Ok(i32::MIN + 1));
assert_eq!((&(min.div2())).try_into(), Ok(i32::MIN / 2));
assert_eq!(
(&(min.div2() + f256::ONE)).try_into(),
Ok(i32::MIN / 2 + 1)
);
}
#[test]
fn test_err() {
assert!(<&f256 as TryInto<i32>>::try_into(&f256::NAN).is_err());
assert!(
<&f256 as TryInto<i32>>::try_into(&f256::NEG_INFINITY).is_err()
);
assert!(<&f256 as TryInto<i32>>::try_into(&f256::INFINITY).is_err());
assert!(<&f256 as TryInto<i32>>::try_into(&ONE_HALF).is_err());
assert!(<&f256 as TryInto<i32>>::try_into(&f256::from(1234567.89))
.is_err());
assert!(<&f256 as TryInto<i32>>::try_into(&f256::from(
i32::MAX as i64 + 1
))
.is_err());
}
}
#[cfg(test)]
mod parity_tests {
use super::*;
#[test]
fn test_parity() {
assert_eq!(f256::ZERO.parity(), Some(Parity::Even));
assert_eq!(f256::NEG_ZERO.parity(), Some(Parity::Even));
assert_eq!(f256::TEN.parity(), Some(Parity::Even));
assert_eq!(f256::NEG_ONE.parity(), Some(Parity::Odd));
assert_eq!(f256::MAX.parity(), Some(Parity::Even));
assert_eq!(f256::MIN.parity(), Some(Parity::Even));
let f = f256::TWO.mul_pow2(FRACTION_BITS) - f256::ONE;
assert_eq!(f.parity(), Some(Parity::Odd));
assert!(f256::MIN_GT_ZERO.parity().is_none());
assert!(f256::MIN_POSITIVE.parity().is_none());
assert!(f256::NAN.parity().is_none());
assert!(f256::NEG_INFINITY.parity().is_none());
assert!(f256::INFINITY.parity().is_none());
assert!(ONE_HALF.parity().is_none());
assert!(EPSILON.parity().is_none());
}
}
#[cfg(test)]
mod mul_pow2_tests {
use super::*;
#[test]
fn test_special() {
assert_eq!(f256::ZERO.mul_pow2(4), f256::ZERO);
assert_eq!(f256::INFINITY.mul_pow2(1), f256::INFINITY);
assert_eq!(f256::NEG_INFINITY.mul_pow2(1), f256::NEG_INFINITY);
assert!(f256::NAN.mul_pow2(38).is_nan());
}
#[test]
fn test_normal() {
let f = f256::TEN.mul_pow2(4);
assert_eq!(f, f256::from(160));
let g = f256::from(0.0793).mul_pow2(3);
assert_eq!(g, f256::from(0.6344));
}
#[test]
fn test_overflow() {
let f = f256::MAX.mul_pow2(1);
assert_eq!(f, f256::INFINITY);
let f = f256::MIN.mul_pow2(5);
assert_eq!(f, f256::NEG_INFINITY);
}
#[test]
fn test_subnormal() {
let f = f256::MIN_POSITIVE - f256::MIN_GT_ZERO;
assert!(f.is_subnormal());
let g = f.mul_pow2(1);
assert!(g.is_normal());
assert_eq!(g, f * f256::TWO);
let f = f256::MIN_GT_ZERO;
let g = f.mul_pow2(5);
assert!(g.is_subnormal());
assert_eq!(g, f * f256::from(32));
}
#[test]
fn test_subnormal_overflow() {
let f = f256::MIN_GT_ZERO;
let g = f.mul_pow2(u32::MAX);
assert_eq!(g, f256::INFINITY);
}
}
#[cfg(test)]
mod div_pow2_tests {
use super::*;
#[test]
fn test_special() {
assert_eq!(f256::ZERO.div_pow2(4), f256::ZERO);
assert_eq!(f256::INFINITY.div_pow2(1), f256::INFINITY);
assert_eq!(f256::NEG_INFINITY.div_pow2(1), f256::NEG_INFINITY);
assert!(f256::NAN.div_pow2(38).is_nan());
}
#[test]
fn test_normal() {
let f = f256::TEN;
assert_eq!(f.div_pow2(3), f256::from(1.25));
let g = f256::from(0.0793);
assert_eq!(g.div_pow2(5), g / f256::from(32));
let h = f256::MIN_POSITIVE.negated();
assert_eq!(h.div_pow2(65), h / f256::from(36893488147419103232_u128));
let f = f256::MIN_POSITIVE.div2();
assert_eq!(f, f256::MIN_POSITIVE / f256::TWO);
let f = f256::MIN_POSITIVE.div_pow2(236);
assert_eq!(f, f256::MIN_GT_ZERO);
}
#[test]
fn test_underflow() {
let f = f256::MIN_GT_ZERO.div_pow2(1);
assert_eq!(f, f256::ZERO);
let f = f256::MIN_POSITIVE.negated().div_pow2(SIGNIFICAND_BITS);
assert_eq!(f, f256::NEG_ZERO);
}
#[test]
fn test_subnormal() {
let f = f256::MIN_POSITIVE - f256::MIN_GT_ZERO;
assert!(f.is_subnormal());
let g = f.div_pow2(7);
assert!(g.is_subnormal());
assert_eq!(g, f / f256::from(128));
}
}