Skip to content

lib: minor fixes #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,5 @@ num = { version = "0.1.40", default-features=false, features=["bigint"] }
num-traits = "0.1.40"
serde = { version = "1", optional = true }

[dev-dependencies.rand]
version = "0.3"

[dev-dependencies.serde_json]
version = "1"
14 changes: 14 additions & 0 deletions examples/floating-precision.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
extern crate bigdecimal;

use bigdecimal::BigDecimal;
use std::str::FromStr;

fn main() {
let input = std::env::args().skip(1).next().unwrap_or("0.7".to_string());
let decimal = BigDecimal::from_str(&input).expect("invalid decimal");
let floating = f32::from_str(&input).expect("invalid float");

println!("Input string: {}", &input);
println!("Big-decimal value: {:.10}", decimal);
println!("Floating-point value: {:.10}", floating);
}
57 changes: 29 additions & 28 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,33 @@

//! A Big Decimal
//!
//! BigDecimal allows storing any real number to arbitrary precision; which
//! `BigDecimal` allows storing any real number to arbitrary precision; which
//! avoids common floating point errors (such as 0.1 + 0.2 ≠ 0.3) at the
//! cost of complexity.
//!
//! Internally, `BigDecimal` uses a `BigInt` object, paired with a 64-bit
//! integer which determines the position of the decimal point. Therefore,
//! the precision *is not* actually arbitrary, but limitied to 2^63 decimal
//! places.
//! the precision *is not* actually arbitrary, but limited to 2<sup>63</sup>
//! decimal places.
//!
//! Common numerical operations are overloaded, so we can treat them
//! the same way we treat other numbers.
//!
//! It is not recommended to convert a floating point number to a decimal
//! directly, as the floating point representation may be unexpected.
//!
//! # Example
//!
//! ```
//! use bigdecimal::BigDecimal;
//! use std::str::FromStr;
//!
//! let input = "0.8";
//! let dec = BigDecimal::from_str(&input).unwrap();
//! let float = f32::from_str(&input).unwrap();
//!
//! println!("Input ({}) with 10 decimals: {} vs {})", input, dec, float);
//! ```

extern crate num;
extern crate num_traits as traits;
Expand Down Expand Up @@ -181,17 +193,14 @@ impl BigDecimal {
if new_scale > self.scale {
let scale_diff = new_scale - self.scale;
let int_val = &self.int_val * ten_to_the(scale_diff as u64);
return BigDecimal::new(int_val, new_scale);

BigDecimal::new(int_val, new_scale)
} else if new_scale < self.scale {
let scale_diff = self.scale - new_scale;
let int_val = &self.int_val / ten_to_the(scale_diff as u64);
return BigDecimal::new(int_val, new_scale);

BigDecimal::new(int_val, new_scale)
} else {
return self.clone();
self.clone()
}

}

/// Return the sign of the `BigDecimal` as `num::bigint::Sign`.
Expand Down Expand Up @@ -380,23 +389,15 @@ impl Ord for BigDecimal {
impl PartialEq for BigDecimal {
#[inline]
fn eq(&self, rhs: &BigDecimal) -> bool {
// println!("{}E{} =?= {}E{}",
// self.int_val,
// self.scale,
// rhs.int_val,
// rhs.scale);

// fix scale and test equality
if self.scale > rhs.scale {
let scaled_int_val = &rhs.int_val * ten_to_the((self.scale - rhs.scale) as u64);
return self.int_val == scaled_int_val;

self.int_val == scaled_int_val
} else if self.scale < rhs.scale {
let scaled_int_val = &self.int_val * ten_to_the((rhs.scale - self.scale) as u64);
return scaled_int_val == rhs.int_val;

scaled_int_val == rhs.int_val
} else {
return self.int_val == rhs.int_val;
self.int_val == rhs.int_val
}
}
}
Expand Down Expand Up @@ -542,9 +543,9 @@ impl<'a, 'b> Div<&'b BigDecimal> for &'a BigDecimal {
#[allow(non_snake_case)]
fn div(self, other: &BigDecimal) -> BigDecimal {
let scale = self.scale - other.scale;
let ref num = self.int_val;
let ref den = other.int_val;
let (quotient, remainder) = num.div_rem(&den);
let num = &self.int_val;
let den = &other.int_val;
let (quotient, remainder) = num.div_rem(den);

// no remainder - quotient is final solution
if remainder == BigInt::zero() {
Expand All @@ -558,7 +559,7 @@ impl<'a, 'b> Div<&'b BigDecimal> for &'a BigDecimal {
let MAX_ITERATIONS = 100;
let mut iteration_count = 0;
while remainder != BigInt::zero() && iteration_count < MAX_ITERATIONS {
let (q, r) = remainder.div_rem(&den);
let (q, r) = remainder.div_rem(den);
quotient = quotient * BIG_TEN + q;
remainder = r * BIG_TEN;

Expand Down Expand Up @@ -683,7 +684,7 @@ impl fmt::Display for BigDecimal {
};

// Concatenate everything
let complete = if after.len() > 0 {
let complete = if !after.is_empty() {
before + "." + after.as_str()
} else {
before
Expand Down Expand Up @@ -760,7 +761,7 @@ impl Num for BigDecimal {
let mut digits = String::from(lead);

// copy all trailing characters after '.' into the digits string
digits.extend(trail.chars());
digits.push_str(trail);

(digits, trail.len() as i64)
}
Expand All @@ -769,7 +770,7 @@ impl Num for BigDecimal {
let scale = decimal_offset - exponent_value;
let big_int = try!(BigInt::from_str_radix(&digits, radix));

return Ok(BigDecimal::new(big_int, scale));
Ok(BigDecimal::new(big_int, scale))
}
}

Expand All @@ -783,7 +784,7 @@ impl ToPrimitive for BigDecimal {
fn to_u64(&self) -> Option<u64> {
match self.sign() {
Sign::Plus => self.with_scale(0).int_val.to_u64(),
Sign::NoSign => return Some(0),
Sign::NoSign => Some(0),
Sign::Minus => None,
}
}
Expand Down