use std::{
cmp::Ordering,
convert::TryInto,
num::FpCategory,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
};
use num_traits::{Float, Num, NumCast, One, ToPrimitive, Zero};
use simple_soft_float::{FloatClass, RoundingMode, Sign, F128, F32, F64};
const MAXITER: i32 = 150;
mod consts {
use super::f128;
pub fn pi() -> f128 {
f128::new(std::f64::consts::PI)
}
pub fn ln_2() -> f128 {
f128::new(std::f64::consts::LN_2)
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Copy, Clone)]
pub struct f128(F128);
impl f128 {
pub fn new<T: ToPrimitive>(f: T) -> Self {
NumCast::from(f).unwrap()
}
}
impl PartialEq for f128 {
fn eq(&self, other: &Self) -> bool {
match self.0.compare(&other.0, false, None) {
Some(Ordering::Equal) => true,
_ => false,
}
}
fn ne(&self, other: &Self) -> bool {
!self.eq(other)
}
}
impl PartialOrd for f128 {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.0.compare(&other.0, false, None)
}
}
impl Zero for f128 {
fn zero() -> Self {
Self(F128::positive_zero())
}
fn set_zero(&mut self) {
self.0 = F128::positive_zero()
}
fn is_zero(&self) -> bool {
self.0.is_positive_zero() || self.0.is_negative_zero()
}
}
impl Neg for f128 {
type Output = Self;
fn neg(self) -> Self::Output {
Self(self.0.neg())
}
}
impl Add for f128 {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0.add(&rhs.0, Some(RoundingMode::TiesToAway), None))
}
}
impl AddAssign for f128 {
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs
}
}
impl Sub for f128 {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self(self.0.sub(&rhs.0, Some(RoundingMode::TiesToAway), None))
}
}
impl SubAssign for f128 {
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs
}
}
impl Mul for f128 {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self(self.0.mul(&rhs.0, Some(RoundingMode::TiesToAway), None))
}
}
impl MulAssign for f128 {
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs
}
}
impl Div for f128 {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
Self(self.0.div(&rhs.0, Some(RoundingMode::TiesToAway), None))
}
}
impl DivAssign for f128 {
fn div_assign(&mut self, rhs: Self) {
*self = *self / rhs
}
}
impl Rem for f128 {
type Output = Self;
fn rem(self, rhs: Self) -> Self::Output {
Self(
self.0
.ieee754_remainder(&rhs.0, Some(RoundingMode::TiesToAway), None),
)
}
}
impl RemAssign for f128 {
fn rem_assign(&mut self, rhs: Self) {
*self = *self % rhs
}
}
impl One for f128 {
fn one() -> Self {
Self(F128::from_u8(1, Some(RoundingMode::TiesToAway), None))
}
fn set_one(&mut self) {
self.0 = F128::from_u8(1, Some(RoundingMode::TiesToAway), None)
}
}
impl Num for f128 {
type FromStrRadixErr = ();
fn from_str_radix(_str: &str, _radix: u32) -> Result<Self, Self::FromStrRadixErr> {
unimplemented!()
}
}
impl NumCast for f128 {
fn from<T: ToPrimitive>(n: T) -> Option<Self> {
n.to_f64().and_then(|n| {
Some(Self(F128::convert_from_float(
&F64::from_bits(n.to_bits()),
Some(RoundingMode::TiesToAway),
None,
)))
})
}
}
impl ToPrimitive for f128 {
fn to_isize(&self) -> Option<isize> {
self.0.to_isize(true, Some(RoundingMode::TiesToAway), None)
}
fn to_i8(&self) -> Option<i8> {
self.0.to_i8(true, Some(RoundingMode::TiesToAway), None)
}
fn to_i16(&self) -> Option<i16> {
self.0.to_i16(true, Some(RoundingMode::TiesToAway), None)
}
fn to_i32(&self) -> Option<i32> {
self.0.to_i32(true, Some(RoundingMode::TiesToAway), None)
}
fn to_i64(&self) -> Option<i64> {
self.0.to_i64(true, Some(RoundingMode::TiesToAway), None)
}
fn to_i128(&self) -> Option<i128> {
self.0.to_i128(true, Some(RoundingMode::TiesToAway), None)
}
fn to_usize(&self) -> Option<usize> {
self.0.to_usize(true, Some(RoundingMode::TiesToAway), None)
}
fn to_u8(&self) -> Option<u8> {
self.0.to_u8(true, Some(RoundingMode::TiesToAway), None)
}
fn to_u16(&self) -> Option<u16> {
self.0.to_u16(true, Some(RoundingMode::TiesToAway), None)
}
fn to_u32(&self) -> Option<u32> {
self.0.to_u32(true, Some(RoundingMode::TiesToAway), None)
}
fn to_u64(&self) -> Option<u64> {
self.0.to_u64(true, Some(RoundingMode::TiesToAway), None)
}
fn to_u128(&self) -> Option<u128> {
self.0.to_u128(true, Some(RoundingMode::TiesToAway), None)
}
fn to_f32(&self) -> Option<f32> {
Some(f32::from_bits(
F32::convert_from_float(&self.0, Some(RoundingMode::TiesToAway), None).into_bits(),
))
}
fn to_f64(&self) -> Option<f64> {
Some(f64::from_bits(
F64::convert_from_float(&self.0, Some(RoundingMode::TiesToAway), None).into_bits(),
))
}
}
fn fac(val: f64) -> f64 {
if val <= 0.0 {
1.0
} else {
fac(val - 1.0) * val
}
}
fn arithmetic_geometric_mean(x: f128, y: f128) -> f128 {
let mut a_n = x;
let mut b_n = x;
while a_n != b_n {
let a_next = (a_n + b_n) / f128::new(2);
let b_next = (a_n * b_n).sqrt();
a_n = a_next;
b_n = b_next;
}
a_n
}
impl Float for f128 {
fn nan() -> Self {
Self(F128::signaling_nan())
}
fn infinity() -> Self {
Self(F128::positive_infinity())
}
fn neg_infinity() -> Self {
Self(F128::negative_infinity())
}
fn neg_zero() -> Self {
Self(F128::negative_zero())
}
fn min_value() -> Self {
Self(F128::signed_max_normal(Sign::Negative))
}
fn min_positive_value() -> Self {
Self(F128::signed_min_subnormal(Sign::Positive))
}
fn epsilon() -> Self {
unimplemented!()
}
fn max_value() -> Self {
Self(F128::signed_max_normal(Sign::Positive))
}
fn is_nan(self) -> bool {
self.0.is_nan()
}
fn is_infinite(self) -> bool {
self.0.is_infinity()
}
fn is_finite(self) -> bool {
self.0.is_finite()
}
fn is_normal(self) -> bool {
self.0.is_normal()
}
fn classify(self) -> FpCategory {
match self.0.class() {
FloatClass::NegativeInfinity | FloatClass::PositiveInfinity => FpCategory::Infinite,
FloatClass::NegativeNormal | FloatClass::PositiveNormal => FpCategory::Normal,
FloatClass::NegativeSubnormal | FloatClass::PositiveSubnormal => FpCategory::Subnormal,
FloatClass::NegativeZero | FloatClass::PositiveZero => FpCategory::Zero,
FloatClass::QuietNaN | FloatClass::SignalingNaN => FpCategory::Nan,
}
}
fn floor(self) -> Self {
unimplemented!()
}
fn ceil(self) -> Self {
unimplemented!()
}
fn round(self) -> Self {
Self(
self.0
.round_to_integral(true, Some(RoundingMode::TiesToAway), None),
)
}
fn trunc(self) -> Self {
unimplemented!()
}
fn fract(self) -> Self {
unimplemented!()
}
fn abs(self) -> Self {
Self(self.0.abs())
}
fn signum(self) -> Self {
match self.0.sign() {
Sign::Positive => Self(F128::from_i8(1, Some(RoundingMode::TiesToAway), None)),
Sign::Negative => Self(F128::from_i8(-1, Some(RoundingMode::TiesToAway), None)),
}
}
fn is_sign_positive(self) -> bool {
self.0.sign() == Sign::Positive
}
fn is_sign_negative(self) -> bool {
self.0.sign() == Sign::Negative
}
fn mul_add(self, a: Self, b: Self) -> Self {
Self(
self.0
.fused_mul_add(&a.0, &b.0, Some(RoundingMode::TiesToAway), None),
)
}
fn recip(self) -> Self {
unimplemented!()
}
fn powi(self, mut n: i32) -> Self {
let mut ret = f128::one();
while n > 0 {
if n % 2 == 0 {
ret *= ret;
n /= 2;
} else {
ret *= ret * ret;
n = (n - 1) / 2;
}
}
ret
}
fn powf(self, n: Self) -> Self {
(self.ln() * n).exp()
}
fn sqrt(self) -> Self {
Self(self.0.sqrt(Some(RoundingMode::TiesToAway), None))
}
fn exp(self) -> Self {
let mut result = Self::zero();
for n in 0..MAXITER {
let current_value = self.powi(n) / Self::new(fac(n as f64));
result += current_value;
}
result
}
fn exp2(self) -> Self {
unimplemented!()
}
fn ln(self) -> Self {
if self == Self::one() {
Self::zero()
} else {
let m = 8;
let s = self * f128::new(2).powi(m);
(crate::softfloat::consts::pi()
/ (f128::new(2) * arithmetic_geometric_mean(f128::one(), f128::new(4) / s)))
- (f128::new(m) * crate::softfloat::consts::ln_2())
}
}
fn log(self, _base: Self) -> Self {
unimplemented!()
}
fn log2(self) -> Self {
unimplemented!()
}
fn log10(self) -> Self {
unimplemented!()
}
fn to_degrees(self) -> Self {
unimplemented!()
}
fn to_radians(self) -> Self {
unimplemented!()
}
fn max(self, _other: Self) -> Self {
unimplemented!()
}
fn min(self, _other: Self) -> Self {
unimplemented!()
}
fn abs_sub(self, other: Self) -> Self {
Self(
self.0
.abs()
.sub(&other.0.abs(), Some(RoundingMode::TiesToAway), None),
)
}
fn cbrt(self) -> Self {
unimplemented!()
}
fn hypot(self, _other: Self) -> Self {
unimplemented!()
}
fn sin(self) -> Self {
unimplemented!()
}
fn cos(self) -> Self {
unimplemented!()
}
fn tan(self) -> Self {
unimplemented!()
}
fn asin(self) -> Self {
unimplemented!()
}
fn acos(self) -> Self {
unimplemented!()
}
fn atan(self) -> Self {
unimplemented!()
}
fn atan2(self, _other: Self) -> Self {
unimplemented!()
}
fn sin_cos(self) -> (Self, Self) {
unimplemented!()
}
fn exp_m1(self) -> Self {
unimplemented!()
}
fn ln_1p(self) -> Self {
unimplemented!()
}
fn sinh(self) -> Self {
unimplemented!()
}
fn cosh(self) -> Self {
unimplemented!()
}
fn tanh(self) -> Self {
unimplemented!()
}
fn asinh(self) -> Self {
unimplemented!()
}
fn acosh(self) -> Self {
unimplemented!()
}
fn atanh(self) -> Self {
unimplemented!()
}
fn integer_decode(self) -> (u64, i16, i8) {
(
self.0.mantissa_field().try_into().unwrap(),
self.0.exponent_field().try_into().unwrap(),
match self.0.sign() {
Sign::Positive => 1,
Sign::Negative => -1,
},
)
}
}