Skip to content

Commit

Permalink
Merge move-addition-impl into trunk
Browse files Browse the repository at this point in the history
  • Loading branch information
akubera committed Mar 5, 2024
2 parents 33f44aa + 03105f3 commit bfb249c
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 71 deletions.
110 changes: 110 additions & 0 deletions src/arithmetic/addition.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//! addition routines
//!
use crate::*;


pub(crate) fn add_bigdecimals(
mut a: BigDecimal,
mut b: BigDecimal,
) -> BigDecimal {
if b.is_zero() {
if a.scale < b.scale {
a.int_val *= ten_to_the((b.scale - a.scale) as u64);
a.scale = b.scale;
}
return a;
}

if a.is_zero() {
if b.scale < a.scale {
b.int_val *= ten_to_the((a.scale - b.scale) as u64);
b.scale = a.scale;
}
return b;
}

let (a, b) = match a.scale.cmp(&b.scale) {
Ordering::Equal => (a, b),
Ordering::Less => (a.take_and_scale(b.scale), b),
Ordering::Greater => (b.take_and_scale(a.scale), a),
};

add_aligned_bigdecimals(a, b)
}

fn add_aligned_bigdecimals(
mut a: BigDecimal,
mut b: BigDecimal,
) -> BigDecimal {
debug_assert_eq!(a.scale, b.scale);
if a.int_val.bits() >= b.int_val.bits() {
a.int_val += b.int_val;
a
} else {
b.int_val += a.int_val;
b
}
}


pub(crate) fn add_bigdecimal_refs<'a, 'b, Lhs, Rhs>(
lhs: Lhs,
rhs: Rhs,
) -> BigDecimal
where
Rhs: Into<BigDecimalRef<'a>>,
Lhs: Into<BigDecimalRef<'b>>,
{
let lhs = lhs.into();
let rhs = rhs.into();
if rhs.is_zero() {
return lhs.to_owned();
}
if lhs.is_zero() {
return rhs.to_owned();
}
if lhs.scale >= rhs.scale {
lhs.to_owned() + rhs
} else {
rhs.to_owned() + lhs
}
}


pub(crate) fn addassign_bigdecimals(
lhs: &mut BigDecimal,
rhs: BigDecimal,
) {
if rhs.is_zero() {
return;
}
if lhs.is_zero() {
*lhs = rhs;
return;
}
lhs.add_assign(rhs.to_ref());
}


pub(crate) fn addassign_bigdecimal_ref<'a, T: Into<BigDecimalRef<'a>>>(
lhs: &mut BigDecimal,
rhs: T,
) {
// TODO: Replace to_owned() with efficient addition algorithm
let rhs = rhs.into().to_owned();
match lhs.scale.cmp(&rhs.scale) {
Ordering::Less => {
let scaled = lhs.with_scale(rhs.scale);
lhs.int_val = scaled.int_val + &rhs.int_val;
lhs.scale = rhs.scale;
}
Ordering::Greater => {
let scaled = rhs.with_scale(lhs.scale);
lhs.int_val += scaled.int_val;
}
Ordering::Equal => {
lhs.int_val += &rhs.int_val;
}
}
}
34 changes: 34 additions & 0 deletions src/arithmetic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use crate::*;

pub(crate) mod addition;
pub(crate) mod sqrt;
pub(crate) mod cbrt;
pub(crate) mod inverse;
Expand All @@ -14,6 +15,12 @@ pub(crate) fn ten_to_the(pow: u64) -> BigInt {
ten_to_the_uint(pow).into()
}

/// Return 10^{pow} as u64
pub(crate) fn ten_to_the_u64(pow: u8) -> u64 {
debug_assert!(pow < 20);
10u64.pow(pow as u32)
}

/// Return 10^pow
pub(crate) fn ten_to_the_uint(pow: u64) -> BigUint {
if pow < 20 {
Expand Down Expand Up @@ -74,3 +81,30 @@ pub(crate) fn count_decimal_digits_uint(uint: &BigUint) -> u64 {
}
digits
}


/// Return difference of two numbers, returning diff as u64
pub(crate) fn diff<T>(a: T, b: T) -> (Ordering, u64)
where
T: ToPrimitive + stdlib::ops::Sub<Output=T> + stdlib::cmp::Ord
{
use stdlib::cmp::Ordering::*;

match a.cmp(&b) {
Less => (Less, (b - a).to_u64().unwrap()),
Greater => (Greater, (a - b).to_u64().unwrap()),
Equal => (Equal, 0),
}
}

/// Return difference of two numbers, returning diff as usize
#[allow(dead_code)]
pub(crate) fn diff_usize(a: usize, b: usize) -> (Ordering, usize) {
use stdlib::cmp::Ordering::*;

match a.cmp(&b) {
Less => (Less, b - a),
Greater => (Greater, a - b),
Equal => (Equal, 0),
}
}
71 changes: 9 additions & 62 deletions src/impl_ops_add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,7 @@ impl Add<BigDecimal> for BigDecimal {

#[inline]
fn add(self, rhs: BigDecimal) -> BigDecimal {
if rhs.is_zero() {
return self;
}
if self.is_zero() {
return rhs;
}

let mut lhs = self;
match lhs.scale.cmp(&rhs.scale) {
Ordering::Equal => {
lhs.int_val += rhs.int_val;
lhs
}
Ordering::Less => lhs.take_and_scale(rhs.scale) + rhs,
Ordering::Greater => rhs.take_and_scale(lhs.scale) + lhs,
}
arithmetic::addition::add_bigdecimals(self, rhs)
}
}

Expand Down Expand Up @@ -61,18 +46,7 @@ impl Add<BigDecimal> for &'_ BigDecimal {
impl<'a, T: Into<BigDecimalRef<'a>>> Add<T> for &'_ BigDecimal {
type Output = BigDecimal;
fn add(self, rhs: T) -> BigDecimal {
let rhs = rhs.into();
if rhs.is_zero() {
return self.clone();
}
if self.is_zero() {
return rhs.to_owned();
}
if self.scale >= rhs.scale {
self.to_owned() + rhs
} else {
rhs.to_owned() + self
}
arithmetic::addition::add_bigdecimal_refs(self, rhs)
}
}

