use crate::f8;
use core::{
iter::{Product, Sum},
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign},
};
impl f8 {
#[inline]
pub const fn saturating_add(self, rhs: Self) -> Self {
Self(self.0.saturating_add(rhs.0))
}
#[inline]
pub const fn saturating_sub(self, rhs: Self) -> Self {
Self(self.0.saturating_sub(rhs.0))
}
#[inline]
pub const fn saturating_mul(self, rhs: Self) -> Self {
Self(((self.0 as u16 * rhs.0 as u16 + 127) / 255) as u8)
}
#[inline]
pub const fn saturating_div(self, rhs: Self) -> Self {
if self.0 == 0 {
return Self::ZERO;
}
if self.0 >= rhs.0 {
return Self::ONE;
}
let numerator = self.0 as u16 * 255;
let divisor = rhs.0 as u16;
let quotient = numerator / divisor;
let twice_remainder = (numerator % divisor) * 2;
let round_up =
twice_remainder > divisor || (twice_remainder == divisor && quotient & 1 != 0);
Self((quotient + round_up as u16) as u8)
}
}
macro_rules! impl_ops {
($trait:ident, $method:ident, $assign_trait:ident, $assign_method:ident, $saturating:ident) => {
impl $trait for f8 {
type Output = Self;
#[inline]
fn $method(self, rhs: Self) -> Self::Output {
self.$saturating(rhs)
}
}
impl $trait<&f8> for f8 {
type Output = f8;
#[inline]
fn $method(self, rhs: &f8) -> Self::Output {
self.$saturating(*rhs)
}
}
impl $trait<f8> for &f8 {
type Output = f8;
#[inline]
fn $method(self, rhs: f8) -> Self::Output {
(*self).$saturating(rhs)
}
}
impl $trait<&f8> for &f8 {
type Output = f8;
#[inline]
fn $method(self, rhs: &f8) -> Self::Output {
(*self).$saturating(*rhs)
}
}
impl $assign_trait for f8 {
#[inline]
fn $assign_method(&mut self, rhs: Self) {
*self = self.$saturating(rhs);
}
}
impl $assign_trait<&f8> for f8 {
#[inline]
fn $assign_method(&mut self, rhs: &f8) {
*self = self.$saturating(*rhs);
}
}
};
}
impl_ops!(Add, add, AddAssign, add_assign, saturating_add);
impl_ops!(Sub, sub, SubAssign, sub_assign, saturating_sub);
impl_ops!(Mul, mul, MulAssign, mul_assign, saturating_mul);
impl_ops!(Div, div, DivAssign, div_assign, saturating_div);
impl Sum for f8 {
#[inline]
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::ZERO, Self::saturating_add)
}
}
impl<'a> Sum<&'a f8> for f8 {
#[inline]
fn sum<I: Iterator<Item = &'a f8>>(iter: I) -> Self {
iter.copied().sum()
}
}
impl Product for f8 {
#[inline]
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::ONE, Self::saturating_mul)
}
}
impl<'a> Product<&'a f8> for f8 {
#[inline]
fn product<I: Iterator<Item = &'a f8>>(iter: I) -> Self {
iter.copied().product()
}
}