use dashu_base::{EstimatedLog2, Sign};
use dashu_int::{DoubleWord, IBig, UBig};
use crate::{error::panic_divide_by_0, repr::Repr};
#[derive(PartialOrd, Ord)]
#[repr(transparent)]
pub struct RBig(pub(crate) Repr);
#[derive(PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Relaxed(pub(crate) Repr);
impl RBig {
pub const ZERO: Self = Self(Repr::zero());
pub const ONE: Self = Self(Repr::one());
pub const NEG_ONE: Self = Self(Repr::neg_one());
#[inline]
pub fn from_parts(numerator: IBig, denominator: UBig) -> Self {
if denominator.is_zero() {
panic_divide_by_0()
}
Self(
Repr {
numerator,
denominator,
}
.reduce(),
)
}
#[inline]
pub fn into_parts(self) -> (IBig, UBig) {
(self.0.numerator, self.0.denominator)
}
#[inline]
pub fn from_parts_signed(numerator: IBig, denominator: IBig) -> Self {
let (sign, mag) = denominator.into_parts();
Self::from_parts(numerator * sign, mag)
}
#[inline]
pub const fn from_parts_const(
sign: Sign,
mut numerator: DoubleWord,
mut denominator: DoubleWord,
) -> Self {
if denominator == 0 {
panic_divide_by_0()
} else if numerator == 0 {
return Self::ZERO;
}
if numerator > 1 && denominator > 1 {
let (mut y, mut r) = (denominator, numerator % denominator);
while r > 1 {
let new_r = y % r;
y = r;
r = new_r;
}
if r == 0 {
numerator /= y;
denominator /= y;
}
}
Self(Repr {
numerator: IBig::from_parts_const(sign, numerator),
denominator: UBig::from_dword(denominator),
})
}
#[inline]
pub fn numerator(&self) -> &IBig {
&self.0.numerator
}
#[inline]
pub fn denominator(&self) -> &UBig {
&self.0.denominator
}
#[inline]
pub fn relax(self) -> Relaxed {
Relaxed(self.0)
}
#[inline]
pub const fn as_relaxed(&self) -> &Relaxed {
unsafe { core::mem::transmute(self) }
}
#[inline]
pub const fn is_zero(&self) -> bool {
self.0.numerator.is_zero()
}
#[inline]
pub const fn is_one(&self) -> bool {
self.0.numerator.is_one() && self.0.denominator.is_one()
}
#[inline]
pub const fn is_int(&self) -> bool {
self.0.denominator.is_one()
}
}
impl Clone for RBig {
#[inline]
fn clone(&self) -> RBig {
RBig(self.0.clone())
}
#[inline]
fn clone_from(&mut self, source: &RBig) {
self.0.clone_from(&source.0)
}
}
impl Default for RBig {
#[inline]
fn default() -> Self {
Self::ZERO
}
}
impl EstimatedLog2 for RBig {
#[inline]
fn log2_bounds(&self) -> (f32, f32) {
self.0.log2_bounds()
}
#[inline]
fn log2_est(&self) -> f32 {
self.0.log2_est()
}
}
impl Relaxed {
pub const ZERO: Self = Self(Repr::zero());
pub const ONE: Self = Self(Repr::one());
pub const NEG_ONE: Self = Self(Repr::neg_one());
#[inline]
pub fn from_parts(numerator: IBig, denominator: UBig) -> Self {
if denominator.is_zero() {
panic_divide_by_0();
}
Self(
Repr {
numerator,
denominator,
}
.reduce2(),
)
}
#[inline]
pub fn into_parts(self) -> (IBig, UBig) {
(self.0.numerator, self.0.denominator)
}
#[inline]
pub fn from_parts_signed(numerator: IBig, denominator: IBig) -> Self {
let (sign, mag) = denominator.into_parts();
Self::from_parts(numerator * sign, mag)
}
#[inline]
pub const fn from_parts_const(
sign: Sign,
numerator: DoubleWord,
denominator: DoubleWord,
) -> Self {
if denominator == 0 {
panic_divide_by_0()
} else if numerator == 0 {
return Self::ZERO;
}
let n2 = numerator.trailing_zeros();
let d2 = denominator.trailing_zeros();
let zeros = if n2 <= d2 { n2 } else { d2 };
Self(Repr {
numerator: IBig::from_parts_const(sign, numerator >> zeros),
denominator: UBig::from_dword(denominator >> zeros),
})
}
#[doc(hidden)]
#[rustversion::since(1.64)]
#[inline]
pub const unsafe fn from_static_words(
sign: dashu_base::Sign,
numerator_words: &'static [dashu_int::Word],
denominator_words: &'static [dashu_int::Word],
) -> Self {
Self(Repr::from_static_words(sign, numerator_words, denominator_words))
}
#[inline]
pub fn numerator(&self) -> &IBig {
&self.0.numerator
}
#[inline]
pub fn denominator(&self) -> &UBig {
&self.0.denominator
}
#[inline]
pub fn canonicalize(self) -> RBig {
RBig(self.0.reduce())
}
#[inline]
pub const fn is_zero(&self) -> bool {
self.0.numerator.is_zero()
}
#[inline]
pub fn is_one(&self) -> bool {
self.0.denominator.as_ibig() == &self.0.numerator
}
}
impl Clone for Relaxed {
#[inline]
fn clone(&self) -> Relaxed {
Relaxed(self.0.clone())
}
#[inline]
fn clone_from(&mut self, source: &Relaxed) {
self.0.clone_from(&source.0)
}
}
impl Default for Relaxed {
#[inline]
fn default() -> Self {
Self::ZERO
}
}
impl EstimatedLog2 for Relaxed {
#[inline]
fn log2_bounds(&self) -> (f32, f32) {
self.0.log2_bounds()
}
#[inline]
fn log2_est(&self) -> f32 {
self.0.log2_est()
}
}