use core::cmp::Ordering;
use core::fmt;
use crate::float::{Float, RoundingMode};
use crate::int::{Int, Sign};
#[derive(Clone)]
pub struct FixedFloat {
value: Float,
mode: RoundingMode,
}
impl FixedFloat {
#[inline]
pub fn from_float(value: Float, mode: RoundingMode) -> FixedFloat {
FixedFloat { value, mode }
}
pub fn from_int(n: &Int, precision: u64, mode: RoundingMode) -> FixedFloat {
FixedFloat {
value: Float::from_int(n, precision, mode),
mode,
}
}
pub fn from_f64(x: f64, precision: u64, mode: RoundingMode) -> FixedFloat {
FixedFloat {
value: Float::from_f64(x, precision, mode),
mode,
}
}
pub fn zero(precision: u64, mode: RoundingMode) -> FixedFloat {
FixedFloat {
value: Float::zero(precision),
mode,
}
}
pub fn nan(precision: u64, mode: RoundingMode) -> FixedFloat {
FixedFloat {
value: Float::nan(precision),
mode,
}
}
pub fn infinity(precision: u64, mode: RoundingMode) -> FixedFloat {
FixedFloat {
value: Float::infinity(precision),
mode,
}
}
pub fn neg_infinity(precision: u64, mode: RoundingMode) -> FixedFloat {
FixedFloat {
value: Float::neg_infinity(precision),
mode,
}
}
pub fn pi(precision: u64, mode: RoundingMode) -> FixedFloat {
FixedFloat {
value: Float::pi(precision, mode),
mode,
}
}
pub fn e(precision: u64, mode: RoundingMode) -> FixedFloat {
FixedFloat {
value: Float::e(precision, mode),
mode,
}
}
#[inline]
pub fn precision(&self) -> u64 {
self.value.precision()
}
#[inline]
pub fn rounding_mode(&self) -> RoundingMode {
self.mode
}
#[inline]
pub fn as_float(&self) -> &Float {
&self.value
}
#[inline]
pub fn into_float(self) -> Float {
self.value
}
#[inline]
pub fn to_f64(&self) -> f64 {
self.value.to_f64()
}
#[inline]
pub fn to_shortest_string(&self) -> alloc::string::String {
self.value.to_shortest_string()
}
#[inline]
pub fn is_nan(&self) -> bool {
self.value.is_nan()
}
#[inline]
pub fn is_infinite(&self) -> bool {
self.value.is_infinite()
}
#[inline]
pub fn is_finite(&self) -> bool {
self.value.is_finite()
}
#[inline]
pub fn is_zero(&self) -> bool {
self.value.is_zero()
}
#[inline]
pub fn sign(&self) -> Sign {
self.value.sign()
}
pub fn with_precision(&self, precision: u64) -> FixedFloat {
FixedFloat {
value: self.value.round(precision, self.mode),
mode: self.mode,
}
}
fn combine(
&self,
rhs: &FixedFloat,
op: fn(&Float, &Float, u64, RoundingMode) -> Float,
) -> FixedFloat {
let precision = self.value.precision().max(rhs.value.precision());
FixedFloat {
value: op(&self.value, &rhs.value, precision, self.mode),
mode: self.mode,
}
}
pub fn neg(&self) -> FixedFloat {
FixedFloat {
value: self.value.neg(),
mode: self.mode,
}
}
pub fn abs(&self) -> FixedFloat {
FixedFloat {
value: self.value.abs(),
mode: self.mode,
}
}
pub fn sqrt(&self) -> FixedFloat {
self.unary(Float::sqrt)
}
pub fn exp(&self) -> FixedFloat {
self.unary(Float::exp)
}
pub fn ln(&self) -> FixedFloat {
self.unary(Float::ln)
}
pub fn sin(&self) -> FixedFloat {
self.unary(Float::sin)
}
pub fn cos(&self) -> FixedFloat {
self.unary(Float::cos)
}
pub fn tan(&self) -> FixedFloat {
self.unary(Float::tan)
}
pub fn atan(&self) -> FixedFloat {
self.unary(Float::atan)
}
pub fn pow(&self, exp: &FixedFloat) -> FixedFloat {
let precision = self.value.precision().max(exp.value.precision());
FixedFloat {
value: self.value.pow(&exp.value, precision, self.mode),
mode: self.mode,
}
}
fn unary(&self, op: fn(&Float, u64, RoundingMode) -> Float) -> FixedFloat {
FixedFloat {
value: op(&self.value, self.value.precision(), self.mode),
mode: self.mode,
}
}
}
impl PartialEq for FixedFloat {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
impl PartialOrd for FixedFloat {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.value.partial_cmp(&other.value)
}
}
impl fmt::Display for FixedFloat {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.value, f)
}
}
impl fmt::Debug for FixedFloat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "FixedFloat({:?}, {:?})", self.value, self.mode)
}
}
macro_rules! fixed_binop {
($tr:ident, $m:ident, $atr:ident, $am:ident, $call:path) => {
impl core::ops::$tr for FixedFloat {
type Output = FixedFloat;
#[inline]
fn $m(self, rhs: FixedFloat) -> FixedFloat {
self.combine(&rhs, $call)
}
}
impl core::ops::$tr<&FixedFloat> for &FixedFloat {
type Output = FixedFloat;
#[inline]
fn $m(self, rhs: &FixedFloat) -> FixedFloat {
self.combine(rhs, $call)
}
}
impl core::ops::$atr for FixedFloat {
#[inline]
fn $am(&mut self, rhs: FixedFloat) {
*self = self.combine(&rhs, $call);
}
}
};
}
fixed_binop!(Add, add, AddAssign, add_assign, Float::add);
fixed_binop!(Sub, sub, SubAssign, sub_assign, Float::sub);
fixed_binop!(Mul, mul, MulAssign, mul_assign, Float::mul);
fixed_binop!(Div, div, DivAssign, div_assign, Float::div);
impl core::ops::Neg for FixedFloat {
type Output = FixedFloat;
#[inline]
fn neg(self) -> FixedFloat {
FixedFloat::neg(&self)
}
}