use crate::extended_scalar::extended_int as ei;
use std::fmt;
use std::ops;
#[cfg(test)]
mod robustdif_tests;
#[cfg(test)]
mod robustfpt_tests;
#[derive(Copy, Clone)]
pub struct ExtendedExponentFpt {
val_: f64,
exp_: i32,
}
const MAX_SIGNIFICANT_EXP_DIF_F64: i32 = 54;
impl From<&ei::ExtendedInt> for ExtendedExponentFpt {
#[inline]
fn from(that: &ei::ExtendedInt) -> Self {
let p = that.p();
Self::new(p.0, p.1)
}
}
impl From<ei::ExtendedInt> for ExtendedExponentFpt {
#[inline]
fn from(that: ei::ExtendedInt) -> Self {
let p = that.p();
Self::new(p.0, p.1)
}
}
impl From<ExtendedExponentFpt> for f64 {
#[inline]
fn from(that: ExtendedExponentFpt) -> f64 {
that.d()
}
}
impl From<f64> for ExtendedExponentFpt {
#[inline]
fn from(that: f64) -> ExtendedExponentFpt {
let rv = libm::frexp(that);
Self::new(rv.0, rv.1)
}
}
#[allow(dead_code)]
impl ExtendedExponentFpt {
#[inline]
pub fn new(val: f64, exp: i32) -> Self {
let fr = libm::frexp(val);
Self {
val_: fr.0,
exp_: exp + fr.1,
}
}
#[inline]
pub fn is_pos(&self) -> bool {
self.val_ > 0.0
}
#[inline]
pub fn is_neg(&self) -> bool {
self.val_ < 0.0
}
#[inline]
pub fn is_zero(&self) -> bool {
self.val_ == 0.0
}
#[inline]
pub fn sqrt(&self) -> Self {
let mut val = self.val_;
let mut exp = self.exp_;
if (exp & 1) != 0 {
val *= 2.0;
exp -= 1;
}
Self::new(val.sqrt(), exp >> 1)
}
pub fn d(&self) -> f64 {
libm::ldexp(self.val_, self.exp_)
}
pub fn val(&self) -> f64 {
self.val_
}
pub fn exp(&self) -> i32 {
self.exp_
}
}
impl ops::Neg for ExtendedExponentFpt {
type Output = Self;
fn neg(self) -> Self {
Self {
val_: -self.val_,
exp_: self.exp_,
}
}
}
impl ops::Add for ExtendedExponentFpt {
type Output = Self;
fn add(self, that: Self) -> Self {
if self.val_ == 0.0 || that.exp_ > self.exp_ + MAX_SIGNIFICANT_EXP_DIF_F64 {
return that;
}
if that.val_ == 0.0 || self.exp_ > that.exp_ + MAX_SIGNIFICANT_EXP_DIF_F64 {
return self;
}
if self.exp_ >= that.exp_ {
let exp_dif = self.exp_ - that.exp_;
let val = libm::ldexp(self.val_, exp_dif) + that.val_;
Self::new(val, that.exp_)
} else {
let exp_dif = that.exp_ - self.exp_;
let val = libm::ldexp(that.val_, exp_dif) + self.val_;
Self::new(val, self.exp_)
}
}
}
impl ops::Sub for ExtendedExponentFpt {
type Output = Self;
fn sub(self, that: Self) -> Self {
if self.val_ == 0.0 || that.exp_ > self.exp_ + MAX_SIGNIFICANT_EXP_DIF_F64 {
return Self::new(-that.val_, that.exp_);
}
if that.val_ == 0.0 || self.exp_ > that.exp_ + MAX_SIGNIFICANT_EXP_DIF_F64 {
return self;
}
if self.exp_ >= that.exp_ {
let exp_dif = self.exp_ - that.exp_;
let val = libm::ldexp(self.val_, exp_dif) - that.val_;
Self::new(val, that.exp_)
} else {
let exp_dif = that.exp_ - self.exp_;
let val = libm::ldexp(-that.val_, exp_dif) + self.val_;
Self::new(val, self.exp_)
}
}
}
impl ops::Mul for ExtendedExponentFpt {
type Output = Self;
fn mul(self, that: Self) -> Self {
let val = self.val_ * that.val_;
let exp = self.exp_ + that.exp_;
Self::new(val, exp)
}
}
impl ops::Mul<f64> for ExtendedExponentFpt {
type Output = Self;
fn mul(self, that: f64) -> Self {
let that = Self::from(that);
self * that
}
}
impl ops::Div for ExtendedExponentFpt {
type Output = Self;
fn div(self, that: Self) -> Self {
let val = self.val_ / that.val_;
let exp = self.exp_ - that.exp_;
Self::new(val, exp)
}
}
impl ops::Div<f64> for ExtendedExponentFpt {
type Output = Self;
fn div(self, that: f64) -> Self {
let that = Self::from(that);
let val = self.val_ / that.val_;
let exp = self.exp_ - that.exp_;
Self::new(val, exp)
}
}
impl ops::AddAssign for ExtendedExponentFpt {
fn add_assign(&mut self, that: Self) {
if self.val_ == 0.0 || that.exp_ > self.exp_ + MAX_SIGNIFICANT_EXP_DIF_F64 {
self.val_ = that.val_;
self.exp_ = that.exp_;
}
if that.val_ == 0.0 || self.exp_ > that.exp_ + MAX_SIGNIFICANT_EXP_DIF_F64 {
return;
}
if self.exp_ >= that.exp_ {
let exp_dif = self.exp_ - that.exp_;
let val = libm::ldexp(self.val_, exp_dif) + that.val_;
self.val_ = val;
self.exp_ = that.exp_;
} else {
let exp_dif = that.exp_ - self.exp_;
let val = libm::ldexp(that.val_, exp_dif) + self.val_;
self.val_ = val;
}
}
}
impl ops::SubAssign for ExtendedExponentFpt {
fn sub_assign(&mut self, that: Self) {
if self.val_ == 0.0 || that.exp_ > self.exp_ + MAX_SIGNIFICANT_EXP_DIF_F64 {
self.val_ = -that.val_;
self.exp_ = that.exp_;
}
if that.val_ == 0.0 || self.exp_ > that.exp_ + MAX_SIGNIFICANT_EXP_DIF_F64 {
return;
}
if self.exp_ >= that.exp_ {
let exp_dif = self.exp_ - that.exp_;
let val = libm::ldexp(self.val_, exp_dif) - that.val_;
self.val_ = val;
self.exp_ = that.exp_;
} else {
let exp_dif = that.exp_ - self.exp_;
let val = libm::ldexp(-that.val_, exp_dif) + self.val_;
self.val_ = val;
}
}
}
impl ops::MulAssign for ExtendedExponentFpt {
fn mul_assign(&mut self, that: Self) {
self.val_ *= that.val_;
self.exp_ += that.exp_;
}
}
impl ops::DivAssign for ExtendedExponentFpt {
fn div_assign(&mut self, that: Self) {
self.val_ /= that.val_;
self.exp_ -= that.exp_;
}
}
impl fmt::Debug for ExtendedExponentFpt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}^{}", self.val_, self.exp_)
}
}