bigdecimal-0.1.0/.gitignore010066400017500001750000000000351345412424200140020ustar0000000000000000Cargo.lock target .vscode/ bigdecimal-0.1.0/.travis.yml010066400017500001750000000015641345413603000141310ustar0000000000000000language: rust rust: - 1.16.0 - 1.22.0 - 1.30.0 - stable - beta - nightly sudo: false script: - cargo build --verbose - cargo test - cargo test --features serde matrix: allow_failures: - rust: nightly addons: apt: packages: - libcurl4-openssl-dev - libelf-dev - libdw-dev - cmake - gcc - binutils-dev - libiberty-dev after_success: | curl -L https://github.com/SimonKagstrom/kcov/archive/master.tar.gz | tar xz && pushd kcov-master && mkdir build && cmake -DCMAKE_INSTALL_PREFIX=$HOME . && make install && popd && for file in target/debug/bigdecimal-*[^\.d]; do mkdir -p "target/cov/$(basename $file)"; $HOME/bin/kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file"; done && bash <(curl -s https://codecov.io/bash) && echo "Uploaded code coverage" bigdecimal-0.1.0/COPYRIGHT010066400017500001750000000004101330261763100133030ustar0000000000000000The BigDecimal project is licensed under the Apache License, Version 2.0 or the MIT license at your option. All files in the project carrying such notice may not be copied, modified, or distributed, except according to these terms. bigdecimal-0.1.0/Cargo.toml.orig010066400017500001750000000010721345413603000147010ustar0000000000000000[package] name = "bigdecimal" version = "0.1.0" authors = ["Andrew Kubera"] description = "Arbitrary percision decimal numbers" documentation = "https://docs.rs/bigdecimal" homepage = "https://github.com/akubera/bigdecimal-rs" repository = "https://github.com/akubera/bigdecimal-rs" keywords = ["mathematics", "numerics", "decimal", "arbitrary-precision", "floating-point"] license = "MIT/Apache-2.0" [dependencies] num-bigint = "0.2" num-integer = "0.1.39" num-traits = "0.2" serde = { version = "1.0", optional = true } [dev-dependencies.serde_json] version = "1.0" bigdecimal-0.1.0/Cargo.toml0000644000000022060000000000000111470ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "bigdecimal" version = "0.1.0" authors = ["Andrew Kubera"] description = "Arbitrary percision decimal numbers" homepage = "https://github.com/akubera/bigdecimal-rs" documentation = "https://docs.rs/bigdecimal" keywords = ["mathematics", "numerics", "decimal", "arbitrary-precision", "floating-point"] license = "MIT/Apache-2.0" repository = "https://github.com/akubera/bigdecimal-rs" [dependencies.num-bigint] version = "0.2" [dependencies.num-integer] version = "0.1.39" [dependencies.num-traits] version = "0.2" [dependencies.serde] version = "1.0" optional = true [dev-dependencies.serde_json] version = "1.0" bigdecimal-0.1.0/LICENSE-APACHE010066400017500001750000000251441330261763100137470ustar0000000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2017 The BigDecimal-rs Contributors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. bigdecimal-0.1.0/LICENSE-MIT010066400017500001750000000020631330261763100134520ustar0000000000000000Copyright (c) 2017 The BigDecimal-rs Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. bigdecimal-0.1.0/README.rst010066400017500001750000000024401345413657000135120ustar0000000000000000============= bigdecimal-rs ============= |travis-badge| |codecov-badge| |gitter-badge| Documentation_ Arbitrary-precision decimal numbers implemented for rust. About ----- This repository contains code originally meant for a bigdecimal module in the popular num_ crate, but was not merged due to uncertainty of what is the best design for such a crate. I created this repository to test various implementations and host a conversation about community wants and needs. License ------- This code is dual-licensed under the permissive MIT_ & `Apache 2.0`_ licenses. .. _Documentation: https://docs.rs/bigdecimal .. _num: https://crates.io/crates/num .. _MIT: https://opensource.org/licenses/MIT .. _Apache 2.0: https://opensource.org/licenses/Apache-2.0 .. |travis-badge| image:: https://travis-ci.org/akubera/bigdecimal-rs.svg?branch=master :target: https://travis-ci.org/akubera/bigdecimal-rs :alt: Travis-Ci .. |codecov-badge| image:: https://codecov.io/gh/akubera/bigdecimal-rs/branch/master/graph/badge.svg :target: https://codecov.io/gh/akubera/bigdecimal-rs :alt: CodeCov.io .. |gitter-badge| image:: https://badges.gitter.im/bigdecimal-rs/Lobby.svg :target: https://gitter.im/bigdecimal-rs/Lobby?utm_source=badge&utm_medium=badge :alt: Gitter bigdecimal-0.1.0/examples/floating-precision.rs010066400017500001750000000007151345412424200177770ustar0000000000000000extern 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); } bigdecimal-0.1.0/examples/repeated_squares.rs010066400017500001750000000010571345412424200175370ustar0000000000000000 extern crate bigdecimal; use bigdecimal::BigDecimal; use std::time::Instant; use std::str::FromStr; fn main() { // let mut x = BigDecimal::from(1.1); let mut x = BigDecimal::from_str("1.1").unwrap(); // for iter in 0..1_000_000 { for iter in 0..1_000 { let start = Instant::now(); x = x.clone() * x; // x = x.take_and_square(); let end = Instant::now(); let usage = end - start; println!("iter {} takes {} secs", iter, usage.as_secs() as f32 + usage.subsec_nanos() as f32 / 1.0e9); } } bigdecimal-0.1.0/src/lib.rs010066400017500001750000002473071345413603000137320ustar0000000000000000// Copyright 2016 Adam Sunderland // 2016-2017 Andrew Kubera // 2017 Ruben De Smet // See the COPYRIGHT file at the top-level directory of this // distribution. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! A Big Decimal //! //! `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 limited to 263 //! 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_bigint; extern crate num_integer; extern crate num_traits as traits; #[cfg(feature = "serde")] extern crate serde; use std::cmp::Ordering; use std::default::Default; use std::error::Error; use std::fmt; use std::hash::{Hash, Hasher}; use std::num::{ParseFloatError, ParseIntError}; use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Rem, Sub, SubAssign}; use std::iter::Sum; use std::str::{self, FromStr}; use num_bigint::{BigInt, ParseBigIntError, Sign, ToBigInt}; use num_integer::Integer; pub use traits::{FromPrimitive, Num, One, Signed, ToPrimitive, Zero}; #[macro_use] mod macros; #[inline(always)] fn ten_to_the(pow: u64) -> BigInt { if pow < 20 { BigInt::from(10u64.pow(pow as u32)) } else { let (half, rem) = pow.div_rem(&16); let mut x = ten_to_the(half); for _ in 0..4 { x = &x * &x; } if rem == 0 { x } else { x * ten_to_the(rem) } } } #[inline(always)] fn count_decimal_digits(int: &BigInt) -> u64 { if int.is_zero() { return 1; } // guess number of digits based on number of bits in UInt let mut digits = (int.bits() as f64 / 3.3219280949) as u64; let mut num = ten_to_the(digits); while int >= &num { num *= 10u8; digits += 1; } digits } /// Internal function used for rounding /// /// returns 1 if most significant digit is >= 5, otherwise 0 /// /// This is used after dividing a number by a power of ten and /// rounding the last digit. /// #[inline(always)] fn get_rounding_term(num: &BigInt) -> u8 { if num.is_zero() { return 0; } let digits = (num.bits() as f64 / 3.3219280949) as u64; let mut n = ten_to_the(digits); // loop-method loop { if num < &n { return 1; } n *= 5; if num < &n { return 0; } n *= 2; } // string-method // let s = format!("{}", num); // let high_digit = u8::from_str(&s[0..1]).unwrap(); // if high_digit < 5 { 0 } else { 1 } } /// A big decimal type. /// #[derive(Clone, Eq)] pub struct BigDecimal { int_val: BigInt, // A positive scale means a negative power of 10 scale: i64, } impl BigDecimal { /// Creates and initializes a `BigDecimal`. /// #[inline] pub fn new(digits: BigInt, scale: i64) -> BigDecimal { BigDecimal { int_val: digits, scale: scale, } } /// Creates and initializes a `BigDecimal`. /// /// # Examples /// /// ``` /// use bigdecimal::{BigDecimal, Zero}; /// /// assert_eq!(BigDecimal::parse_bytes(b"0", 10).unwrap(), BigDecimal::zero()); /// // assert_eq!(BigDecimal::parse_bytes(b"f", 16), BigDecimal::parse_bytes(b"16", 10)); /// ``` #[inline] pub fn parse_bytes(buf: &[u8], radix: u32) -> Option { str::from_utf8(buf) .ok() .and_then(|s| BigDecimal::from_str_radix(s, radix).ok()) } /// Return a new BigDecimal object equivalent to self, with internal /// scaling set to the number specified. /// If the new_scale is lower than the current value (indicating a larger /// power of 10), digits will be dropped (as precision is lower) /// #[inline] pub fn with_scale(&self, new_scale: i64) -> BigDecimal { if self.int_val.is_zero() { return BigDecimal::new(BigInt::zero(), new_scale); } 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); 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); BigDecimal::new(int_val, new_scale) } else { self.clone() } } #[inline(always)] fn take_and_scale(mut self, new_scale: i64) -> BigDecimal { // let foo = bar.moved_and_scaled_to() if self.int_val.is_zero() { return BigDecimal::new(BigInt::zero(), new_scale); } if new_scale > self.scale { self.int_val *= ten_to_the((new_scale - self.scale) as u64); BigDecimal::new(self.int_val, new_scale) } else if new_scale < self.scale { self.int_val /= ten_to_the((self.scale - new_scale) as u64); BigDecimal::new(self.int_val, new_scale) } else { self } } /// Return a new BigDecimal object with precision set to new value /// #[inline] pub fn with_prec(&self, prec: u64) -> BigDecimal { let digits = self.digits(); if digits > prec { let diff = digits - prec; let p = ten_to_the(diff); let (mut q, r) = self.int_val.div_rem(&p); // check for "leading zero" in remainder term; otherwise round if p < 10 * &r { q += get_rounding_term(&r); } BigDecimal { int_val: q, scale: self.scale - diff as i64, } } else if digits < prec { let diff = prec - digits; BigDecimal { int_val: &self.int_val * ten_to_the(diff), scale: self.scale + diff as i64, } } else { self.clone() } } /// Return the sign of the `BigDecimal` as `num::bigint::Sign`. /// /// # Examples /// /// ``` /// extern crate num_bigint; /// extern crate bigdecimal; /// use std::str::FromStr; /// /// assert_eq!(bigdecimal::BigDecimal::from_str("-1").unwrap().sign(), num_bigint::Sign::Minus); /// assert_eq!(bigdecimal::BigDecimal::from_str("0").unwrap().sign(), num_bigint::Sign::NoSign); /// assert_eq!(bigdecimal::BigDecimal::from_str("1").unwrap().sign(), num_bigint::Sign::Plus); /// ``` #[inline] pub fn sign(&self) -> num_bigint::Sign { self.int_val.sign() } /// Return the internal big integer value and an exponent. Note that a positive /// exponent indicates a negative power of 10. /// /// # Examples /// /// ``` /// extern crate num_bigint; /// extern crate bigdecimal; /// use std::str::FromStr; /// /// assert_eq!(bigdecimal::BigDecimal::from_str("1.1").unwrap().as_bigint_and_exponent(), /// (num_bigint::BigInt::from_str("11").unwrap(), 1)); #[inline] pub fn as_bigint_and_exponent(&self) -> (BigInt, i64) { (self.int_val.clone(), self.scale) } /// Convert into the internal big integer value and an exponent. Note that a positive /// exponent indicates a negative power of 10. /// /// # Examples /// /// ``` /// extern crate num_bigint; /// extern crate bigdecimal; /// use std::str::FromStr; /// /// assert_eq!(bigdecimal::BigDecimal::from_str("1.1").unwrap().into_bigint_and_exponent(), /// (num_bigint::BigInt::from_str("11").unwrap(), 1)); #[inline] pub fn into_bigint_and_exponent(self) -> (BigInt, i64) { (self.int_val, self.scale) } /// Number of digits in the non-scaled integer representation /// #[inline] pub fn digits(&self) -> u64 { count_decimal_digits(&self.int_val) } /// Compute the absolute value of number #[inline] pub fn abs(&self) -> BigDecimal { BigDecimal { int_val: self.int_val.abs(), scale: self.scale, } } #[inline] pub fn double(&self) -> BigDecimal { if self.is_zero() { self.clone() } else { BigDecimal { int_val: self.int_val.clone() * 2, scale: self.scale, } } } /// Divide this efficiently by 2 /// /// Note, if this is odd, the precision will increase by 1, regardless /// of the context's limit. /// #[inline] pub fn half(&self) -> BigDecimal { if self.is_zero() { self.clone() } else if self.int_val.is_even() { BigDecimal { int_val: self.int_val.clone().div(2u8), scale: self.scale, } } else { BigDecimal { int_val: self.int_val.clone().mul(5u8), scale: self.scale + 1, } } } /// #[inline] pub fn square(&self) -> BigDecimal { if self.is_zero() || self.is_one() { self.clone() } else { BigDecimal { int_val: self.int_val.clone() * &self.int_val, scale: self.scale * 2, } } } #[inline] pub fn cube(&self) -> BigDecimal { if self.is_zero() || self.is_one() { self.clone() } else { BigDecimal { int_val: self.int_val.clone() * &self.int_val * &self.int_val, scale: self.scale * 3, } } } /// Take the square root of the number /// /// If the value is < 0, None is returned /// #[inline] pub fn sqrt(&self) -> Option { if self.is_zero() || self.is_one() { return Some(self.clone()); } if self.is_negative() { return None; } // make guess let guess = { let log2_10 = 3.32192809488736234787031942948939018_f64; let magic_guess_scale = 1.1951678538495576_f64; let initial_guess = (self.int_val.bits() as f64 - self.scale as f64 * log2_10) / 2.0; let res = magic_guess_scale * initial_guess.exp2(); if res.is_normal() { BigDecimal::from(res) } else { // can't guess with float - just guess magnitude let scale = (self.int_val.bits() as f64 / -log2_10 + self.scale as f64).round() as i64; BigDecimal::new(BigInt::from(1), scale / 2) } }; // // wikipedia example - use for testing the algorithm // if self == &BigDecimal::from_str("125348").unwrap() { // running_result = BigDecimal::from(600) // } // TODO: Use context variable to set precision let max_precision = 100; let next_iteration = move |r: BigDecimal| { // division needs to be precise to (at least) one extra digit let tmp = impl_division( self.int_val.clone(), &r.int_val, self.scale - r.scale, max_precision + 1, ); // half will increase precision on each iteration (tmp + r).half() }; // calculate first iteration let mut running_result = next_iteration(guess); let mut prev_result = BigDecimal::one(); let mut result = BigDecimal::zero(); // TODO: Prove that we don't need to arbitrarily limit iterations // and that convergence can be calculated while prev_result != result { // store current result to test for convergence prev_result = result; // calculate next iteration running_result = next_iteration(running_result); // 'result' has clipped precision, 'running_result' has full precision result = if running_result.digits() > max_precision { running_result.with_prec(max_precision) } else { running_result.clone() }; } return Some(result); } /// Take the cube root of the number /// #[inline] pub fn cbrt(&self) -> BigDecimal { if self.is_zero() || self.is_one() { return self.clone(); } if self.is_negative() { return -self.abs().cbrt(); } // make guess let guess = { let log2_10 = 3.32192809488736234787031942948939018_f64; let magic_guess_scale = 1.124960491619939_f64; let initial_guess = (self.int_val.bits() as f64 - self.scale as f64 * log2_10) / 3.0; let res = magic_guess_scale * initial_guess.exp2(); if res.is_normal() { BigDecimal::from(res) } else { // can't guess with float - just guess magnitude let scale = (self.int_val.bits() as f64 / log2_10 - self.scale as f64).round() as i64; BigDecimal::new(BigInt::from(1), -scale / 3) } }; // TODO: Use context variable to set precision let max_precision = 100; let three = BigDecimal::from(3); let next_iteration = move |r: BigDecimal| { let sqrd = r.square(); let tmp = impl_division( self.int_val.clone(), &sqrd.int_val, self.scale - sqrd.scale, max_precision + 1, ); let tmp = tmp + r.double(); impl_division( tmp.int_val, &three.int_val, tmp.scale - three.scale, max_precision + 1, ) }; // result initial let mut running_result = next_iteration(guess); let mut prev_result = BigDecimal::one(); let mut result = BigDecimal::zero(); // TODO: Prove that we don't need to arbitrarily limit iterations // and that convergence can be calculated while prev_result != result { // store current result to test for convergence prev_result = result; running_result = next_iteration(running_result); // result has clipped precision, running_result has full precision result = if running_result.digits() > max_precision { running_result.with_prec(max_precision) } else { running_result.clone() }; } return result; } /// Compute the reciprical of the number: x-1 #[inline] pub fn inverse(&self) -> BigDecimal { if self.is_zero() || self.is_one() { return self.clone(); } if self.is_negative() { return self.abs().inverse().neg(); } let guess = { let bits = self.int_val.bits() as f64; let scale = self.scale as f64; let log2_10 = 3.32192809488736234787031942948939018_f64; let magic_factor = 0.721507597259061_f64; let initial_guess = scale * log2_10 - bits; let res = magic_factor * initial_guess.exp2(); if res.is_normal() { BigDecimal::from(res) } else { // can't guess with float - just guess magnitude let scale = (bits / log2_10 + scale).round() as i64; BigDecimal::new(BigInt::from(1), -scale) } }; let max_precision = 100; let next_iteration = move |r: BigDecimal| { let two = BigDecimal::from(2); let tmp = two - self * &r; r * tmp }; // calculate first iteration let mut running_result = next_iteration(guess); let mut prev_result = BigDecimal::one(); let mut result = BigDecimal::zero(); // TODO: Prove that we don't need to arbitrarily limit iterations // and that convergence can be calculated while prev_result != result { // store current result to test for convergence prev_result = result; // calculate next iteration running_result = next_iteration(running_result).with_prec(max_precision); // 'result' has clipped precision, 'running_result' has full precision result = if running_result.digits() > max_precision { running_result.with_prec(max_precision) } else { running_result.clone() }; } return result; } /// Return true if this number has zero fractional part (is equal /// to an integer) /// #[inline] pub fn is_integer(&self) -> bool { if self.scale <= 0 { true } else { (self.int_val.clone() % ten_to_the(self.scale as u64)).is_zero() } } /// Evaluate the natural-exponential function ex /// #[inline] pub fn exp(&self) -> BigDecimal { if self.is_zero() { return BigDecimal::one(); } let precision = self.digits(); let mut term = self.clone(); let mut result = self.clone() + BigDecimal::one(); let mut prev_result = result.clone(); let mut factorial = BigInt::one(); for n in 2.. { term *= self; factorial *= n; // ∑ term=x^n/n! result += impl_division( term.int_val.clone(), &factorial, term.scale, 117 + precision, ); let trimmed_result = result.with_prec(105); if prev_result == trimmed_result { return trimmed_result.with_prec(100); } prev_result = trimmed_result; } return result.with_prec(100); } } #[derive(Debug, PartialEq)] pub enum ParseBigDecimalError { ParseDecimal(ParseFloatError), ParseInt(ParseIntError), ParseBigInt(ParseBigIntError), Empty, Other(String), } impl fmt::Display for ParseBigDecimalError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use ParseBigDecimalError::*; match *self { ParseDecimal(ref e) => e.fmt(f), ParseInt(ref e) => e.fmt(f), ParseBigInt(ref e) => e.fmt(f), Empty => "Failed to parse empty string".fmt(f), Other(ref reason) => reason[..].fmt(f), } } } impl Error for ParseBigDecimalError { fn description(&self) -> &str { "failed to parse bigint/biguint" } } impl From for ParseBigDecimalError { fn from(err: ParseFloatError) -> ParseBigDecimalError { ParseBigDecimalError::ParseDecimal(err) } } impl From for ParseBigDecimalError { fn from(err: ParseIntError) -> ParseBigDecimalError { ParseBigDecimalError::ParseInt(err) } } impl From for ParseBigDecimalError { fn from(err: ParseBigIntError) -> ParseBigDecimalError { ParseBigDecimalError::ParseBigInt(err) } } impl FromStr for BigDecimal { type Err = ParseBigDecimalError; #[inline] fn from_str(s: &str) -> Result { BigDecimal::from_str_radix(s, 10) } } #[allow(deprecated)] // trim_right_match -> trim_end_match impl Hash for BigDecimal { fn hash(&self, state: &mut H) { let mut dec_str = self.int_val.to_str_radix(10).to_string(); let scale = self.scale; let zero = self.int_val.is_zero(); if scale > 0 && !zero { let mut cnt = 0; dec_str = dec_str .trim_right_matches(|x| { cnt += 1; x == '0' && cnt <= scale }) .to_string(); } else if scale < 0 && !zero { dec_str.push_str(&"0".repeat(self.scale.abs() as usize)); } dec_str.hash(state); } } impl PartialOrd for BigDecimal { #[inline] fn partial_cmp(&self, other: &BigDecimal) -> Option { Some(self.cmp(other)) } } impl Ord for BigDecimal { /// Complete ordering implementation for BigDecimal /// /// # Example /// /// ``` /// use std::str::FromStr; /// /// let a = bigdecimal::BigDecimal::from_str("-1").unwrap(); /// let b = bigdecimal::BigDecimal::from_str("1").unwrap(); /// assert!(a < b); /// assert!(b > a); /// let c = bigdecimal::BigDecimal::from_str("1").unwrap(); /// assert!(b >= c); /// assert!(c >= b); /// let d = bigdecimal::BigDecimal::from_str("10.0").unwrap(); /// assert!(d > c); /// let e = bigdecimal::BigDecimal::from_str(".5").unwrap(); /// assert!(e < c); /// ``` #[inline] fn cmp(&self, other: &BigDecimal) -> Ordering { let scmp = self.sign().cmp(&other.sign()); if scmp != Ordering::Equal { return scmp; } match self.sign() { Sign::NoSign => Ordering::Equal, _ => { let tmp = self - other; match tmp.sign() { Sign::Plus => Ordering::Greater, Sign::Minus => Ordering::Less, Sign::NoSign => Ordering::Equal, } } } } } impl PartialEq for BigDecimal { #[inline] fn eq(&self, rhs: &BigDecimal) -> bool { // 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); 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); scaled_int_val == rhs.int_val } else { self.int_val == rhs.int_val } } } impl Default for BigDecimal { #[inline] fn default() -> BigDecimal { Zero::zero() } } impl Zero for BigDecimal { #[inline] fn zero() -> BigDecimal { BigDecimal::new(BigInt::zero(), 0) } #[inline] fn is_zero(&self) -> bool { self.int_val.is_zero() } } impl One for BigDecimal { #[inline] fn one() -> BigDecimal { BigDecimal::new(BigInt::one(), 0) } } impl Add for BigDecimal { type Output = BigDecimal; #[inline] fn add(self, rhs: BigDecimal) -> BigDecimal { 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, } } } impl<'a> Add<&'a BigDecimal> for BigDecimal { type Output = BigDecimal; #[inline] fn add(self, rhs: &'a BigDecimal) -> BigDecimal { 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.with_scale(lhs.scale) + lhs, } } } impl<'a> Add for &'a BigDecimal { type Output = BigDecimal; #[inline] fn add(self, rhs: BigDecimal) -> BigDecimal { rhs + self } } impl<'a, 'b> Add<&'b BigDecimal> for &'a BigDecimal { type Output = BigDecimal; #[inline] fn add(self, rhs: &BigDecimal) -> BigDecimal { let lhs = self; if self.scale < rhs.scale { lhs.with_scale(rhs.scale) + rhs } else if self.scale > rhs.scale { rhs.with_scale(lhs.scale) + lhs } else { BigDecimal::new(lhs.int_val.clone() + &rhs.int_val, lhs.scale) } } } impl Add for BigDecimal { type Output = BigDecimal; #[inline] fn add(self, rhs: BigInt) -> BigDecimal { let mut lhs = self; match lhs.scale.cmp(&0) { Ordering::Equal => { lhs.int_val += rhs; lhs } Ordering::Greater => { lhs.int_val += rhs * ten_to_the(lhs.scale as u64); lhs } Ordering::Less => lhs.take_and_scale(0) + rhs, } } } impl<'a> Add<&'a BigInt> for BigDecimal { type Output = BigDecimal; #[inline] fn add(self, rhs: &BigInt) -> BigDecimal { let mut lhs = self; match lhs.scale.cmp(&0) { Ordering::Equal => { lhs.int_val += rhs; lhs } Ordering::Greater => { lhs.int_val += rhs * ten_to_the(lhs.scale as u64); lhs } Ordering::Less => lhs.take_and_scale(0) + rhs, } } } impl<'a> Add for &'a BigDecimal { type Output = BigDecimal; #[inline] fn add(self, rhs: BigInt) -> BigDecimal { BigDecimal::new(rhs, 0) + self } } impl<'a, 'b> Add<&'a BigInt> for &'b BigDecimal { type Output = BigDecimal; #[inline] fn add(self, rhs: &BigInt) -> BigDecimal { self.with_scale(0) + rhs } } forward_val_assignop!(impl AddAssign for BigDecimal, add_assign); impl<'a> AddAssign<&'a BigDecimal> for BigDecimal { #[inline] fn add_assign(&mut self, rhs: &BigDecimal) { if self.scale < rhs.scale { let scaled = self.with_scale(rhs.scale); self.int_val = scaled.int_val + &rhs.int_val; self.scale = rhs.scale; } else if self.scale > rhs.scale { let scaled = rhs.with_scale(self.scale); self.int_val += scaled.int_val; } else { self.int_val += &rhs.int_val; } } } impl<'a> AddAssign for BigDecimal { #[inline] fn add_assign(&mut self, rhs: BigInt) { *self += BigDecimal::new(rhs, 0) } } impl<'a> AddAssign<&'a BigInt> for BigDecimal { #[inline] fn add_assign(&mut self, rhs: &BigInt) { /* // which one looks best? if self.scale == 0 { self.int_val += rhs; } else if self.scale > 0 { self.int_val += rhs * ten_to_the(self.scale as u64); } else { self.int_val *= ten_to_the((-self.scale) as u64); self.int_val += rhs; self.scale = 0; } */ match self.scale.cmp(&0) { Ordering::Equal => self.int_val += rhs, Ordering::Greater => self.int_val += rhs * ten_to_the(self.scale as u64), Ordering::Less => { // *self += BigDecimal::new(rhs, 0) self.int_val *= ten_to_the((-self.scale) as u64); self.int_val += rhs; self.scale = 0; } } } } impl Sub for BigDecimal { type Output = BigDecimal; #[inline] fn sub(self, rhs: BigDecimal) -> BigDecimal { let mut lhs = self; let scale = std::cmp::max(lhs.scale, rhs.scale); match lhs.scale.cmp(&rhs.scale) { Ordering::Equal => { lhs.int_val -= rhs.int_val; lhs } Ordering::Less => lhs.take_and_scale(scale) - rhs, Ordering::Greater => lhs - rhs.take_and_scale(scale), } } } impl<'a> Sub<&'a BigDecimal> for BigDecimal { type Output = BigDecimal; #[inline] fn sub(self, rhs: &BigDecimal) -> BigDecimal { let mut lhs = self; let scale = std::cmp::max(lhs.scale, rhs.scale); 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 => lhs - rhs.with_scale(scale), } } } impl<'a> Sub for &'a BigDecimal { type Output = BigDecimal; #[inline] fn sub(self, rhs: BigDecimal) -> BigDecimal { -(rhs - self) } } impl<'a, 'b> Sub<&'b BigDecimal> for &'a BigDecimal { type Output = BigDecimal; #[inline] fn sub(self, rhs: &BigDecimal) -> BigDecimal { if self.scale < rhs.scale { self.with_scale(rhs.scale) - rhs } else if self.scale > rhs.scale { let rhs = rhs.with_scale(self.scale); self - rhs } else { BigDecimal::new(&self.int_val - &rhs.int_val, self.scale) } } } impl Sub for BigDecimal { type Output = BigDecimal; #[inline] fn sub(self, rhs: BigInt) -> BigDecimal { let mut lhs = self; match lhs.scale.cmp(&0) { Ordering::Equal => { lhs.int_val -= rhs; lhs } Ordering::Greater => { lhs.int_val -= rhs * ten_to_the(lhs.scale as u64); lhs } Ordering::Less => lhs.take_and_scale(0) - rhs, } } } impl<'a> Sub<&'a BigInt> for BigDecimal { type Output = BigDecimal; #[inline] fn sub(self, rhs: &BigInt) -> BigDecimal { let mut lhs = self; match lhs.scale.cmp(&0) { Ordering::Equal => { lhs.int_val -= rhs; lhs } Ordering::Greater => { lhs.int_val -= rhs * ten_to_the(lhs.scale as u64); lhs } Ordering::Less => lhs.take_and_scale(0) - rhs, } } } impl<'a> Sub for &'a BigDecimal { type Output = BigDecimal; #[inline] fn sub(self, rhs: BigInt) -> BigDecimal { BigDecimal::new(rhs, 0) - self } } impl<'a, 'b> Sub<&'a BigInt> for &'b BigDecimal { type Output = BigDecimal; #[inline] fn sub(self, rhs: &BigInt) -> BigDecimal { self.with_scale(0) - rhs } } forward_val_assignop!(impl SubAssign for BigDecimal, sub_assign); impl<'a> SubAssign<&'a BigDecimal> for BigDecimal { #[inline] fn sub_assign(&mut self, rhs: &BigDecimal) { if self.scale < rhs.scale { let lhs = self.with_scale(rhs.scale); self.int_val = lhs.int_val - &rhs.int_val; self.scale = rhs.scale; } else if self.scale > rhs.scale { self.int_val -= rhs.with_scale(self.scale).int_val; } else { self.int_val = &self.int_val - &rhs.int_val; } } } impl<'a> SubAssign for BigDecimal { #[inline(always)] fn sub_assign(&mut self, rhs: BigInt) { *self -= BigDecimal::new(rhs, 0) } } impl<'a> SubAssign<&'a BigInt> for BigDecimal { #[inline(always)] fn sub_assign(&mut self, rhs: &BigInt) { match self.scale.cmp(&0) { Ordering::Equal => SubAssign::sub_assign(&mut self.int_val, rhs), Ordering::Greater => SubAssign::sub_assign(&mut self.int_val, rhs * ten_to_the(self.scale as u64)), Ordering::Less => { self.int_val *= ten_to_the((-self.scale) as u64); SubAssign::sub_assign(&mut self.int_val, rhs); self.scale = 0; } } } } impl Mul for BigDecimal { type Output = BigDecimal; #[inline] fn mul(mut self, rhs: BigDecimal) -> BigDecimal { self.scale += rhs.scale; self.int_val *= rhs.int_val; self } } impl<'a> Mul<&'a BigDecimal> for BigDecimal { type Output = BigDecimal; #[inline] fn mul(mut self, rhs: &'a BigDecimal) -> BigDecimal { self.scale += rhs.scale; MulAssign::mul_assign(&mut self.int_val, &rhs.int_val); self } } impl<'a> Mul for &'a BigDecimal { type Output = BigDecimal; #[inline] fn mul(self, rhs: BigDecimal) -> BigDecimal { rhs * self } } impl<'a, 'b> Mul<&'b BigDecimal> for &'a BigDecimal { type Output = BigDecimal; #[inline] fn mul(self, rhs: &BigDecimal) -> BigDecimal { let scale = self.scale + rhs.scale; BigDecimal::new(&self.int_val * &rhs.int_val, scale) } } impl Mul for BigDecimal { type Output = BigDecimal; #[inline] fn mul(mut self, rhs: BigInt) -> BigDecimal { self.int_val *= rhs; self } } impl<'a> Mul<&'a BigInt> for BigDecimal { type Output = BigDecimal; #[inline] fn mul(mut self, rhs: &BigInt) -> BigDecimal { self.int_val *= rhs; self } } impl<'a> Mul for &'a BigDecimal { type Output = BigDecimal; #[inline] fn mul(self, mut rhs: BigInt) -> BigDecimal { rhs *= &self.int_val; BigDecimal::new(rhs, self.scale) } } impl<'a, 'b> Mul<&'a BigInt> for &'b BigDecimal { type Output = BigDecimal; #[inline] fn mul(self, rhs: &BigInt) -> BigDecimal { let value = &self.int_val * rhs; BigDecimal::new(value, self.scale) } } forward_val_assignop!(impl MulAssign for BigDecimal, mul_assign); impl<'a> MulAssign<&'a BigDecimal> for BigDecimal { #[inline] fn mul_assign(&mut self, rhs: &BigDecimal) { self.scale += rhs.scale; self.int_val = &self.int_val * &rhs.int_val; } } impl_div_for_primitives!(); #[inline(always)] fn impl_division(mut num: BigInt, den: &BigInt, mut scale: i64, max_precision: u64) -> BigDecimal { // quick zero check if num.is_zero() { return BigDecimal::new(num, 0); } match (num.is_negative(), den.is_negative()) { (true, true) => return impl_division(num.neg(), &den.neg(), scale, max_precision), (true, false) => return -impl_division(num.neg(), den, scale, max_precision), (false, true) => return -impl_division(num, &den.neg(), scale, max_precision), (false, false) => (), } // shift digits until numerator is larger than denominator (set scale appropriately) while &num < den { scale += 1; num *= 10; } // first division let (mut quotient, mut remainder) = num.div_rem(den); // division complete if remainder.is_zero() { return BigDecimal { int_val: quotient, scale: scale, }; } let mut precision = count_decimal_digits("ient); // shift remainder by 1 decimal; // quotient will be 1 digit upon next division remainder *= 10; while !remainder.is_zero() && precision < max_precision { let (q, r) = remainder.div_rem(den); quotient = quotient * 10 + q; remainder = r * 10; precision += 1; scale += 1; } if !remainder.is_zero() { // round final number with remainder quotient += get_rounding_term(&remainder.div(den)); } let result = BigDecimal::new(quotient, scale); // println!(" {} / {}\n = {}\n", self, other, result); return result; } impl Div for BigDecimal { type Output = BigDecimal; #[inline] fn div(self, other: BigDecimal) -> BigDecimal { if other.is_zero() { panic!("Division by zero"); } if self.is_zero() || other.is_one() { return self; } let scale = self.scale - other.scale; if &self.int_val == &other.int_val { return BigDecimal { int_val: 1.into(), scale: scale, }; } let max_precision = 100; return impl_division(self.int_val, &other.int_val, scale, max_precision); } } impl<'a> Div<&'a BigDecimal> for BigDecimal { type Output = BigDecimal; #[inline] fn div(self, other: &'a BigDecimal) -> BigDecimal { if other.is_zero() { panic!("Division by zero"); } if self.is_zero() || other.is_one() { return self; } let scale = self.scale - other.scale; if &self.int_val == &other.int_val { return BigDecimal { int_val: 1.into(), scale: scale, }; } let max_precision = 100; return impl_division(self.int_val, &other.int_val, scale, max_precision); } } forward_ref_val_binop!(impl Div for BigDecimal, div); impl<'a, 'b> Div<&'b BigDecimal> for &'a BigDecimal { type Output = BigDecimal; #[inline] fn div(self, other: &BigDecimal) -> BigDecimal { if other.is_zero() { panic!("Division by zero"); } // TODO: Fix setting scale if self.is_zero() || other.is_one() { return self.clone(); } let scale = self.scale - other.scale; let num_int = &self.int_val; let den_int = &other.int_val; if num_int == den_int { return BigDecimal { int_val: 1.into(), scale: scale, }; } let max_precision = 100; return impl_division(num_int.clone(), &den_int, scale, max_precision); } } impl Rem for BigDecimal { type Output = BigDecimal; #[inline] fn rem(self, other: BigDecimal) -> BigDecimal { let scale = std::cmp::max(self.scale, other.scale); let num = self.take_and_scale(scale).int_val; let den = other.take_and_scale(scale).int_val; BigDecimal::new(num % den, scale) } } impl<'a> Rem<&'a BigDecimal> for BigDecimal { type Output = BigDecimal; #[inline] fn rem(self, other: &BigDecimal) -> BigDecimal { let scale = std::cmp::max(self.scale, other.scale); let num = self.take_and_scale(scale).int_val; let den = &other.int_val; let result = if scale == other.scale { num % den } else { num % (den * ten_to_the((scale - other.scale) as u64)) }; BigDecimal::new(result, scale) } } impl<'a> Rem for &'a BigDecimal { type Output = BigDecimal; #[inline] fn rem(self, other: BigDecimal) -> BigDecimal { let scale = std::cmp::max(self.scale, other.scale); let num = &self.int_val; let den = other.take_and_scale(scale).int_val; let result = if scale == self.scale { num % den } else { let scaled_num = num * ten_to_the((scale - self.scale) as u64); scaled_num % den }; BigDecimal::new(result, scale) } } impl<'a, 'b> Rem<&'b BigDecimal> for &'a BigDecimal { type Output = BigDecimal; #[inline] fn rem(self, other: &BigDecimal) -> BigDecimal { let scale = std::cmp::max(self.scale, other.scale); let num = &self.int_val; let den = &other.int_val; let result = match self.scale.cmp(&other.scale) { Ordering::Equal => num % den, Ordering::Less => { let scaled_num = num * ten_to_the((scale - self.scale) as u64); scaled_num % den } Ordering::Greater => { let scaled_den = den * ten_to_the((scale - other.scale) as u64); num % scaled_den } }; BigDecimal::new(result, scale) } } impl Neg for BigDecimal { type Output = BigDecimal; #[inline] fn neg(mut self) -> BigDecimal { self.int_val = -self.int_val; self } } impl<'a> Neg for &'a BigDecimal { type Output = BigDecimal; #[inline] fn neg(self) -> BigDecimal { -self.clone() } } impl Signed for BigDecimal { #[inline] fn abs(&self) -> BigDecimal { match self.sign() { Sign::Plus | Sign::NoSign => self.clone(), Sign::Minus => -self, } } #[inline] fn abs_sub(&self, other: &BigDecimal) -> BigDecimal { if *self <= *other { Zero::zero() } else { self - other } } #[inline] fn signum(&self) -> BigDecimal { match self.sign() { Sign::Plus => One::one(), Sign::NoSign => Zero::zero(), Sign::Minus => -Self::one(), } } #[inline] fn is_positive(&self) -> bool { self.sign() == Sign::Plus } #[inline] fn is_negative(&self) -> bool { self.sign() == Sign::Minus } } impl Sum for BigDecimal { #[inline] fn sum>(iter: I) -> BigDecimal { iter.fold(Zero::zero(), |a, b| a + b) } } impl<'a> Sum<&'a BigDecimal> for BigDecimal { #[inline] fn sum>(iter: I) -> BigDecimal { iter.fold(Zero::zero(), |a, b| a + b) } } impl fmt::Display for BigDecimal { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Aquire the absolute integer as a decimal string let mut abs_int = self.int_val.abs().to_str_radix(10); // Split the representation at the decimal point let (before, after) = if self.scale >= abs_int.len() as i64 { // First case: the integer representation falls // completely behind the decimal point let scale = self.scale as usize; let after = "0".repeat(scale - abs_int.len()) + abs_int.as_str(); ("0".to_string(), after) } else { // Second case: the integer representation falls // around, or before the decimal point let location = abs_int.len() as i64 - self.scale; if location > abs_int.len() as i64 { // Case 2.1, entirely before the decimal point // We should prepend zeros let zeros = location as usize - abs_int.len(); let abs_int = abs_int + "0".repeat(zeros as usize).as_str(); (abs_int, "".to_string()) } else { // Case 2.2, somewhere around the decimal point // Just split it in two let after = abs_int.split_off(location as usize); (abs_int, after) } }; // Alter precision after the decimal point let after = if let Some(precision) = f.precision() { let len = after.len(); if len < precision { after + "0".repeat(precision - len).as_str() } else { // TODO: Should we round? after[0..precision].to_string() } } else { after }; // Concatenate everything let complete_without_sign = if !after.is_empty() { before + "." + after.as_str() } else { before }; let non_negative = match self.int_val.sign() { Sign::Plus | Sign::NoSign => true, _ => false, }; //pad_integral does the right thing although we have a decimal f.pad_integral(non_negative, "", &complete_without_sign) } } impl fmt::Debug for BigDecimal { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "BigDecimal(\"{}\")", self) } } impl Num for BigDecimal { type FromStrRadixErr = ParseBigDecimalError; /// Creates and initializes a BigDecimal. #[inline] fn from_str_radix(s: &str, radix: u32) -> Result { if radix != 10 { return Err(ParseBigDecimalError::Other(String::from( "The radix for decimal MUST be 10", ))); } let exp_separator: &[_] = &['e', 'E']; // split slice into base and exponent parts let (base_part, exponent_value) = match s.find(exp_separator) { // exponent defaults to 0 if (e|E) not found None => (s, 0), // split and parse exponent field Some(loc) => { // slice up to `loc` and 1 after to skip the 'e' char let (base, exp) = (&s[..loc], &s[loc + 1..]); // special consideration for rust 1.0.0 which would not // parse a leading '+' let exp = match exp.chars().next() { Some('+') => &exp[1..], _ => exp, }; (base, try!(i64::from_str(exp))) } }; // TEMPORARY: Test for emptiness - remove once BigInt supports similar error if base_part == "" { return Err(ParseBigDecimalError::Empty); } // split decimal into a digit string and decimal-point offset let (digits, decimal_offset): (String, _) = match base_part.find('.') { // No dot! pass directly to BigInt None => (base_part.to_string(), 0), // decimal point found - necessary copy into new string buffer Some(loc) => { // split into leading and trailing digits let (lead, trail) = (&base_part[..loc], &base_part[loc + 1..]); // copy all leading characters into 'digits' string let mut digits = String::from(lead); // copy all trailing characters after '.' into the digits string digits.push_str(trail); (digits, trail.len() as i64) } }; let scale = decimal_offset - exponent_value; let big_int = try!(BigInt::from_str_radix(&digits, radix)); Ok(BigDecimal::new(big_int, scale)) } } impl ToPrimitive for BigDecimal { fn to_i64(&self) -> Option { match self.sign() { Sign::Minus | Sign::Plus => self.with_scale(0).int_val.to_i64(), Sign::NoSign => Some(0), } } fn to_u64(&self) -> Option { match self.sign() { Sign::Plus => self.with_scale(0).int_val.to_u64(), Sign::NoSign => Some(0), Sign::Minus => None, } } fn to_f64(&self) -> Option { self.int_val .to_f64() .map(|x| x * 10f64.powi(-self.scale as i32)) } } impl From for BigDecimal { #[inline] fn from(n: i64) -> Self { BigDecimal { int_val: BigInt::from(n), scale: 0, } } } impl From for BigDecimal { #[inline] fn from(n: u64) -> Self { BigDecimal { int_val: BigInt::from(n), scale: 0, } } } impl From<(BigInt, i64)> for BigDecimal { #[inline] fn from((int_val, scale): (BigInt, i64)) -> Self { BigDecimal { int_val: int_val, scale: scale, } } } impl From for BigDecimal { #[inline] fn from(int_val: BigInt) -> Self { BigDecimal { int_val: int_val, scale: 0, } } } macro_rules! impl_from_type { ($FromType:ty, $AsType:ty) => { impl From<$FromType> for BigDecimal { #[inline] fn from(n: $FromType) -> Self { BigDecimal::from(n as $AsType) } } }; } impl_from_type!(u8, u64); impl_from_type!(u16, u64); impl_from_type!(u32, u64); impl_from_type!(i8, i64); impl_from_type!(i16, i64); impl_from_type!(i32, i64); impl From for BigDecimal { #[inline] fn from(n: f32) -> Self { BigDecimal::from_str(&format!( "{:.PRECISION$e}", n, PRECISION = ::std::f32::DIGITS as usize )).unwrap() } } impl From for BigDecimal { #[inline] fn from(n: f64) -> Self { BigDecimal::from_str(&format!( "{:.PRECISION$e}", n, PRECISION = ::std::f64::DIGITS as usize )).unwrap() } } impl FromPrimitive for BigDecimal { #[inline] fn from_i64(n: i64) -> Option { Some(BigDecimal::from(n)) } #[inline] fn from_u64(n: u64) -> Option { Some(BigDecimal::from(n)) } #[inline] fn from_f32(n: f32) -> Option { Some(BigDecimal::from(n)) } #[inline] fn from_f64(n: f64) -> Option { Some(BigDecimal::from(n)) } } impl ToBigInt for BigDecimal { fn to_bigint(&self) -> Option { Some(self.with_scale(0).int_val) } } /// Tools to help serializing/deserializing `BigDecimal`s #[cfg(feature = "serde")] mod bigdecimal_serde { use super::BigDecimal; use serde::{de, ser}; use std::fmt; impl ser::Serialize for BigDecimal { fn serialize(&self, serializer: S) -> Result where S: ser::Serializer, { serializer.collect_str(&self) } } struct BigDecimalVisitor; impl<'de> de::Visitor<'de> for BigDecimalVisitor { type Value = BigDecimal; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "a number or formatted decimal string") } fn visit_str(self, value: &str) -> Result where E: de::Error, { use std::str::FromStr; BigDecimal::from_str(value).map_err(|err| E::custom(format!("{}", err))) } fn visit_u64(self, value: u64) -> Result where E: de::Error, { Ok(BigDecimal::from(value)) } fn visit_i64(self, value: i64) -> Result where E: de::Error, { Ok(BigDecimal::from(value)) } fn visit_f64(self, value: f64) -> Result where E: de::Error, { Ok(BigDecimal::from(value)) } } impl<'de> de::Deserialize<'de> for BigDecimal { fn deserialize(d: D) -> Result where D: de::Deserializer<'de>, { d.deserialize_any(BigDecimalVisitor) } } #[cfg(test)] extern crate serde_json; #[test] fn test_serde_serialize() { use std::str::FromStr; let vals = vec![ ("1.0", "1.0"), ("0.5", "0.5"), ("50", "50"), ("50000", "50000"), ("1e-3", "0.001"), ("1e12", "1000000000000"), ("0.25", "0.25"), ("12.34", "12.34"), ("0.15625", "0.15625"), ("0.3333333333333333", "0.3333333333333333"), ("3.141592653589793", "3.141592653589793"), ("94247.77960769380", "94247.77960769380"), ("10.99", "10.99"), ("12.0010", "12.0010"), ]; for (s, v) in vals { let expected = format!("\"{}\"", v); let value = serde_json::to_string(&BigDecimal::from_str(s).unwrap()).unwrap(); assert_eq!(expected, value); } } #[test] fn test_serde_deserialize_str() { use std::str::FromStr; let vals = vec![ ("1.0", "1.0"), ("0.5", "0.5"), ("50", "50"), ("50000", "50000"), ("1e-3", "0.001"), ("1e12", "1000000000000"), ("0.25", "0.25"), ("12.34", "12.34"), ("0.15625", "0.15625"), ("0.3333333333333333", "0.3333333333333333"), ("3.141592653589793", "3.141592653589793"), ("94247.77960769380", "94247.77960769380"), ("10.99", "10.99"), ("12.0010", "12.0010"), ]; for (s, v) in vals { let expected = BigDecimal::from_str(v).unwrap(); let value: BigDecimal = serde_json::from_str(&format!("\"{}\"", s)).unwrap(); assert_eq!(expected, value); } } #[test] fn test_serde_deserialize_int() { use traits::FromPrimitive; let vals = vec![0, 1, 81516161, -370, -8, -99999999999]; for n in vals { let expected = BigDecimal::from_i64(n).unwrap(); let value: BigDecimal = serde_json::from_str(&serde_json::to_string(&n).unwrap()).unwrap(); assert_eq!(expected, value); } } #[test] fn test_serde_deserialize_f64() { use traits::FromPrimitive; let vals = vec![ 1.0, 0.5, 0.25, 50.0, 50000., 0.001, 12.34, 5.0 * 0.03125, ::std::f64::consts::PI, ::std::f64::consts::PI * 10000.0, ::std::f64::consts::PI * 30000.0, ]; for n in vals { let expected = BigDecimal::from_f64(n).unwrap(); let value: BigDecimal = serde_json::from_str(&serde_json::to_string(&n).unwrap()).unwrap(); assert_eq!(expected, value); } } } #[cfg_attr(rustfmt, rustfmt_skip)] #[cfg(test)] mod bigdecimal_tests { use BigDecimal; use traits::{ToPrimitive, FromPrimitive}; use std::str::FromStr; use num_bigint; #[test] fn test_sum() { let vals = vec![ BigDecimal::from_f32(2.5).unwrap(), BigDecimal::from_f32(0.3).unwrap(), BigDecimal::from_f32(0.001).unwrap(), ]; let expected_sum = BigDecimal::from_f32(2.801).unwrap(); let sum = vals.iter().sum::(); assert_eq!(expected_sum, sum); } #[test] fn test_to_i64() { let vals = vec![ ("12.34", 12), ("3.14", 3), ("50", 50), ("50000", 50000), ("0.001", 0), // TODO: Is the desired behaviour to round? //("0.56", 1), ]; for (s, ans) in vals { let calculated = BigDecimal::from_str(s).unwrap().to_i64().unwrap(); assert_eq!(ans, calculated); } } #[test] fn test_to_f64() { let vals = vec![ ("12.34", 12.34), ("3.14", 3.14), ("50", 50.), ("50000", 50000.), ("0.001", 0.001), ]; for (s, ans) in vals { let diff = BigDecimal::from_str(s).unwrap().to_f64().unwrap() - ans; let diff = diff.abs(); assert!(diff < 1e-10); } } #[test] fn test_from_i8() { let vals = vec![ ("0", 0), ("1", 1), ("12", 12), ("-13", -13), ("111", 111), ("-128", ::std::i8::MIN), ("127", ::std::i8::MAX), ]; for (s, n) in vals { let expected = BigDecimal::from_str(s).unwrap(); let value = BigDecimal::from_i8(n).unwrap(); assert_eq!(expected, value); } } #[test] fn test_from_f32() { let vals = vec![ ("1.0", 1.0), ("0.5", 0.5), ("0.25", 0.25), ("50.", 50.0), ("50000", 50000.), ("0.001", 0.001), ("12.34", 12.34), ("0.15625", 5.0 * 0.03125), ("3.141593", ::std::f32::consts::PI), ("31415.93", ::std::f32::consts::PI * 10000.0), ("94247.78", ::std::f32::consts::PI * 30000.0), // ("3.14159265358979323846264338327950288f32", ::std::f32::consts::PI), ]; for (s, n) in vals { let expected = BigDecimal::from_str(s).unwrap(); let value = BigDecimal::from_f32(n).unwrap(); assert_eq!(expected, value); // assert_eq!(expected, n); } } #[test] fn test_from_f64() { let vals = vec![ ("1.0", 1.0f64), ("0.5", 0.5), ("50", 50.), ("50000", 50000.), ("1e-3", 0.001), ("0.25", 0.25), ("12.34", 12.34), // ("12.3399999999999999", 12.34), // <- Precision 16 decimal points ("0.15625", 5.0 * 0.03125), ("0.3333333333333333", 1.0 / 3.0), ("3.141592653589793", ::std::f64::consts::PI), ("31415.92653589793", ::std::f64::consts::PI * 10000.0f64), ("94247.77960769380", ::std::f64::consts::PI * 30000.0f64), ]; for (s, n) in vals { let expected = BigDecimal::from_str(s).unwrap(); let value = BigDecimal::from_f64(n).unwrap(); assert_eq!(expected, value); // assert_eq!(expected, n); } } #[test] fn test_add() { let vals = vec![ ("12.34", "1.234", "13.574"), ("12.34", "-1.234", "11.106"), ("1234e6", "1234e-6", "1234000000.001234"), ("1234e-6", "1234e6", "1234000000.001234"), ("18446744073709551616.0", "1", "18446744073709551617"), ("184467440737e3380", "0", "184467440737e3380"), ]; for &(x, y, z) in vals.iter() { let mut a = BigDecimal::from_str(x).unwrap(); let b = BigDecimal::from_str(y).unwrap(); let c = BigDecimal::from_str(z).unwrap(); assert_eq!(a.clone() + b.clone(), c); assert_eq!(a.clone() + &b, c); assert_eq!(&a + b.clone(), c); assert_eq!(&a + &b, c); a += b; assert_eq!(a, c); } } #[test] fn test_sub() { let vals = vec![ ("12.34", "1.234", "11.106"), ("12.34", "-1.234", "13.574"), ("1234e6", "1234e-6", "1233999999.998766"), ]; for &(x, y, z) in vals.iter() { let mut a = BigDecimal::from_str(x).unwrap(); let b = BigDecimal::from_str(y).unwrap(); let c = BigDecimal::from_str(z).unwrap(); assert_eq!(a.clone() - b.clone(), c); assert_eq!(a.clone() - &b, c); assert_eq!(&a - b.clone(), c); assert_eq!(&a - &b, c); a -= b; assert_eq!(a, c); } } #[test] fn test_mul() { let vals = vec![ ("2", "1", "2"), ("12.34", "1.234", "15.22756"), ("2e1", "1", "20"), ("3", ".333333", "0.999999"), ("2389472934723", "209481029831", "500549251119075878721813"), ("1e-450", "1e500", ".1e51"), ]; for &(x, y, z) in vals.iter() { let mut a = BigDecimal::from_str(x).unwrap(); let b = BigDecimal::from_str(y).unwrap(); let c = BigDecimal::from_str(z).unwrap(); assert_eq!(a.clone() * b.clone(), c); assert_eq!(a.clone() * &b, c); assert_eq!(&a * b.clone(), c); assert_eq!(&a * &b, c); a *= b; assert_eq!(a, c); } } #[test] fn test_div() { let vals = vec![ ("0", "1", "0"), ("0", "10", "0"), ("2", "1", "2"), ("2e1", "1", "2e1"), ("10", "10", "1"), ("100", "10.0", "1e1"), ("20.0", "200", ".1"), ("4", "2", "2.0"), ("15", "3", "5.0"), ("1", "2", "0.5"), ("1", "2e-2", "5e1"), ("1", "0.2", "5"), ("1.0", "0.02", "50"), ("1", "0.020", "5e1"), ("5.0", "4.00", "1.25"), ("5.0", "4.000", "1.25"), ("5", "4.000", "1.25"), ("5", "4", "125e-2"), ("100", "5", "20"), ("-50", "5", "-10"), ("200", "-5", "-40."), ("1", "3", ".3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333"), ("-2", "-3", ".6666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667"), ("-12.34", "1.233", "-10.00811030008110300081103000811030008110300081103000811030008110300081103000811030008110300081103001"), ("125348", "352.2283", "355.8714617763535752237966114591019517738921035021887792661748076460636467881768727839301952739175132"), ]; for &(x, y, z) in vals.iter() { let a = BigDecimal::from_str(x).unwrap(); let b = BigDecimal::from_str(y).unwrap(); let c = BigDecimal::from_str(z).unwrap(); assert_eq!(a.clone() / b.clone(), c); assert_eq!(a.clone() / &b, c); assert_eq!(&a / b.clone(), c); assert_eq!(&a / &b, c); // assert_eq!(q.scale, c.scale); // let mut q = a; // q /= b; // assert_eq!(q, c); } } #[test] #[should_panic(expected = "Division by zero")] fn test_division_by_zero_panics() { let x = BigDecimal::from_str("3.14").unwrap(); let _r = x / 0; } #[test] #[should_panic(expected = "Division by zero")] fn test_division_by_zero_panics_v2() { use traits::Zero; let x = BigDecimal::from_str("3.14").unwrap(); let _r = x / BigDecimal::zero(); } #[test] fn test_rem() { let vals = vec![ ("100", "5", "0"), ("2e1", "1", "0"), ("2", "1", "0"), ("1", "3", "1"), ("1", "0.5", "0"), ("1.5", "1", "0.5"), ("1", "3e-2", "1e-2"), ("10", "0.003", "0.001"), ("3", "2", "1"), ("-3", "2", "-1"), ("3", "-2", "1"), ("-3", "-2", "-1"), ("12.34", "1.233", "0.01"), ]; for &(x, y, z) in vals.iter() { let a = BigDecimal::from_str(x).unwrap(); let b = BigDecimal::from_str(y).unwrap(); let c = BigDecimal::from_str(z).unwrap(); let rem = &a % &b; assert_eq!(rem, c, "{} [&{} % &{}] == {}", rem, a, b, c); let rem = a.clone() % &b; assert_eq!(rem, c, "{} [{} % &{}] == {}", rem, a, b, c); let rem = &a % b.clone(); assert_eq!(rem, c, "{} [&{} % {}] == {}", rem, a, b, c); let rem = a.clone() % b.clone(); assert_eq!(rem, c, "{} [{} % {}] == {}", rem, a, b, c); } let vals = vec![ (("100", -2), ("50", -1), "0"), (("100", 0), ("50", -1), "0"), (("100", -2), ("30", 0), "10"), (("100", 0), ("30", -1), "10"), ]; for &((x, xs), (y, ys), z) in vals.iter() { let a = BigDecimal::from_str(x).unwrap().with_scale(xs); let b = BigDecimal::from_str(y).unwrap().with_scale(ys); let c = BigDecimal::from_str(z).unwrap(); let rem = &a % &b; assert_eq!(rem, c, "{} [{} % {}] == {}", rem, a, b, c); } } #[test] fn test_equal() { let vals = vec![ ("2", ".2e1"), ("0e1", "0.0"), ("0e0", "0.0"), ("0e-0", "0.0"), ("-0901300e-3", "-901.3"), ("-0.901300e+3", "-901.3"), ("-0e-1", "-0.0"), ("2123121e1231", "212.3121e1235"), ]; for &(x, y) in vals.iter() { let a = BigDecimal::from_str(x).unwrap(); let b = BigDecimal::from_str(y).unwrap(); assert_eq!(a, b); } } #[test] fn test_not_equal() { let vals = vec![ ("2", ".2e2"), ("1e45", "1e-900"), ("1e+900", "1e-900"), ]; for &(x, y) in vals.iter() { let a = BigDecimal::from_str(x).unwrap(); let b = BigDecimal::from_str(y).unwrap(); assert!(a != b, "{} == {}", a, b); } } #[test] fn test_hash_equal() { use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; fn hash(obj: &T) -> u64 where T: Hash { let mut hasher = DefaultHasher::new(); obj.hash(&mut hasher); hasher.finish() } let vals = vec![ ("1.1234", "1.1234000"), ("1.12340000", "1.1234"), ("001.1234", "1.1234000"), ("001.1234", "0001.1234"), ("1.1234000000", "1.1234000"), ("1.12340", "1.1234000000"), ("-0901300e-3", "-901.3"), ("-0.901300e+3", "-901.3"), ("100", "100.00"), ("100.00", "100"), ("0.00", "0"), ("0.00", "0.000"), ("-0.00", "0.000"), ("0.00", "-0.000"), ]; for &(x,y) in vals.iter() { let a = BigDecimal::from_str(x).unwrap(); let b = BigDecimal::from_str(y).unwrap(); assert_eq!(a, b); assert_eq!(hash(&a), hash(&b), "hash({}) != hash({})", a, b); } } #[test] fn test_hash_not_equal() { use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; fn hash(obj: &T) -> u64 where T: Hash { let mut hasher = DefaultHasher::new(); obj.hash(&mut hasher); hasher.finish() } let vals = vec![ ("1.1234", "1.1234001"), ("10000", "10"), ("10", "10000"), ("10.0", "100"), ]; for &(x,y) in vals.iter() { let a = BigDecimal::from_str(x).unwrap(); let b = BigDecimal::from_str(y).unwrap(); assert!(a != b, "{} == {}", a, b); assert!(hash(&a) != hash(&b), "hash({}) == hash({})", a, b); } } #[test] fn test_hash_equal_scale() { use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; fn hash(obj: &T) -> u64 where T: Hash { let mut hasher = DefaultHasher::new(); obj.hash(&mut hasher); hasher.finish() } let vals = vec![ ("1234.5678", -2, "1200", 0), ("1234.5678", -2, "1200", -2), ("1234.5678", 0, "1234.1234", 0), ("1234.5678", -3, "1200", -3), ("-1234", -2, "-1200", 0), ]; for &(x,xs,y,ys) in vals.iter() { let a = BigDecimal::from_str(x).unwrap().with_scale(xs); let b = BigDecimal::from_str(y).unwrap().with_scale(ys); assert_eq!(a, b); assert_eq!(hash(&a), hash(&b), "hash({}) != hash({})", a, b); } } #[test] fn test_with_prec() { let vals = vec![ ("7", 1, "7"), ("7", 2, "7.0"), ("895", 2, "900"), ("8934", 2, "8900"), ("8934", 1, "9000"), ("1.0001", 5, "1.0001"), ("1.0001", 4, "1"), ("1.00009", 6, "1.00009"), ("1.00009", 5, "1.0001"), ("1.00009", 4, "1.000"), ]; for &(x, p, y) in vals.iter() { let a = BigDecimal::from_str(x).unwrap().with_prec(p); assert_eq!(a, BigDecimal::from_str(y).unwrap()); } } #[test] fn test_digits() { let vals = vec![ ("0", 1), ("7", 1), ("10", 2), ("8934", 4), ]; for &(x, y) in vals.iter() { let a = BigDecimal::from_str(x).unwrap(); assert_eq!(a.digits(), y); } } #[test] fn test_get_rounding_term() { use num_bigint::BigInt; use super::get_rounding_term; let vals = vec![ ("0", 0), ("4", 0), ("5", 1), ("10", 0), ("15", 0), ("49", 0), ("50", 1), ("51", 1), ("8934", 1), ("9999", 1), ("10000", 0), ("50000", 1), ("99999", 1), ("100000", 0), ("100001", 0), ("10000000000", 0), ("9999999999999999999999999999999999999999", 1), ("10000000000000000000000000000000000000000", 0), ]; for &(x, y) in vals.iter() { let a = BigInt::from_str(x).unwrap(); assert_eq!(get_rounding_term(&a), y, "{}", x); } } #[test] fn test_abs() { let vals = vec![ ("10", "10"), ("-10", "10"), ]; for &(x, y) in vals.iter() { let a = BigDecimal::from_str(x).unwrap().abs(); let b = BigDecimal::from_str(y).unwrap(); assert!(a == b, "{} == {}", a, b); } } #[test] fn test_count_decimal_digits() { use num_bigint::BigInt; use super::count_decimal_digits; let vals = vec![ ("10", 2), ("1", 1), ("9", 1), ("999", 3), ("1000", 4), ("9900", 4), ("9999", 4), ("10000", 5), ("99999", 5), ("100000", 6), ("999999", 6), ("1000000", 7), ("9999999", 7), ("999999999999", 12), ("999999999999999999999999", 24), ("999999999999999999999999999999999999999999999999", 48), ("999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 96), ("199999911199999999999999999999999999999999999999999999999999999999999999999999999999999999999000", 96), ("999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999991", 192), ("199999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 192), ]; for &(x, y) in vals.iter() { let a = BigInt::from_str(x).unwrap(); let b = count_decimal_digits(&a); assert_eq!(b, y); } } #[test] fn test_half() { let vals = vec![ ("100", "50."), ("2", "1"), (".2", ".1"), ("42", "21"), ("3", "1.5"), ("99", "49.5"), ("3.141592653", "1.5707963265"), ("3.1415926536", "1.5707963268"), ]; for &(x, y) in vals.iter() { let a = BigDecimal::from_str(x).unwrap().half(); let b = BigDecimal::from_str(y).unwrap(); assert_eq!(a, b); assert_eq!(a.scale, b.scale); } } #[test] fn test_is_integer() { let true_vals = vec![ "100", "100.00", "1724e4", "31.47e8", "-31.47e8", "-0.0", ]; let false_vals = vec![ "100.1", "0.001", "3147e-3", "3147e-8", "-0.01", "-1e-3", ]; for s in true_vals { let d = BigDecimal::from_str(&s).unwrap(); assert!(d.is_integer()); } for s in false_vals { let d = BigDecimal::from_str(&s).unwrap(); assert!(!d.is_integer()); } } #[test] fn test_inverse() { let vals = vec![ ("100", "0.01"), ("2", "0.5"), (".2", "5"), ("3.141592653", "0.3183098862435492205742690218851870990799646487459493049686604293188738877535183744268834079171116523"), ]; for &(x, y) in vals.iter() { let a = BigDecimal::from_str(x).unwrap(); let i = a.inverse(); let b = BigDecimal::from_str(y).unwrap(); assert_eq!(i, b); assert_eq!(BigDecimal::from(1)/&a, b); assert_eq!(i.inverse(), a); // assert_eq!(a.scale, b.scale, "scale mismatch ({} != {}", a, b); } } #[test] fn test_sqrt() { let vals = vec![ ("1e-232", "1e-116"), ("1.00", "1"), ("1.001", "1.000499875062460964823258287700109753027590031219780479551442971840836093890879944856933288426795152"), ("100", "10"), ("49", "7"), (".25", ".5"), ("0.0152399025", ".12345"), ("152399025", "12345"), (".00400", "0.06324555320336758663997787088865437067439110278650433653715009705585188877278476442688496216758600590"), (".1", "0.3162277660168379331998893544432718533719555139325216826857504852792594438639238221344248108379300295"), ("2", "1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573"), ("125348", "354.0451948551201563108487193176101314241016013304294520812832530590100407318465590778759640828114535"), ("18446744073709551616.1099511", "4294967296.000000000012799992691725492477397918722952224079252026972356303360555051219312462698703293"), ("3.141592653589793115997963468544185161590576171875", "1.772453850905515992751519103139248439290428205003682302442979619028063165921408635567477284443197875"), (".000000000089793115997963468544185161590576171875", "0.000009475922962855041517561783740144225422359796851494316346796373337470068631250135521161989831460407155"), ("0.7177700109762963922745342343167413624881759290454997218753321040760896053150388903350654937434826216803814031987652326749140535150336357405672040727695124057298138872112244784753994931999476811850580200000000000000000000000000000000", "0.8472130847527653667042980517799020703921106560594525833177762276594388966885185567535692987624493813"), ("0.01234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901", "0.1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"), ("0.1108890000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000444", "0.3330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000667"), ]; for &(x, y) in vals.iter() { let a = BigDecimal::from_str(x).unwrap().sqrt().unwrap(); let b = BigDecimal::from_str(y).unwrap(); assert_eq!(a, b); } } #[test] fn test_big_sqrt() { use num_bigint::BigInt; let vals = vec![ (("2", -70), "141421356237309504880168872420969807.8569671875376948073176679737990732478462107038850387534327641573"), (("3", -170), "17320508075688772935274463415058723669428052538103806280558069794519330169088000370811.46186757248576"), (("9", -199), "9486832980505137995996680633298155601158665417975650480572514558377783315917714664032744325137900886"), (("7", -200), "26457513110645905905016157536392604257102591830824501803683344592010688232302836277603928864745436110"), (("777", -204), "2.787471972953270789531596912111625325974789615194854615319795902911796043681078997362635440358922503E+103"), (("7", -600), "2.645751311064590590501615753639260425710259183082450180368334459201068823230283627760392886474543611E+300"), (("2", -900), "1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573E+450"), (("7", -999), "8.366600265340755479781720257851874893928153692986721998111915430804187725943170098308147119649515362E+499"), (("74908163946345982392040522594123773796", -999), "2.736935584670307552030924971360722787091742391079630976117950955395149091570790266754718322365663909E+518"), (("20", -1024), "4.472135954999579392818347337462552470881236719223051448541794490821041851275609798828828816757564550E512"), (("3", 1025), "5.477225575051661134569697828008021339527446949979832542268944497324932771227227338008584361638706258E-513"), ]; for &((s, scale), e) in vals.iter() { let expected = BigDecimal::from_str(e).unwrap(); let sqrt = BigDecimal::new(BigInt::from_str(s).unwrap(), scale).sqrt().unwrap(); assert_eq!(sqrt, expected); } } #[test] fn test_cbrt() { let vals = vec![ ("0.00", "0"), ("1.00", "1"), ("1.001", "1.000333222283909495175449559955220102010284758197360454054345461242739715702641939155238095670636841"), ("10", "2.154434690031883721759293566519350495259344942192108582489235506346411106648340800185441503543243276"), ("-59283293e25", "-84006090355.84281237113712383191213626687332139035750444925827809487776780721673264524620270275301685"), ("94213372931e-127", "2.112049945275324414051072540210070583697242797173805198575907094646677475250362108901530353886613160E-39"), ]; for &(x, y) in vals.iter() { let a = BigDecimal::from_str(x).unwrap().cbrt(); let b = BigDecimal::from_str(y).unwrap(); assert_eq!(a, b); } } #[test] fn test_double() { let vals = vec![ ("1", "2"), ("1.00", "2.00"), ("1.50", "3.00"), ("5", "10"), ("5.0", "10.0"), ("5.5", "11.0"), ("5.05", "10.10"), ]; for &(x, y) in vals.iter() { let a = BigDecimal::from_str(x).unwrap().double(); let b = BigDecimal::from_str(y).unwrap(); assert_eq!(a, b); assert_eq!(a.scale, b.scale); } } #[test] fn test_square() { let vals = vec![ ("1.00", "1.00"), ("1.5", "2.25"), ("1.50", "2.2500"), ("5", "25"), ("5.0", "25.00"), ("-5.0", "25.00"), ("5.5", "30.25"), ("0.80", "0.6400"), ("0.01234", "0.0001522756"), ("3.1415926", "9.86960406437476"), ]; for &(x, y) in vals.iter() { let a = BigDecimal::from_str(x).unwrap().square(); let b = BigDecimal::from_str(y).unwrap(); assert_eq!(a, b); assert_eq!(a.scale, b.scale); } } #[test] fn test_cube() { let vals = vec![ ("1.00", "1.00"), ("1.50", "3.375000"), ("5", "125"), ("5.0", "125.000"), ("5.00", "125.000000"), ("-5", "-125"), ("-5.0", "-125.000"), ("2.01", "8.120601"), ("5.5", "166.375"), ("0.01234", "0.000001879080904"), ("3.1415926", "31.006275093569669642776"), ]; for &(x, y) in vals.iter() { let a = BigDecimal::from_str(x).unwrap().cube(); let b = BigDecimal::from_str(y).unwrap(); assert_eq!(a, b); assert_eq!(a.scale, b.scale); } } #[test] fn test_exp() { let vals = vec![ ("0", "1"), ("1", "2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427"), ("1.01", "2.745601015016916493989776316660387624073750819595962291667398087987297168243899027802501018008905180"), ("0.5", "1.648721270700128146848650787814163571653776100710148011575079311640661021194215608632776520056366643"), ("-1", "0.3678794411714423215955237701614608674458111310317678345078368016974614957448998033571472743459196437"), ("-0.01", "0.9900498337491680535739059771800365577720790812538374668838787452931477271687452950182155307793838110"), ("-10.04", "0.00004361977305405268676261569570537884674661515701779752139657120453194647205771372804663141467275928595"), //("-1000.04", "4.876927702336787390535723208392195312680380995235400234563172353460484039061383367037381490416091595E-435"), ("-20.07", "1.921806899438469499721914055500607234723811054459447828795824348465763824284589956630853464778332349E-9"), ("10", "22026.46579480671651695790064528424436635351261855678107423542635522520281857079257519912096816452590"), ("20", "485165195.4097902779691068305415405586846389889448472543536108003159779961427097401659798506527473494"), //("777.7", "5.634022488451236612534495413455282583175841288248965283178668787259870456538271615076138061788051442E+337"), ]; for &(x, y) in vals.iter() { let a = BigDecimal::from_str(x).unwrap().exp(); let b = BigDecimal::from_str(y).unwrap(); assert_eq!(a, b); } } #[test] fn test_from_str() { let vals = vec![ ("1331.107", 1331107, 3), ("1.0", 10, 1), ("2e1", 2, -1), ("0.00123", 123, 5), ("-123", -123, 0), ("-1230", -1230, 0), ("12.3", 123, 1), ("123e-1", 123, 1), ("1.23e+1", 123, 1), ("1.23E+3", 123, -1), ("1.23E-8", 123, 10), ("-1.23E-10", -123, 12), ]; for &(source, val, scale) in vals.iter() { let x = BigDecimal::from_str(source).unwrap(); assert_eq!(x.int_val.to_i32().unwrap(), val); assert_eq!(x.scale, scale); } } #[test] fn test_fmt() { let vals = vec![ // b s ( {} {:.1} {:.4} {:4.1} {:+05.1} {:<4.1} (1, 0, ( "1", "1.0", "1.0000", " 1.0", "+01.0", "1.0 " )), (1, 1, ( "0.1", "0.1", "0.1000", " 0.1", "+00.1", "0.1 " )), (1, 2, ( "0.01", "0.0", "0.0100", " 0.0", "+00.0", "0.0 " )), (1, -2, ("100", "100.0", "100.0000", "100.0", "+100.0", "100.0" )), (-1, 0, ( "-1", "-1.0", "-1.0000", "-1.0", "-01.0", "-1.0" )), (-1, 1, ( "-0.1", "-0.1", "-0.1000", "-0.1", "-00.1", "-0.1" )), (-1, 2, ( "-0.01", "-0.0", "-0.0100", "-0.0", "-00.0", "-0.0" )), ]; for (i, scale, results) in vals { let x = BigDecimal::new(num_bigint::BigInt::from(i), scale); assert_eq!(format!("{}", x), results.0); assert_eq!(format!("{:.1}", x), results.1); assert_eq!(format!("{:.4}", x), results.2); assert_eq!(format!("{:4.1}", x), results.3); assert_eq!(format!("{:+05.1}", x), results.4); assert_eq!(format!("{:<4.1}", x), results.5); } } #[test] fn test_debug() { let vals = vec![ ("BigDecimal(\"123.456\")", "123.456"), ("BigDecimal(\"123.400\")", "123.400"), ("BigDecimal(\"1.20\")", "01.20"), // ("BigDecimal(\"1.2E3\")", "01.2E3"), <- ambiguous precision ("BigDecimal(\"1200\")", "01.2E3"), ]; for (expected, source) in vals { let var = BigDecimal::from_str(source).unwrap(); assert_eq!(format!("{:?}", var), expected); } } #[test] fn test_signed() { use traits::{One, Signed, Zero}; assert!(!BigDecimal::zero().is_positive()); assert!(!BigDecimal::one().is_negative()); assert!(BigDecimal::one().is_positive()); assert!((-BigDecimal::one()).is_negative()); assert!((-BigDecimal::one()).abs().is_positive()); } #[test] #[should_panic(expected = "InvalidDigit")] fn test_bad_string_nan() { BigDecimal::from_str("hello").unwrap(); } #[test] #[should_panic(expected = "Empty")] fn test_bad_string_empty() { BigDecimal::from_str("").unwrap(); } #[test] #[should_panic(expected = "InvalidDigit")] fn test_bad_string_invalid_char() { BigDecimal::from_str("12z3.12").unwrap(); } #[test] #[should_panic(expected = "InvalidDigit")] fn test_bad_string_nan_exponent() { BigDecimal::from_str("123.123eg").unwrap(); } #[test] #[should_panic(expected = "Empty")] fn test_bad_string_empty_exponent() { BigDecimal::from_str("123.123E").unwrap(); } #[test] #[should_panic(expected = "InvalidDigit")] fn test_bad_string_multiple_decimal_points() { BigDecimal::from_str("123.12.45").unwrap(); } #[test] #[should_panic(expected = "Empty")] fn test_bad_string_only_decimal() { BigDecimal::from_str(".").unwrap(); } #[test] #[should_panic(expected = "Empty")] fn test_bad_string_only_decimal_and_exponent() { BigDecimal::from_str(".e4").unwrap(); } } bigdecimal-0.1.0/src/macros.rs010066400017500001750000000161251345412424200144420ustar0000000000000000// \file src/macros.rs //! macros for /* macro_rules! forward_val_val_binop { (impl $imp:ident for $res:ty, $method:ident) => { impl $imp<$res> for $res { type Output = $res; #[inline] fn $method(self, other: $res) -> $res { // forward to val-ref $imp::$method(self, &other) } } }; } */ macro_rules! forward_ref_val_binop { (impl $imp:ident for $res:ty, $method:ident) => { impl<'a> $imp<$res> for &'a $res { type Output = $res; #[inline] fn $method(self, other: $res) -> $res { // forward to ref-ref $imp::$method(self, &other) } } }; } /* macro_rules! forward_val_ref_binop { (impl $imp:ident for $res:ty, $method:ident) => { impl<'a> $imp<&'a $res> for $res { type Output = $res; #[inline] fn $method(self, other: &$res) -> $res { // forward to ref-ref $imp::$method(&self, other) } } }; } // Forward everything to ref-ref, when reusing storage is not helpful macro_rules! forward_all_binop_to_ref_ref { (impl $imp:ident for $res:ty, $method:ident) => { forward_val_val_binop!(impl $imp for $res, $method); forward_val_ref_binop!(impl $imp for $res, $method); forward_ref_val_binop!(impl $imp for $res, $method); }; } */ macro_rules! forward_val_assignop { (impl $imp:ident for $res:ty, $method:ident) => { impl $imp<$res> for $res { #[inline] fn $method(&mut self, other: $res) { // forward to mutref-ref $imp::$method(self, &other) } } }; } macro_rules! impl_div_for_uint_primitive { // (impl $imp:ident for $res:ty, $method:ident) => { ($res:ty) => { impl<'a> Div<$res> for &'a BigDecimal { type Output = BigDecimal; #[inline] fn div(self, den: $res) -> Self::Output { if den == 1 { self.clone() } else if den == 2 { self.half() } else { self / BigDecimal::from(den) } } } impl<'a> Div<&'a BigDecimal> for $res { type Output = BigDecimal; #[inline(always)] fn div(self, den: &'a BigDecimal) -> Self::Output { BigDecimal::from(self) / den } } impl Div for $res { type Output = BigDecimal; #[inline(always)] fn div(self, den: BigDecimal) -> Self::Output { BigDecimal::from(self) / den } } }; } macro_rules! impl_div_for_int_primitive { // (impl $imp:ident for $res:ty, $method:ident) => { ($res:ty) => { impl<'a> Div<$res> for BigDecimal { type Output = BigDecimal; #[inline(always)] fn div(self, den: $res) -> Self::Output { if den < 0 { -Div::div(self, -den) } else if den == 1 { self } else if den == 2 { self.half() } else { self / BigDecimal::from(den) } } } impl<'a> Div<$res> for &'a BigDecimal { type Output = BigDecimal; #[inline(always)] fn div(self, den: $res) -> Self::Output { if den < 0 { -Div::div(self, -den) } else if den == 1 { self.clone() } else if den == 2 { self.half() } else { self / BigDecimal::from(den) } } } impl<'a> Div<&'a BigDecimal> for $res { type Output = BigDecimal; #[inline(always)] fn div(self, den: &'a BigDecimal) -> Self::Output { match (self < 0, den.is_negative()) { (true, true) => -self / -den, (true, false) => (-self / den).neg(), (false, true) => (-self / den.abs()), (false, false) => BigDecimal::from(self) / den, } } } impl Div for $res { type Output = BigDecimal; #[inline(always)] fn div(self, den: BigDecimal) -> Self::Output { match (self < 0, den.is_negative()) { (true, true) => -self / -den, (true, false) => (-self / den).neg(), (false, true) => (-self / den.abs()), (false, false) => BigDecimal::from(self) / den, } } } }; } macro_rules! impl_div_for_float_primitive { // (impl $imp:ident for $res:ty, $method:ident) => { ($res:ty) => { impl<'a> Div<$res> for &'a BigDecimal { type Output = BigDecimal; #[inline] fn div(self, den: $res) -> Self::Output { if den.is_nan() { BigDecimal::zero() } else if den == 1.0 { self.clone() } else if den == 0.5 { self.double() } else if den == 2.0 { self.half() } else if den == -1.0 { -self } else if den < 0.0 && self.is_positive() { -(self / -den) } else { self / BigDecimal::from(den) } } } impl<'a> Div<&'a BigDecimal> for $res { type Output = BigDecimal; #[inline(always)] fn div(self, den: &'a BigDecimal) -> Self::Output { if self.is_nan() { BigDecimal::zero() } else { BigDecimal::from(self) / den } } } impl Div for $res { type Output = BigDecimal; #[inline(always)] fn div(self, den: BigDecimal) -> Self::Output { if self.is_nan() { BigDecimal::zero() } else { BigDecimal::from(self) / den } } } }; } macro_rules! forward_primitive_types { (floats => $macro_name:ident) => { $macro_name!(f32); $macro_name!(f64); }; (ints => $macro_name:ident) => { $macro_name!(i8); $macro_name!(i16); $macro_name!(i32); $macro_name!(i64); }; (uints => $macro_name:ident) => { $macro_name!(u8); $macro_name!(u16); $macro_name!(u32); $macro_name!(u64); }; } macro_rules! impl_div_for_primitives { () => { forward_primitive_types!(floats => impl_div_for_float_primitive); forward_primitive_types!(ints => impl_div_for_int_primitive); forward_primitive_types!(uints => impl_div_for_uint_primitive); }; } bigdecimal-0.1.0/.cargo_vcs_info.json0000644000000001120000000000000131430ustar00{ "git": { "sha1": "8405996b00dc75e59cc6b27da3365a73c6c59750" } }