use crate::{
rfloat::{RFloat, RFloatContext},
Real, RoundingContext, RoundingMode, Split,
};
use super::{Exceptions, Float};
#[derive(Clone, Debug)]
pub struct FloatContext {
prec: usize,
rm: RoundingMode,
}
impl FloatContext {
pub fn new(prec: usize) -> Self {
Self {
prec,
rm: RoundingMode::NearestTiesToEven,
}
}
pub fn with_max_p(mut self, prec: usize) -> Self {
self.prec = prec;
self
}
pub fn with_rm(mut self, rm: RoundingMode) -> Self {
self.rm = rm;
self
}
pub fn max_p(&self) -> usize {
self.prec
}
pub fn rm(&self) -> RoundingMode {
self.rm
}
}
impl RoundingContext for FloatContext {
type Format = Float;
fn round<T: Real>(&self, val: &T) -> Self::Format {
if val.is_zero() {
Float {
num: RFloat::zero(),
flags: Exceptions::default(),
ctx: self.clone(),
}
} else if val.is_infinite() {
if val.sign().unwrap() {
Float {
num: RFloat::NegInfinity,
flags: Exceptions::default(),
ctx: self.clone(),
}
} else {
Float {
num: RFloat::PosInfinity,
flags: Exceptions::default(),
ctx: self.clone(),
}
}
} else if val.is_nar() {
Float {
num: RFloat::Nan,
flags: Exceptions::default(),
ctx: self.clone(),
}
} else {
let (p, n) = RFloatContext::new()
.with_max_p(self.max_p())
.round_params(val);
let split = Split::new(val, p, n);
let inexact = !split.is_exact();
let unrounded_e = split.e();
let rounded = RFloatContext::round_finalize(split, self.rm);
let carry = match (unrounded_e, rounded.e()) {
(Some(e1), Some(e2)) => e2 > e1,
(_, _) => false,
};
Float {
num: rounded,
flags: Exceptions {
inexact,
carry,
..Default::default()
},
ctx: self.clone(),
}
}
}
}