use crate::{math, private::Sealed};
use core::{
fmt::Debug,
ops::{
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign,
},
};
pub trait Channel:
Copy
+ Debug
+ Default
+ PartialOrd
+ Add<Output = Self>
+ Div<Output = Self>
+ Mul<Output = Self>
+ Sub<Output = Self>
+ Neg<Output = Self>
+ AddAssign
+ SubAssign
+ DivAssign
+ MulAssign
+ Sealed
+ Unpin
+ From<Ch8>
+ From<Ch16>
+ From<Ch32>
+ From<Ch64>
+ Into<Ch8>
+ Into<Ch16>
+ Into<Ch32>
+ Into<Ch64>
+ 'static
{
const MIN: Self;
const MID: Self;
const MAX: Self;
fn to_f64(self) -> f64;
fn from_f64(from: f64) -> Self;
#[inline(always)]
fn lerp(self, rhs: Self, t: Self) -> Self {
self + t * (rhs - self)
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd, Ord, Eq)]
#[repr(transparent)]
pub struct Ch8(i8);
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd, Ord, Eq)]
#[repr(transparent)]
pub struct Ch16(i16);
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct Ch32(f32);
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct Ch64(f64);
impl Eq for Ch32 {}
impl Eq for Ch64 {}
impl Ch8 {
#[inline(always)]
pub fn new(value: i8) -> Self {
Ch8(value)
}
}
impl Ch16 {
#[inline(always)]
pub fn new(value: i16) -> Self {
Ch16(value)
}
}
impl Ch32 {
#[inline(always)]
pub fn new(value: f32) -> Self {
Ch32(value.min(1.0).max(-1.0))
}
}
impl Ch64 {
#[inline(always)]
pub fn new(value: f64) -> Self {
Ch64(value.min(1.0).max(-1.0))
}
}
impl From<i8> for Ch8 {
#[inline(always)]
fn from(value: i8) -> Self {
Ch8(value)
}
}
impl From<Ch8> for i8 {
#[inline(always)]
fn from(c: Ch8) -> i8 {
c.0
}
}
impl From<i16> for Ch16 {
#[inline(always)]
fn from(value: i16) -> Self {
Ch16(value)
}
}
impl From<Ch16> for i16 {
#[inline(always)]
fn from(c: Ch16) -> i16 {
c.0
}
}
impl From<f32> for Ch32 {
#[inline(always)]
fn from(value: f32) -> Self {
Self(value.min(1.0).max(-1.0))
}
}
impl From<Ch32> for f32 {
#[inline(always)]
fn from(c: Ch32) -> f32 {
c.0
}
}
impl From<Ch64> for f64 {
#[inline(always)]
fn from(c: Ch64) -> f64 {
c.0
}
}
impl<R: Into<Self>> Sub<R> for Ch8 {
type Output = Self;
#[inline(always)]
fn sub(self, rhs: R) -> Self {
Self(self.0.saturating_sub(rhs.into().0))
}
}
impl<R: Into<Self>> Sub<R> for Ch16 {
type Output = Self;
#[inline(always)]
fn sub(self, rhs: R) -> Self {
Self(self.0.saturating_sub(rhs.into().0))
}
}
impl<R: Into<Self>> Sub<R> for Ch32 {
type Output = Self;
#[inline(always)]
fn sub(self, rhs: R) -> Self {
Self((self.0 - rhs.into().0).min(1.0).max(-1.0))
}
}
impl<R: Into<Self>> Sub<R> for Ch64 {
type Output = Self;
#[inline(always)]
fn sub(self, rhs: R) -> Self {
Self((self.0 - rhs.into().0).min(1.0).max(-1.0))
}
}
impl<R: Into<Self>> Add<R> for Ch8 {
type Output = Self;
#[inline(always)]
fn add(self, rhs: R) -> Self {
Self(self.0.saturating_add(rhs.into().0))
}
}
impl<R: Into<Self>> Add<R> for Ch16 {
type Output = Self;
#[inline(always)]
fn add(self, rhs: R) -> Self {
Self(self.0.saturating_add(rhs.into().0))
}
}
impl<R: Into<Self>> Add<R> for Ch32 {
type Output = Self;
#[inline(always)]
fn add(self, rhs: R) -> Self {
let value = self.0 + rhs.into().0;
Self(value.min(1.0).max(-1.0))
}
}
impl<R: Into<Self>> Add<R> for Ch64 {
type Output = Self;
#[inline(always)]
fn add(self, rhs: R) -> Self {
let value = self.0 + rhs.into().0;
Self(value.min(1.0).max(-1.0))
}
}
impl<R: Into<Self>> Div<R> for Ch8 {
type Output = Self;
#[inline(always)]
fn div(self, rhs: R) -> Self {
let rhs = rhs.into().0;
if rhs != 0 {
let ss = i32::from(self.0) << 8;
let rr = i32::from(rhs);
let value = (ss / rr).min(127).max(-128) as i8;
Self(value)
} else {
Self::MAX
}
}
}
impl<R: Into<Self>> Div<R> for Ch16 {
type Output = Self;
#[inline(always)]
fn div(self, rhs: R) -> Self {
let rhs = rhs.into().0;
if rhs != 0 {
let ss = i32::from(self.0) << 16;
let rr = i32::from(rhs);
let value = (ss / rr).min(i16::MAX.into()).max(i16::MIN.into());
Self(value as i16)
} else {
Self::MAX
}
}
}
impl<R: Into<Self>> Div<R> for Ch32 {
type Output = Self;
#[inline(always)]
fn div(self, rhs: R) -> Self {
Self((self.0 / rhs.into().0).min(1.0).max(-1.0))
}
}
impl<R: Into<Self>> Div<R> for Ch64 {
type Output = Self;
#[inline(always)]
fn div(self, rhs: R) -> Self {
Self((self.0 / rhs.into().0).min(1.0).max(-1.0))
}
}
impl<R: Into<Self>> Mul<R> for Ch8 {
type Output = Self;
#[inline(always)]
fn mul(self, rhs: R) -> Self {
let l = i16::from(self.0);
let r = i16::from(rhs.into().0);
let v = (l * r) / 127;
Self(v.min(127) as i8)
}
}
impl<R: Into<Self>> Mul<R> for Ch16 {
type Output = Self;
#[inline(always)]
fn mul(self, rhs: R) -> Self {
let l = i32::from(self.0);
let r = i32::from(rhs.into().0);
let v = (l * r) / 32767;
Self(v.min(32767) as i16)
}
}
impl<R: Into<Self>> Mul<R> for Ch32 {
type Output = Self;
#[inline(always)]
fn mul(self, rhs: R) -> Self {
Self(self.0 * rhs.into().0)
}
}
impl<R: Into<Self>> Mul<R> for Ch64 {
type Output = Self;
#[inline(always)]
fn mul(self, rhs: R) -> Self {
Self(self.0 * rhs.into().0)
}
}
impl<R: Into<Self>> AddAssign<R> for Ch8 {
#[inline(always)]
fn add_assign(&mut self, rhs: R) {
*self = *self + rhs.into();
}
}
impl<R: Into<Self>> AddAssign<R> for Ch16 {
#[inline(always)]
fn add_assign(&mut self, rhs: R) {
*self = *self + rhs.into();
}
}
impl<R: Into<Self>> AddAssign<R> for Ch32 {
#[inline(always)]
fn add_assign(&mut self, rhs: R) {
*self = *self + rhs.into();
}
}
impl<R: Into<Self>> AddAssign<R> for Ch64 {
#[inline(always)]
fn add_assign(&mut self, rhs: R) {
*self = *self + rhs.into();
}
}
impl<R: Into<Self>> SubAssign<R> for Ch8 {
#[inline(always)]
fn sub_assign(&mut self, rhs: R) {
*self = *self - rhs.into();
}
}
impl<R: Into<Self>> SubAssign<R> for Ch16 {
#[inline(always)]
fn sub_assign(&mut self, rhs: R) {
*self = *self - rhs.into();
}
}
impl<R: Into<Self>> SubAssign<R> for Ch32 {
#[inline(always)]
fn sub_assign(&mut self, rhs: R) {
*self = *self - rhs.into();
}
}
impl<R: Into<Self>> SubAssign<R> for Ch64 {
#[inline(always)]
fn sub_assign(&mut self, rhs: R) {
*self = *self - rhs.into();
}
}
impl<R: Into<Self>> MulAssign<R> for Ch8 {
#[inline(always)]
fn mul_assign(&mut self, rhs: R) {
*self = *self * rhs.into();
}
}
impl<R: Into<Self>> MulAssign<R> for Ch16 {
#[inline(always)]
fn mul_assign(&mut self, rhs: R) {
*self = *self * rhs.into();
}
}
impl<R: Into<Self>> MulAssign<R> for Ch32 {
#[inline(always)]
fn mul_assign(&mut self, rhs: R) {
*self = *self * rhs.into();
}
}
impl<R: Into<Self>> MulAssign<R> for Ch64 {
#[inline(always)]
fn mul_assign(&mut self, rhs: R) {
*self = *self * rhs.into();
}
}
impl<R: Into<Self>> DivAssign<R> for Ch8 {
#[inline(always)]
fn div_assign(&mut self, rhs: R) {
*self = *self / rhs.into();
}
}
impl<R: Into<Self>> DivAssign<R> for Ch16 {
#[inline(always)]
fn div_assign(&mut self, rhs: R) {
*self = *self / rhs.into();
}
}
impl<R: Into<Self>> DivAssign<R> for Ch32 {
#[inline(always)]
fn div_assign(&mut self, rhs: R) {
*self = *self / rhs.into();
}
}
impl<R: Into<Self>> DivAssign<R> for Ch64 {
#[inline(always)]
fn div_assign(&mut self, rhs: R) {
*self = *self / rhs.into();
}
}
impl Channel for Ch8 {
const MIN: Ch8 = Ch8(i8::MIN);
const MID: Ch8 = Ch8(0);
const MAX: Ch8 = Ch8(i8::MAX);
#[inline(always)]
fn to_f64(self) -> f64 {
Ch64::from(self).0
}
#[inline(always)]
fn from_f64(from: f64) -> Self {
Self::from(Ch64::new(from))
}
}
impl Channel for Ch16 {
const MIN: Ch16 = Ch16(i16::MIN);
const MID: Ch16 = Ch16(0);
const MAX: Ch16 = Ch16(i16::MAX);
#[inline(always)]
fn to_f64(self) -> f64 {
Ch64::from(self).0
}
#[inline(always)]
fn from_f64(from: f64) -> Self {
Self::from(Ch64::new(from))
}
}
impl Channel for Ch32 {
const MIN: Ch32 = Ch32(-1.0);
const MID: Ch32 = Ch32(0.0);
const MAX: Ch32 = Ch32(1.0);
#[inline(always)]
fn to_f64(self) -> f64 {
self.0 as f64
}
#[inline(always)]
fn from_f64(from: f64) -> Self {
Self(from as f32)
}
}
impl Channel for Ch64 {
const MIN: Ch64 = Ch64(-1.0);
const MID: Ch64 = Ch64(0.0);
const MAX: Ch64 = Ch64(1.0);
#[inline(always)]
fn to_f64(self) -> f64 {
self.0
}
#[inline(always)]
fn from_f64(from: f64) -> Self {
Self(from)
}
}
impl From<Ch64> for Ch8 {
#[inline(always)]
fn from(value: Ch64) -> Self {
Ch8::new(math::floor_i8(value.0 * 127.5))
}
}
impl From<Ch64> for Ch16 {
#[inline(always)]
fn from(value: Ch64) -> Self {
Ch16::new(math::floor_i16(value.0 * 32767.5))
}
}
impl From<Ch64> for Ch32 {
#[inline(always)]
fn from(value: Ch64) -> Self {
Ch32::new(value.0 as f32)
}
}
impl From<Ch32> for Ch8 {
#[inline(always)]
fn from(value: Ch32) -> Self {
Ch8::new(math::floorh_i8(value.0 * 127.5))
}
}
impl From<Ch32> for Ch16 {
#[inline(always)]
fn from(value: Ch32) -> Self {
Ch16::new(math::floorh_i16(value.0 * 32767.5))
}
}
impl From<Ch32> for Ch64 {
#[inline(always)]
fn from(value: Ch32) -> Self {
Ch64::new(value.0.into())
}
}
impl From<Ch16> for Ch8 {
#[inline(always)]
fn from(c: Ch16) -> Self {
Ch8::new((c.0 >> 8) as i8)
}
}
impl From<Ch16> for Ch32 {
#[inline(always)]
fn from(c: Ch16) -> Self {
Self((f32::from(c.0) / 32767.5) + (1.0 / 65535.0))
}
}
impl From<Ch16> for Ch64 {
#[inline(always)]
fn from(c: Ch16) -> Self {
Self((f64::from(c.0) / 32767.5) + (1.0 / 65535.0))
}
}
impl From<Ch8> for Ch16 {
#[inline(always)]
fn from(c: Ch8) -> Self {
let c = c.0.wrapping_sub(-128) as u8;
let v = u16::from_ne_bytes([c, c]).wrapping_add(32768) as i16;
Ch16::from(v)
}
}
impl From<Ch8> for Ch32 {
#[inline(always)]
fn from(c: Ch8) -> Self {
Self((f32::from(c.0) / 127.5) + (1.0 / 255.0))
}
}
impl From<Ch8> for Ch64 {
#[inline(always)]
fn from(c: Ch8) -> Self {
Self((f64::from(c.0) / 127.5) + (1.0 / 255.0))
}
}
impl Neg for Ch8 {
type Output = Ch8;
#[inline(always)]
fn neg(self) -> Self {
Ch8((u8::MAX - self.0 as u8) as i8)
}
}
impl Neg for Ch16 {
type Output = Ch16;
#[inline(always)]
fn neg(self) -> Self {
Ch16((u16::MAX - self.0 as u16) as i16)
}
}
impl Neg for Ch32 {
type Output = Ch32;
#[inline(always)]
fn neg(self) -> Self {
Ch32(-self.0)
}
}
impl Neg for Ch64 {
type Output = Ch64;
#[inline(always)]
fn neg(self) -> Self {
Ch64(-self.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn channel_neg() {
assert_eq!(Ch8::new(-128), -Ch8::new(127));
assert_eq!(Ch16::new(-32768), -Ch16::new(32767));
assert_eq!(Ch32::new(-1.0), -Ch32::new(1.0));
assert_eq!(Ch64::new(-1.0), -Ch64::new(1.0));
assert_eq!(Ch8::new(127), -Ch8::new(-128));
assert_eq!(Ch16::new(32767), -Ch16::new(-32768));
assert_eq!(Ch32::new(1.0), -Ch32::new(-1.0));
assert_eq!(Ch64::new(1.0), -Ch64::new(-1.0));
assert_eq!(Ch8::new(-1), -Ch8::new(0));
assert_eq!(Ch8::new(0), -Ch8::new(-1));
assert_eq!(Ch16::new(-1), -Ch16::new(0));
assert_eq!(Ch16::new(0), -Ch16::new(-1));
assert_eq!(Ch32::new(0.0), -Ch32::new(0.0));
assert_eq!(Ch64::new(0.0), -Ch64::new(0.0));
}
#[test]
fn ch8_roundtrip() {
assert_eq!(-1.0, Ch8::new(-128).to_f64());
assert_eq!(1.0, Ch8::new(127).to_f64());
assert_eq!(Ch8::new(-128), Ch8::from_f64(Ch8::new(-128).to_f64()));
assert_eq!(Ch8::new(0), Ch8::from_f64(Ch8::new(0).to_f64()));
assert_eq!(Ch8::new(127), Ch8::from_f64(Ch8::new(127).to_f64()));
}
#[test]
fn ch16_roundtrip() {
assert_eq!(-1.0, Ch16::new(-32768).to_f64());
assert_eq!(1.0, Ch16::new(32767).to_f64());
assert_eq!(
Ch16::new(-32768),
Ch16::from_f64(Ch16::new(-32768).to_f64())
);
assert_eq!(Ch16::new(0), Ch16::from_f64(Ch16::new(0).to_f64()));
assert_eq!(Ch16::new(32767), Ch16::from_f64(Ch16::new(32767).to_f64()));
}
#[test]
fn ch32_roundtrip() {
assert_eq!(-1.0, Ch32::new(-1.0).to_f64());
assert_eq!(0.0, Ch32::new(0.0).to_f64());
assert_eq!(1.0, Ch32::new(1.0).to_f64());
assert_eq!(Ch32::new(-1.0), Ch32::from_f64(Ch32::new(-1.0).to_f64()));
assert_eq!(Ch32::new(0.0), Ch32::from_f64(Ch32::new(0.0).to_f64()));
assert_eq!(Ch32::new(1.0), Ch32::from_f64(Ch32::new(1.0).to_f64()));
}
#[test]
fn ch8_to_ch16() {
assert_eq!(Ch16::new(-32768), Ch16::from(Ch8::new(-128)));
assert_eq!(Ch16::new(32767), Ch16::from(Ch8::new(127)));
}
#[test]
fn ch16_to_ch8() {
assert_eq!(Ch8::new(-128), Ch8::from(Ch16::new(-32768)));
assert_eq!(Ch8::new(0), Ch8::from(Ch16::new(0)));
assert_eq!(Ch8::new(127), Ch8::from(Ch16::new(32767)));
}
#[test]
fn ch8_arith() {
assert_eq!(Ch8::new(-1), Ch8::new(-128) + Ch8::new(127));
assert_eq!(Ch8::new(32), Ch8::new(-32) + Ch8::new(64));
assert_eq!(Ch8::new(127), Ch8::new(0) + Ch8::new(127));
assert_eq!(Ch8::new(-128), Ch8::new(-64) + Ch8::new(-64));
assert_eq!(Ch8::new(0), Ch8::new(-128) - Ch8::new(-128));
assert_eq!(Ch8::new(0), Ch8::new(127) - Ch8::new(127));
assert_eq!(Ch8::new(-127), Ch8::new(0) - Ch8::new(127));
assert_eq!(Ch8::new(0), Ch8::new(0) * Ch8::new(127));
assert_eq!(Ch8::new(127), Ch8::new(127) * Ch8::new(127));
assert_eq!(Ch8::new(-128), Ch8::new(127) * Ch8::new(-128));
assert_eq!(Ch8::new(-128), Ch8::new(-128) * Ch8::new(127));
assert_eq!(Ch8::new(127), Ch8::new(-128) * Ch8::new(-128));
assert_eq!(Ch8::new(-64), Ch8::new(127) * Ch8::new(-64));
assert_eq!(Ch8::new(0), Ch8::new(0) / Ch8::new(127));
assert_eq!(Ch8::new(127), Ch8::new(127) / Ch8::new(127));
assert_eq!(Ch8::new(-128), Ch8::new(127) / Ch8::new(-128));
assert_eq!(Ch8::new(-128), Ch8::new(-128) / Ch8::new(127));
assert_eq!(Ch8::new(127), Ch8::new(-128) / Ch8::new(-128));
assert_eq!(Ch8::new(-128), Ch8::new(64) / Ch8::new(-64));
}
#[test]
fn ch16_arith() {
assert_eq!(Ch16::new(-1), Ch16::new(-32768) + Ch16::new(32767));
assert_eq!(Ch16::new(8192), Ch16::new(-8192) + Ch16::new(16384));
assert_eq!(Ch16::new(32767), Ch16::new(0) + Ch16::new(32767));
assert_eq!(Ch16::new(-32768), Ch16::new(-16384) + Ch16::new(-16384));
assert_eq!(Ch16::new(0), Ch16::new(-32768) - Ch16::new(-32768));
assert_eq!(Ch16::new(0), Ch16::new(32767) - Ch16::new(32767));
assert_eq!(Ch16::new(-32767), Ch16::new(0) - Ch16::new(32767));
assert_eq!(Ch16::new(0), Ch16::new(0) * Ch16::new(32767));
assert_eq!(Ch16::new(32767), Ch16::new(32767) * Ch16::new(32767));
assert_eq!(Ch16::new(-32768), Ch16::new(32767) * Ch16::new(-32768));
assert_eq!(Ch16::new(-32768), Ch16::new(-32768) * Ch16::new(32767));
assert_eq!(Ch16::new(32767), Ch16::new(-32768) * Ch16::new(-32768));
assert_eq!(Ch16::new(-16384), Ch16::new(32767) * Ch16::new(-16384));
assert_eq!(Ch16::new(0), Ch16::new(0) / Ch16::new(32767));
assert_eq!(Ch16::new(32767), Ch16::new(32767) / Ch16::new(32767));
assert_eq!(Ch16::new(-32768), Ch16::new(32767) / Ch16::new(-32768));
assert_eq!(Ch16::new(-32768), Ch16::new(-32768) / Ch16::new(32767));
assert_eq!(Ch16::new(32767), Ch16::new(-32768) / Ch16::new(-32768));
assert_eq!(Ch16::new(-32768), Ch16::new(16384) / Ch16::new(-16384));
}
#[test]
fn ch32_arith() {
assert_eq!(Ch32::new(0.0), Ch32::new(-1.0) + Ch32::new(1.0));
assert_eq!(Ch32::new(0.25), Ch32::new(-0.25) + Ch32::new(0.5));
assert_eq!(Ch32::new(1.0), Ch32::new(0.0) + Ch32::new(1.0));
assert_eq!(Ch32::new(-1.0), Ch32::new(-0.5) + Ch32::new(-0.5));
assert_eq!(Ch32::new(0.0), Ch32::new(-1.0) - Ch32::new(-1.0));
assert_eq!(Ch32::new(0.0), Ch32::new(1.0) - Ch32::new(1.0));
assert_eq!(Ch32::new(-1.0), Ch32::new(0.0) - Ch32::new(1.0));
assert_eq!(Ch32::new(0.0), Ch32::new(0.0) * Ch32::new(1.0));
assert_eq!(Ch32::new(1.0), Ch32::new(1.0) * Ch32::new(1.0));
assert_eq!(Ch32::new(-1.0), Ch32::new(1.0) * Ch32::new(-1.0));
assert_eq!(Ch32::new(1.0), Ch32::new(-1.0) * Ch32::new(-1.0));
assert_eq!(Ch32::new(-0.5), Ch32::new(1.0) * Ch32::new(-0.5));
assert_eq!(Ch32::new(0.0), Ch32::new(0.0) / Ch32::new(1.0));
assert_eq!(Ch32::new(1.0), Ch32::new(1.0) / Ch32::new(1.0));
assert_eq!(Ch32::new(-1.0), Ch32::new(1.0) / Ch32::new(-1.0));
assert_eq!(Ch32::new(-1.0), Ch32::new(-1.0) / Ch32::new(1.0));
assert_eq!(Ch32::new(1.0), Ch32::new(-1.0) / Ch32::new(-1.0));
assert_eq!(Ch32::new(-1.0), Ch32::new(0.5) / Ch32::new(-0.5));
}
#[test]
fn ch64_arith() {
assert_eq!(Ch64::new(0.0), Ch64::new(-1.0) + Ch64::new(1.0));
assert_eq!(Ch64::new(0.25), Ch64::new(-0.25) + Ch64::new(0.5));
assert_eq!(Ch64::new(1.0), Ch64::new(0.0) + Ch64::new(1.0));
assert_eq!(Ch64::new(-1.0), Ch64::new(-0.5) + Ch64::new(-0.5));
assert_eq!(Ch64::new(0.0), Ch64::new(-1.0) - Ch64::new(-1.0));
assert_eq!(Ch64::new(0.0), Ch64::new(1.0) - Ch64::new(1.0));
assert_eq!(Ch64::new(-1.0), Ch64::new(0.0) - Ch64::new(1.0));
assert_eq!(Ch64::new(0.0), Ch64::new(0.0) * Ch64::new(1.0));
assert_eq!(Ch64::new(1.0), Ch64::new(1.0) * Ch64::new(1.0));
assert_eq!(Ch64::new(-1.0), Ch64::new(1.0) * Ch64::new(-1.0));
assert_eq!(Ch64::new(1.0), Ch64::new(-1.0) * Ch64::new(-1.0));
assert_eq!(Ch64::new(-0.5), Ch64::new(1.0) * Ch64::new(-0.5));
assert_eq!(Ch64::new(0.0), Ch64::new(0.0) / Ch64::new(1.0));
assert_eq!(Ch64::new(1.0), Ch64::new(1.0) / Ch64::new(1.0));
assert_eq!(Ch64::new(-1.0), Ch64::new(1.0) / Ch64::new(-1.0));
assert_eq!(Ch64::new(-1.0), Ch64::new(-1.0) / Ch64::new(1.0));
assert_eq!(Ch64::new(1.0), Ch64::new(-1.0) / Ch64::new(-1.0));
assert_eq!(Ch64::new(-1.0), Ch64::new(0.5) / Ch64::new(-0.5));
}
#[test]
fn ch8_saturation() {
assert_eq!(Ch8::new(127), Ch8::new(96) + Ch8::new(64));
assert_eq!(Ch8::new(-128), Ch8::new(-64) + Ch8::new(-96));
assert_eq!(Ch8::new(-128), Ch8::new(-64) - Ch8::new(96));
assert_eq!(Ch8::new(127), Ch8::new(64) / Ch8::new(32));
assert_eq!(Ch8::new(-128), Ch8::new(64) / Ch8::new(-32));
}
#[test]
fn ch16_saturation() {
assert_eq!(Ch16::new(32767), Ch16::new(24576) + Ch16::new(16384));
assert_eq!(Ch16::new(-32768), Ch16::new(-16384) + Ch16::new(-24576));
assert_eq!(Ch16::new(-32768), Ch16::new(-16384) - Ch16::new(24576));
assert_eq!(Ch16::new(32767), Ch16::new(16384) / Ch16::new(8192));
assert_eq!(Ch16::new(-32768), Ch16::new(16384) / Ch16::new(-8192));
}
#[test]
fn ch32_saturation() {
assert_eq!(Ch32::new(1.0), Ch32::new(0.75) + Ch32::new(0.5));
assert_eq!(Ch32::new(-1.0), Ch32::new(-0.5) + Ch32::new(-0.75));
assert_eq!(Ch32::new(-1.0), Ch32::new(-0.5) - Ch32::new(0.75));
assert_eq!(Ch32::new(1.0), Ch32::new(0.5) / Ch32::new(0.25));
assert_eq!(Ch32::new(-1.0), Ch32::new(0.5) / Ch32::new(-0.25));
}
#[test]
fn ch64_saturation() {
assert_eq!(Ch64::new(1.0), Ch64::new(0.75) + Ch64::new(0.5));
assert_eq!(Ch64::new(-1.0), Ch64::new(-0.5) + Ch64::new(-0.75));
assert_eq!(Ch64::new(-1.0), Ch64::new(-0.5) - Ch64::new(0.75));
assert_eq!(Ch64::new(1.0), Ch64::new(0.5) / Ch64::new(0.25));
assert_eq!(Ch64::new(-1.0), Ch64::new(0.5) / Ch64::new(-0.25));
}
}