Expand All @@ -98,12 +72,7 @@ impl Add<BigDecimal> for BigDecimalRef<'_> {
impl<'a, T: Into<BigDecimalRef<'a>>> Add<T> for BigDecimalRef<'_> {
type Output = BigDecimal;
fn add(self, rhs: T) -> BigDecimal {
let rhs = rhs.into();
if self.scale >= rhs.scale {
self.to_owned() + rhs
} else {
rhs.to_owned() + self
}
arithmetic::addition::add_bigdecimal_refs(self, rhs)
}
}

Expand All @@ -122,23 +91,23 @@ impl Add<BigDecimal> for BigInt {

#[inline]
fn add(self, rhs: BigDecimal) -> BigDecimal {
rhs + self
BigDecimal::from(self) + rhs
}
}

impl<'a> Add<&'a BigDecimal> for BigInt {
type Output = BigDecimal;

fn add(self, rhs: &BigDecimal) -> BigDecimal {
rhs.to_ref().add(self)
BigDecimal::from(self) + rhs
}
}

impl<'a> Add<BigDecimalRef<'a>> for BigInt {
type Output = BigDecimal;

fn add(self, rhs: BigDecimalRef<'_>) -> BigDecimal {
rhs.add(self)
BigDecimal::from(self) + rhs
}
}

Expand Down Expand Up @@ -173,43 +142,21 @@ impl<'a> Add<BigDecimalRef<'a>> for &BigInt {

impl AddAssign<BigDecimal> for BigDecimal {
fn add_assign(&mut self, rhs: BigDecimal) {
if rhs.is_zero() {
return;
}
if self.is_zero() {
*self = rhs;
return;
}
self.add_assign(rhs.to_ref());
arithmetic::addition::addassign_bigdecimals(self, rhs)
}
}

impl<'a, N: Into<BigDecimalRef<'a>>> AddAssign<N> for BigDecimal {
#[inline]
fn add_assign(&mut self, rhs: N) {
// TODO: Replace to_owned() with efficient addition algorithm
let rhs = rhs.into().to_owned();
match self.scale.cmp(&rhs.scale) {
Ordering::Less => {
let scaled = self.with_scale(rhs.scale);
self.int_val = scaled.int_val + &rhs.int_val;
self.scale = rhs.scale;
}
Ordering::Greater => {
let scaled = rhs.with_scale(self.scale);
self.int_val += scaled.int_val;
}
Ordering::Equal => {
self.int_val += &rhs.int_val;
}
}
arithmetic::addition::addassign_bigdecimal_ref(self, rhs)
}
}

impl AddAssign<BigInt> for BigDecimal {
#[inline]
fn add_assign(&mut self, rhs: BigInt) {
self.add_assign(&rhs);
self.add_assign(BigDecimal::from(rhs));
}
}

Expand Down
33 changes: 24 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,14 @@ pub use context::Context;
use arithmetic::{
ten_to_the,
ten_to_the_uint,
ten_to_the_u64,
diff,
diff_usize,
count_decimal_digits,
count_decimal_digits_uint,
};


/// Internal function used for rounding
///
/// returns 1 if most significant digit is >= 5, otherwise 0
Expand Down Expand Up @@ -380,20 +384,31 @@ impl BigDecimal {
///
fn take_and_scale(mut self, new_scale: i64) -> BigDecimal {
if self.int_val.is_zero() {
return BigDecimal::new(BigInt::zero(), new_scale);
self.scale = new_scale;
return self;
}

match new_scale.cmp(&self.scale) {
Ordering::Greater => {
self.int_val *= ten_to_the((new_scale - self.scale) as u64);
BigDecimal::new(self.int_val, new_scale)
match diff(new_scale, self.scale) {
(Ordering::Greater, scale_diff) => {
self.scale = new_scale;
if scale_diff < 20 {
self.int_val *= ten_to_the_u64(scale_diff as u8);
} else {
self.int_val *= ten_to_the(scale_diff);
}
}
Ordering::Less => {
self.int_val /= ten_to_the((self.scale - new_scale) as u64);
BigDecimal::new(self.int_val, new_scale)
(Ordering::Less, scale_diff) => {
self.scale = new_scale;
if scale_diff < 20 {
self.int_val /= ten_to_the_u64(scale_diff as u8);
} else {
self.int_val /= ten_to_the(scale_diff);
}
}
Ordering::Equal => self,
(Ordering::Equal, _) => {},
}

self
}

/// Take and return bigdecimal with the given sign
Expand Down

0 comments on commit bfb249c

Please sign in to comment.