diff --git a/Cargo.toml b/Cargo.toml index e7274f6..a01b1be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/examples/floating-precision.rs b/examples/floating-precision.rs new file mode 100644 index 0000000..2813a1e --- /dev/null +++ b/examples/floating-precision.rs @@ -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); +} diff --git a/src/lib.rs b/src/lib.rs index aa869b5..210e655 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,14 +12,14 @@ //! 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 263 +//! decimal places. //! //! Common numerical operations are overloaded, so we can treat them //! the same way we treat other numbers. @@ -27,6 +27,18 @@ //! 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; @@ -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`. @@ -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 } } } @@ -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() { @@ -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; @@ -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 @@ -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) } @@ -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)) } } @@ -783,7 +784,7 @@ impl ToPrimitive for BigDecimal { fn to_u64(&self) -> Option { 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, } }