#![doc = include_str!("../README.md")]
#![no_std]
#[macro_export]
macro_rules! f32 {
($value:expr) => {{
const C: $crate::F32 = { $crate::F32::from_native_f32($value) };
C
}};
}
#[macro_export]
macro_rules! f64 {
($value:expr) => {{
const C: $crate::F64 = { $crate::F64::from_native_f64($value) };
C
}};
}
mod conv;
mod soft_f32;
mod soft_f64;
pub use crate::soft_f32::F32;
pub use crate::soft_f64::F64;
const fn abs_diff(a: i32, b: i32) -> u32 {
a.wrapping_sub(b).wrapping_abs() as u32
}
macro_rules! impl_traits {
($ty:ty, $native_ty:ty, $from_native:ident, $to_native:ident) => {
impl From<$native_ty> for $ty {
fn from(value: $native_ty) -> Self {
Self::$from_native(value)
}
}
impl From<$ty> for $native_ty {
fn from(value: $ty) -> Self {
value.$to_native()
}
}
impl PartialEq<Self> for $ty {
fn eq(&self, other: &Self) -> bool {
match self.cmp(*other) {
Some(core::cmp::Ordering::Equal) => true,
_ => false,
}
}
}
impl PartialOrd for $ty {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
self.cmp(*other)
}
}
impl core::ops::Add for $ty {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self::add(self, rhs)
}
}
impl core::ops::Sub for $ty {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self::sub(self, rhs)
}
}
impl core::ops::Mul for $ty {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self::mul(self, rhs)
}
}
impl core::ops::Div for $ty {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
Self::div(self, rhs)
}
}
impl core::ops::Neg for $ty {
type Output = Self;
fn neg(self) -> Self::Output {
Self::neg(self)
}
}
impl core::ops::AddAssign for $ty {
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs;
}
}
impl core::ops::SubAssign for $ty {
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl core::ops::MulAssign for $ty {
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}
impl core::ops::DivAssign for $ty {
fn div_assign(&mut self, rhs: Self) {
*self = *self / rhs;
}
}
};
}
impl_traits!(crate::soft_f32::F32, f32, from_native_f32, to_native_f32);
impl_traits!(crate::soft_f64::F64, f64, from_native_f64, to_native_f64);
#[cfg(test)]
mod tests {
use crate::soft_f32::F32;
use crate::soft_f64::F64;
const RANGE: core::ops::Range<i32> = -1000..1000;
const F32_FACTOR: f32 = 10.0;
const F64_FACTOR: f64 = 1000.0;
#[test]
fn f32_add() {
for a in RANGE {
let a = a as f32 * F32_FACTOR;
for b in RANGE {
let b = b as f32 * F32_FACTOR;
assert_eq!(
F32::from_native_f32(a)
.add(F32::from_native_f32(b))
.to_native_f32(),
a + b
);
}
}
}
#[test]
fn f32_sub() {
for a in RANGE {
let a = a as f32 * F32_FACTOR;
for b in RANGE {
let b = b as f32 * F32_FACTOR;
assert_eq!(
F32::from_native_f32(a)
.sub(F32::from_native_f32(b))
.to_native_f32(),
a - b
);
}
}
}
#[test]
fn f32_mul() {
for a in RANGE {
let a = a as f32 * F32_FACTOR;
for b in RANGE {
let b = b as f32 * F32_FACTOR;
assert_eq!(
F32::from_native_f32(a)
.mul(F32::from_native_f32(b))
.to_native_f32(),
a * b
);
}
}
}
#[test]
fn f32_div() {
for a in RANGE {
let a = a as f32 * F32_FACTOR;
for b in RANGE {
let b = b as f32 * F32_FACTOR;
let x = F32::from_native_f32(a)
.div(F32::from_native_f32(b))
.to_native_f32();
let y = a / b;
assert!(x == y || x.is_nan() && y.is_nan())
}
}
}
#[test]
fn f64_add() {
for a in RANGE {
let a = a as f64 * F64_FACTOR;
for b in RANGE {
let b = b as f64 * F64_FACTOR;
assert_eq!(
F64::from_native_f64(a)
.sub(F64::from_native_f64(b))
.to_native_f64(),
a - b
);
}
}
}
#[test]
fn f64_sub() {
for a in RANGE {
let a = a as f64 * F64_FACTOR;
for b in RANGE {
let b = b as f64 * F64_FACTOR;
assert_eq!(
F64::from_native_f64(a)
.sub(F64::from_native_f64(b))
.to_native_f64(),
a - b
);
}
}
}
#[test]
fn f64_mul() {
for a in RANGE {
let a = a as f64 * F64_FACTOR;
for b in RANGE {
let b = b as f64 * F64_FACTOR;
assert_eq!(
F64::from_native_f64(a)
.mul(F64::from_native_f64(b))
.to_native_f64(),
a * b
);
}
}
}
#[test]
fn f64_div() {
for a in RANGE {
let a = a as f64 * F64_FACTOR;
for b in RANGE {
let b = b as f64 * F64_FACTOR;
let x = F64::from_native_f64(a)
.div(F64::from_native_f64(b))
.to_native_f64();
let y = a / b;
assert!(x == y || x.is_nan() && y.is_nan())
}
}
}
}