use num_traits::Zero;
use rug::Integer;
use crate::rfloat::RFloat;
use crate::Real;
#[derive(Clone, Debug)]
pub struct Split {
high: RFloat,
low: RFloat,
max_p: Option<usize>,
split_pos: isize,
}
impl Split {
pub fn new<T: Real>(num: &T, max_p: Option<usize>, n: isize) -> Self {
assert!(!num.is_nar(), "must be real {:?}", num);
let (high, low) = num.split(n);
Self {
high,
low,
max_p,
split_pos: n,
}
}
pub fn num(&self) -> &RFloat {
&self.high
}
pub fn lost(&self) -> &RFloat {
&self.low
}
pub fn max_p(&self) -> Option<usize> {
self.max_p
}
pub fn split_pos(&self) -> isize {
self.split_pos
}
pub fn rgs(&self) -> (bool, bool, bool) {
let (half, lower) = self.low.split(self.split_pos - 1);
let (quarter, lower) = lower.split(self.split_pos - 2);
(!half.is_zero(), !quarter.is_zero(), !lower.is_zero())
}
pub fn rs(&self) -> (bool, bool) {
let (half, lower) = self.low.split(self.split_pos - 1);
(!half.is_zero(), !lower.is_zero())
}
pub fn is_exact(&self) -> bool {
self.low.is_zero()
}
}
impl Real for Split {
fn radix() -> usize {
2
}
fn sign(&self) -> Option<bool> {
self.high.sign()
}
fn exp(&self) -> Option<isize> {
match self.low.exp() {
Some(exp) => Some(exp),
None => self.high.exp(),
}
}
fn e(&self) -> Option<isize> {
match self.high.e() {
Some(e) => Some(e),
None => self.low.e(),
}
}
fn n(&self) -> Option<isize> {
match self.low.n() {
Some(n) => Some(n),
None => self.high.n(),
}
}
fn c(&self) -> Option<Integer> {
match (self.high.is_zero(), self.low.is_zero()) {
(true, true) => Some(Integer::zero()),
(false, true) => self.high.c(),
(true, false) => self.low.c(),
(false, false) => {
let c1 = self.high.c().unwrap();
let c2 = self.low.c().unwrap();
let offset = self.high.exp().unwrap() - self.low.exp().unwrap();
Some((c1 << offset) + c2)
}
}
}
fn m(&self) -> Option<Integer> {
self.c().map(|c| if self.sign().unwrap() { -c } else { c })
}
fn prec(&self) -> Option<usize> {
match (self.e(), self.n()) {
(None, None) => None,
(Some(e), Some(n)) => Some((e - n) as usize),
(_, _) => panic!("unreachable"),
}
}
fn is_nar(&self) -> bool {
false
}
fn is_finite(&self) -> bool {
true
}
fn is_infinite(&self) -> bool {
false
}
fn is_zero(&self) -> bool {
self.high.is_zero() && self.low.is_zero()
}
fn is_negative(&self) -> Option<bool> {
match self.high.is_negative() {
Some(b) => Some(b),
None => self.low.is_negative(),
}
}
fn is_numerical(&self) -> bool {
true
}
}