use core::{fmt, ops::*};
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct L32(u32);
impl L32 {
pub const NAR: Self = Self(0xC0000000);
pub const ZERO: Self = Self(0x40000000);
pub const ONE: Self = Self(0);
#[inline]
pub const fn to_bits(self) -> u32 {
self.0
}
#[inline]
pub const fn from_bits(bits: u32) -> Self {
Self(bits)
}
#[inline]
pub fn sqrt(self) -> Self {
let exp = self.0 >> 1;
let exp_sign = self.0 & 0x40000000;
let mut res = Self(exp_sign | exp);
if self == Self::ZERO {
res = Self::ZERO;
}
if self.0 & 0x80000000 != 0 {
res = Self::NAR;
}
res
}
}
impl fmt::Debug for L32 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl Mul<L32> for L32 {
type Output = Self;
#[inline]
fn mul(self, rhs: L32) -> Self {
let sign = (self.0 ^ rhs.0) & 0x80000000;
let exp = self.0.wrapping_add(rhs.0) & 0x7FFFFFFF;
let mut res = Self(sign | exp);
if self == Self::ZERO || rhs == Self::ZERO {
res = Self::ZERO;
}
if self == Self::NAR || rhs == Self::NAR {
res = Self::NAR;
}
res
}
}
impl MulAssign<L32> for L32 {
#[inline]
fn mul_assign(&mut self, rhs: L32) {
*self = *self * rhs;
}
}
impl Div<L32> for L32 {
type Output = L32;
#[inline]
fn div(self, rhs: L32) -> Self::Output {
let sign = (self.0 ^ rhs.0) & 0x80000000;
let exp = self.0.wrapping_sub(rhs.0) & 0x7FFFFFFF;
let mut res = Self(sign | exp);
if self == Self::ZERO {
res = Self::ZERO;
}
if self == Self::NAR || rhs == Self::NAR || rhs == Self::ZERO {
res = Self::NAR;
}
res
}
}
impl DivAssign<L32> for L32 {
#[inline]
fn div_assign(&mut self, rhs: L32) {
*self = *self / rhs;
}
}
impl Default for L32 {
#[inline]
fn default() -> Self {
Self::ZERO
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sqrt() {
assert_eq!(L32::NAR.sqrt(), L32::NAR);
assert_eq!(L32(0x80000000).sqrt(), L32::NAR);
assert_eq!(L32(0x80000001).sqrt(), L32::NAR);
assert_eq!(L32(0x81234567).sqrt(), L32::NAR);
assert_eq!(L32(0xF3FCFEF3).sqrt(), L32::NAR);
assert_eq!(L32(0xFFFFFFFF).sqrt(), L32::NAR);
assert_eq!(L32(0x00000000).sqrt(), L32(0x00000000));
assert_eq!(L32(0x00000001).sqrt(), L32(0x00000000));
assert_eq!(L32(0x00800000).sqrt(), L32(0x00400000));
assert_eq!(L32(0x00800001).sqrt(), L32(0x00400000));
assert_eq!(L32(0x3FFFFFFF).sqrt(), L32(0x1FFFFFFF));
assert_eq!(L32(0x70006101).sqrt(), L32(0x78003080));
assert_eq!(L32(0x7FFFFFFF).sqrt(), L32(0x7FFFFFFF));
assert_eq!(L32(0x40000001).sqrt(), L32(0x60000000));
assert_eq!(L32(0x60000000).sqrt(), L32(0x70000000));
}
#[test]
fn mul() {
fn test(a: u32, b: u32, res: u32) {
assert_eq!(L32(a) * L32(b), L32(res));
assert_eq!(L32(b) * L32(a), L32(res));
}
test(0xBFFFFFFF, 0x00000001, 0xC0000000);
test(0xBFFFFFFF, 0x80000001, 0x40000000);
test(0x3FFFFFFF, 0x00000001, 0x40000000);
test(0x3FFFFFFF, 0x80000001, 0xC0000000);
test(0xBFFFFFFF, 0x40000000, 0x40000000);
test(0x3FFFFFFF, 0x40000000, 0x40000000);
test(0x00000000, 0x40000000, 0x40000000);
test(0x80000000, 0x40000000, 0x40000000);
test(0xDEADBEEF, 0x40000000, 0x40000000);
test(0xDEADBEEF, 0xC0000000, 0xC0000000);
test(0x00000000, 0xC0000000, 0xC0000000);
test(0x80000000, 0xC0000000, 0xC0000000);
test(0x40000000, 0xC0000000, 0xC0000000);
test(0xBFFFFFFF, 0x80000000, 0x3FFFFFFF);
test(0x7FFFFFFF, 0x00000001, 0x00000000);
test(0xFFFFFFFF, 0x00000001, 0x80000000);
test(0xDEADBEEF, 0xBEEFDEAD, 0x1D9D9D9C);
}
#[test]
fn div() {
fn test(a: u32, b: u32, res: u32) {
assert_eq!(L32(a) / L32(b), L32(res));
}
test(0xBFFFFFFF, 0x7FFFFFFF, 0xC0000000);
test(0xBFFFFFFF, 0xFFFFFFFF, 0x40000000);
test(0x3FFFFFFF, 0x7FFFFFFF, 0x40000000);
test(0x3FFFFFFF, 0xFFFFFFFF, 0xC0000000);
test(0x40000000, 0xBFFFFFFF, 0x40000000);
test(0x40000000, 0x3FFFFFFF, 0x40000000);
test(0x40000000, 0x00000000, 0x40000000);
test(0x40000000, 0x80000000, 0x40000000);
test(0x40000000, 0xDEADBEEF, 0x40000000);
test(0x40000000, 0x00000001, 0x40000000);
test(0xDEADBEEF, 0xC0000000, 0xC0000000);
test(0x00000000, 0xC0000000, 0xC0000000);
test(0x80000000, 0xC0000000, 0xC0000000);
test(0xC0000000, 0xDEADBEEF, 0xC0000000);
test(0xC0000000, 0x00000000, 0xC0000000);
test(0xC0000000, 0x80000000, 0xC0000000);
test(0xBFFFFFFF, 0x40000000, 0xC0000000);
test(0x3FFFFFFF, 0x40000000, 0xC0000000);
test(0x00000000, 0x40000000, 0xC0000000);
test(0x80000000, 0x40000000, 0xC0000000);
test(0xDEADBEEF, 0x40000000, 0xC0000000);
test(0x00000001, 0x40000000, 0xC0000000);
test(0xBFFFFFFF, 0x80000000, 0x3FFFFFFF);
test(0x00000000, 0x00000001, 0x7FFFFFFF);
test(0x80000000, 0x00000001, 0xFFFFFFFF);
test(0xDEADBEEF, 0xBEEFDEAD, 0x1FBDE042);
}
}