bigdecimal-0.4.10/.cargo_vcs_info.json0000644000000001360000000000100131760ustar { "git": { "sha1": "ea0803e5dbaea8dd87d7b5d53d3fd366310a6f4f" }, "path_in_vcs": "" }bigdecimal-0.4.10/Cargo.lock0000644000000076340000000000100111630ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bigdecimal" version = "0.4.10" dependencies = [ "autocfg", "libm", "num-bigint", "num-integer", "num-traits", "paste", "serde", "serde_json", "serde_test", "siphasher", ] [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "libm" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "num-bigint" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-integer" version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ "num-traits", ] [[package]] name = "num-traits" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "proc-macro2" version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "serde" version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "serde_test" version = "1.0.175" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29baf0f77ca9ad9c6ed46e1b408b5e0f30b5184bcd66884e7f6d36bd7a65a8a4" dependencies = [ "serde", ] [[package]] name = "siphasher" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "syn" version = "2.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e2415488199887523e74fd9a5f7be804dfd42d868ae0eca382e3917094d210e" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" bigdecimal-0.4.10/Cargo.toml0000644000000042220000000000100111740ustar # 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 are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "bigdecimal" version = "0.4.10" authors = ["Andrew Kubera"] build = "build.rs" include = [ "LICENSE-APACHE", "LICENSE-MIT", "README.md", "build.rs", "src/**/*.rs", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Arbitrary precision decimal numbers" homepage = "https://github.com/akubera/bigdecimal-rs" documentation = "https://docs.rs/bigdecimal" readme = "README.md" keywords = [ "numerics", "bignum", "decimal", "arbitrary-precision", ] categories = [ "mathematics", "science", "no-std", ] license = "MIT/Apache-2.0" repository = "https://github.com/akubera/bigdecimal-rs" [features] default = ["std"] serde-json = [ "serde/derive", "serde_json", ] std = [ "num-bigint/std", "num-integer/std", "num-traits/std", ] string-only = [] [lib] name = "bigdecimal" path = "src/lib.rs" bench = false [dependencies.libm] version = "0.2.6" [dependencies.num-bigint] version = "0.4" default-features = false [dependencies.num-integer] version = "0.1" default-features = false [dependencies.num-traits] version = "0.2" default-features = false [dependencies.serde] version = "1.0" optional = true default-features = false [dependencies.serde_json] version = "1.0" features = [ "alloc", "arbitrary_precision", ] optional = true default-features = false [dev-dependencies.paste] version = "1" [dev-dependencies.serde_test] version = "<1.0.176" [dev-dependencies.siphasher] version = "0.3.10" default-features = false [build-dependencies.autocfg] version = "1" [lints.rust.unexpected_cfgs] level = "allow" priority = 0 check-cfg = ["cfg(no_track_caller)"] bigdecimal-0.4.10/Cargo.toml.orig000064400000000000000000000036531046102023000146640ustar 00000000000000[package] name = "bigdecimal" version = "0.4.10" authors = ["Andrew Kubera"] description = "Arbitrary precision decimal numbers" documentation = "https://docs.rs/bigdecimal" homepage = "https://github.com/akubera/bigdecimal-rs" repository = "https://github.com/akubera/bigdecimal-rs" keywords = [ "numerics", "bignum", "decimal", "arbitrary-precision", ] categories = [ "mathematics", "science", "no-std" ] license = "MIT/Apache-2.0" autobenches = false edition = "2015" include = [ "LICENSE-APACHE", "LICENSE-MIT", "README.md", "build.rs", "src/**/*.rs", ] [lib] bench = false [dependencies] libm = "0.2.6" num-bigint = { version = "0.4", default-features = false } num-integer = { version = "0.1", default-features = false } num-traits = { version = "0.2", default-features = false } serde = { version = "1.0", optional = true, default-features = false } # Allow direct parsing of JSON floats, for full arbitrary precision serde_json = { version = "1.0", optional = true, default-features = false, features = ["alloc", "arbitrary_precision"]} [dev-dependencies] paste = "1" serde_test = "<1.0.176" siphasher = { version = "0.3.10", default-features = false } # The following dev-dependencies are only required for benchmarking # (use the `benchmark-bigdecimal` script to uncomment these and run benchmarks) # BENCH: criterion = { version = "0.4", features = [ "html_reports" ] } # BENCH: oorandom = { version = "11.1.3" } # BENCH: lazy_static = { version = "1" } # Only required for property testing - incompatible with older versions of rust # PROPERTY-TESTS: proptest = "1" [build-dependencies] autocfg = "1" [features] default = ["std"] serde-json = ["serde/derive", "serde_json"] string-only = [] std = ["num-bigint/std", "num-integer/std", "num-traits/std"] # BENCH: [[bench]] # BENCH: name = "arithmetic" # BENCH: harness = false [lints.rust] unexpected_cfgs = { level = "allow", check-cfg = ['cfg(no_track_caller)'] } bigdecimal-0.4.10/LICENSE-APACHE000064400000000000000000000251441046102023000137200ustar 00000000000000 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 2023 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.4.10/LICENSE-MIT000064400000000000000000000020631046102023000134230ustar 00000000000000Copyright (c) 2023 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.4.10/README.md000064400000000000000000000256001046102023000132500ustar 00000000000000# bigdecimal-rs [![crate](https://img.shields.io/crates/v/bigdecimal.svg)](https://crates.io/crates/bigdecimal) [![Documentation](https://docs.rs/bigdecimal/badge.svg)](https://docs.rs/bigdecimal) [![minimum rustc 1.43](https://img.shields.io/badge/rustc-1.43+-red.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html) [![codecov](https://codecov.io/gh/akubera/bigdecimal-rs/branch/feature/circleci/graph/badge.svg?token=YTwyxrxJ3S)](https://codecov.io/gh/akubera/bigdecimal-rs) [![build status - master](https://gitlab.com/akubera/bigdecimal-rs/badges/master/pipeline.svg?ignore_skipped=true&key_text=status:master&key_width=96)](https://gitlab.com/akubera/bigdecimal-rs/-/pipelines) [![build status - trunk](https://gitlab.com/akubera/bigdecimal-rs/badges/trunk/pipeline.svg?ignore_skipped=true&key_text=status:trunk&key_width=96)](https://gitlab.com/akubera/bigdecimal-rs/-/pipelines) Arbitrary-precision decimal numbers implemented in pure Rust. ## Community Join the conversation on Zulip: https://bigdecimal-rs.zulipchat.com Please share important stuff like use-cases, issues, benchmarks, and naming-convention preferences. This project is currently being re-written, so if performance or flexibility is lacking, check again soon and it may be fixed. ## Usage Add bigdecimal as a dependency to your `Cargo.toml` file: ```toml [dependencies] bigdecimal = "0.4" ``` Import and use the `BigDecimal` struct to solve your problems: ```rust use bigdecimal::BigDecimal; fn main() { let two = BigDecimal::from(2); println!("sqrt(2) = {}", two.sqrt().unwrap()); } ``` this code will print ``` sqrt(2) = 1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573 ``` ### Serialization If you are passing BigDecimals between systems, be sure to use a serialization format which explicitly supports decimal numbers and does not require transformations to floating-point binary numbers, or there will be information loss. Text formats like JSON should work ok as long as the receiver will also parse numbers as decimals so complete precision is kept accurate. Typically JSON-parsing implementations do not do this by default, and need special configuration. Binary formats like msgpack may expect/require representing numbers as 64-bit IEEE-754 floating-point, and will likely lose precision by default unless you explicitly format the decimal as a string, bytes, or some custom structure. By default, this will serialize the decimal _as a string_. To use `serde_json` with this crate it is recommended to enable the `serde-json` feature (note `serde -dash- json` , not `serde_json`) and that will add support for serializing & deserializing values to BigDecimal. By default it will parse numbers and strings using normal conventions. If you want to serialize to a number, rather than a string, you can use the `serde(with)` annotation as shown in the following example: ```toml [dependencies] bigdecimal = { version = "0.4", features = [ "serde-json" ] } # '-' not '_' ``` ```rust use bigdecimal::BigDecimal; use serde::*; use serde_json; #[derive(Debug,Serialize,Deserialize)] struct MyStruct { name: String, // this will be written to json as string value: BigDecimal, // this will be written to json as number #[serde(with = "bigdecimal::serde::json_num")] number: BigDecimal, } fn main() { let json_src = r#" { "name": "foo", "value": 1234567e-3, "number": 3.14159 } "#; let my_struct: MyStruct = serde_json::from_str(&json_src).unwrap(); dbg!(my_struct); // MyStruct { name: "foo", value: BigDecimal("1234.567"), BigDecimal("3.1459") } println!("{}", serde_json::to_string(&my_struct)); // {"name":"foo","value":"1234.567","number":3.1459} } ``` If you have suggestions for improving serialization, please bring them to the Zulip chat. ### Formatting Until a more sophisticated formatting solution is implemented (currently work in progress), we are restricted to Rust's `fmt::Display` formatting options. This is how this crate formats BigDecimals: - `{}` - Default Display - Format as "human readable" number - "Small" fractional numbers (close to zero) are printed in scientific notation - Number is considered "small" by number of leading zeros exceeding a threshold - Configurable by the compile-time environment variable: `RUST_BIGDECIMAL_FMT_EXPONENTIAL_LOWER_THRESHOLD` - Default 5 - Example: `1.23e-3` will print as `0.00123` but `1.23e-10` will be `1.23E-10` - Trailing zeros will be added to "small" integers, avoiding scientific notation - May appear to have more precision than they do - Example: decimal `1e1` would be rendered as `10` - The threshold for "small" is configured by compile-time environment variable: `RUST_BIGDECIMAL_FMT_EXPONENTIAL_UPPER_THRESHOLD` - Default 15 - `1e15` => `1000000000000000` - Large integers (e.g. `1e50000000`) will print in scientific notation, not a 1 followed by fifty million zeros - All other numbers are printed in standard decimal notation - `{:.}` - Display with precision - Format number with exactly `PREC` digits after the decimal place - Numbers with fractional components will be rounded at precision point, or have zeros padded to precision point - Integers will have zeros padded to the precision point - To prevent unreasonably sized output, a threshold limits the number of padded zeros - Greater than the default case, since specific precision was requested - Configurable by the compile-time environment variable: `RUST_BIGDECIMAL_FMT_MAX_INTEGER_PADDING` - Default 1000 - If digits exceed this threshold, they are printed without decimal-point, suffixed with scale of the big decimal - `{:e}` / `{:E}` - Exponential format - Formats in scientific notation with either `e` or `E` as exponent delimiter - Precision is kept exactly - `{:.e}` - formats in scientific notation, keeping number - Number is rounded / zero padded until - `{:?}` - Debug - Shows internal representation of BigDecimal - `123.456` => `BigDecimal(sign=Plus, scale=3, digits=[123456])` - `-1e10000` => `BigDecimal(sign=Minus, scale=-10000, digits=[1])` - `{:#?}` - Alternate Debug (used by `dbg!()`) - Shows simple int+exponent string representation of BigDecimal - `123.456` => `BigDecimal("123456e-3")` - `-1e10000` => `BigDecimal("-1e10000")` There is a [formatting-example](examples/formatting-examples.rs) script in the `examples/` directory that demonstrates the formatting options and comparison with Rust's standard floating point Display. It is recommended you include unit tests in your code to guarantee that future versions of BigDecimal continue to format numbers the way you expect. The rules above are not likely to change, but they are probably the only part of this library that are relatively subjective, and could change behavior without indication from the compiler. Also, check for changes to the configuration environment variables, those may change name until 1.0. ### Compile-Time Configuration You can set a few default parameters at _compile-time_ via environment variables: | Environment Variable | Default | |----------------------------------------------------|------------| | `RUST_BIGDECIMAL_DEFAULT_PRECISION` | 100 | | `RUST_BIGDECIMAL_DEFAULT_ROUNDING_MODE` | `HalfEven` | | `RUST_BIGDECIMAL_FMT_EXPONENTIAL_LOWER_THRESHOLD` | 5 | | `RUST_BIGDECIMAL_FMT_EXPONENTIAL_UPPER_THRESHOLD` | 15 | | `RUST_BIGDECIMAL_FMT_MAX_INTEGER_PADDING` | 1000 | These allow setting the default [Context] fields globally without incurring a runtime lookup, or having to pass Context parameters through all calculations. (If you want runtime control over these fields, you will have to pass Contexts to your functions.) Examine [build.rs] for how those are converted to constants in the code (if interested). [Context]: https://docs.rs/bigdecimal/latest/bigdecimal/struct.Context.html [build.rs]: ./build.rs #### Default precision Default precision may be set at compile time with the environment variable `RUST_BIGDECIMAL_DEFAULT_PRECISION`. The default value of this variable is 100. This will be used as maximum precision for operations which may produce infinite digits (inverse, sqrt, ...). Note that other operations, such as multiplication, will preserve all digits; so multiplying two 70 digit numbers will result in one 140 digit number. The user will have to manually trim the number of digits after calculations to reasonable amounts using the `x.with_prec(30)` method. A new set of methods with explicit precision and rounding modes is being worked on, but even after those are introduced the default precision will have to be used as the implicit value. #### Rounding mode The default Context uses this value for rounding. Valid values are the variants of the [RoundingMode] enum. Defaults to `HalfEven`. [RoundingMode]: https://docs.rs/bigdecimal/latest/bigdecimal/rounding/enum.RoundingMode.html #### Exponential Format Threshold The maximum number of leading zeros after the decimal place before the formatter uses exponential form (i.e. scientific notation). There is currently no mechanism to change this during runtime. If you know of a good solution for number formatting in Rust, please let me know! #### Example Compile time configuration Given the program: ```rust fn main() { let n = BigDecimal::from(700); println!("1/{n} = {}", n.inverse()); } ``` Compiling with different environment variables prints different results ``` $ export BIG_DECIMAL_DEFAULT_PRECISION=8 $ cargo run 1/700 = 0.0014285714 $ export RUST_BIGDECIMAL_DEFAULT_PRECISION=5 $ cargo run 1/700 = 0.0014286 $ export RUST_BIGDECIMAL_DEFAULT_ROUNDING_MODE=Down $ cargo run 1/700 = 0.0014285 $ export RUST_BIGDECIMAL_EXPONENTIAL_FORMAT_THRESHOLD=2 $ cargo run 1/700 = 1.4285E-3 ``` > [!NOTE] > > These are **compile time** environment variables, and the BigDecimal > library is not configurable at **runtime** via environment variable, or > any kind of global variables, by default. > > This is for flexibility and performance. ## About This repository contains code originally meant for a bigdecimal module in the popular [num](https://crates.io/crates/num) crate, but was not merged due to uncertainty of what the best design for such a crate should be. ## License This code is dual-licensed under the permissive [MIT](https://opensource.org/licenses/MIT) & [Apache 2.0](https://opensource.org/licenses/Apache-2.0) licenses. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. bigdecimal-0.4.10/build.rs000064400000000000000000000112121046102023000134300ustar 00000000000000use std::env; use std::path::{Path, PathBuf}; // configuration defaults const DEFAULT_PRECISION: &str = "100"; const DEFAULT_ROUNDING_MODE: &str = "HalfEven"; const FMT_EXPONENTIAL_LOWER_THRESHOLD: &str = "5"; const FMT_EXPONENTIAL_UPPER_THRESHOLD: &str = "15"; const FMT_MAX_INTEGER_PADDING: &str = "1000"; const SERDE_MAX_SCALE: &str = "150000"; fn main() { let ac = autocfg::new(); // Fn() -> impl Trait ac.emit_rustc_version(1, 75); // abs_diff ac.emit_rustc_version(1, 60); // slice::fill ac.emit_rustc_version(1, 50); // Option::zip ac.emit_rustc_version(1, 46); // int::unsigned_abs (1.51) ac.emit_expression_cfg("0i64.unsigned_abs()", "has_unsigned_abs"); // Remove this comment if enabled proptests // ::PROPERTY-TESTS:: autocfg::emit("property_tests"); let outdir: PathBuf = std::env::var_os("OUT_DIR").unwrap().into(); write_default_precision_file(&outdir); write_default_rounding_mode(&outdir); write_exponential_format_threshold_file(&outdir); write_max_serde_parsing_scale_limit(&outdir); } /// Loads the environment variable string or default macro_rules! load_env { ($env:ident, $name:literal, $default:ident) => {{ println!("cargo:rerun-if-env-changed={}", $name); $env::var($name).unwrap_or_else(|_| $default.to_owned()) }}; } /// Create default_precision.rs, containing definition of constant DEFAULT_PRECISION loaded in src/lib.rs fn write_default_precision_file(outdir: &Path) { let env_var = load_env!(env, "RUST_BIGDECIMAL_DEFAULT_PRECISION", DEFAULT_PRECISION); let rust_file_path = outdir.join("default_precision.rs"); let default_prec: u32 = env_var .parse::() .expect("$RUST_BIGDECIMAL_DEFAULT_PRECISION must be an integer > 0") .into(); let rust_file_contents = format!("const DEFAULT_PRECISION: u64 = {};", default_prec); std::fs::write(rust_file_path, rust_file_contents).unwrap(); } /// Create default_rounding_mode.rs, using value of RUST_BIGDECIMAL_DEFAULT_ROUNDING_MODE environment variable fn write_default_rounding_mode(outdir: &Path) { let rounding_mode_name = load_env!(env, "RUST_BIGDECIMAL_DEFAULT_ROUNDING_MODE", DEFAULT_ROUNDING_MODE); let rust_file_path = outdir.join("default_rounding_mode.rs"); let rust_file_contents = format!("const DEFAULT_ROUNDING_MODE: RoundingMode = RoundingMode::{};", rounding_mode_name); std::fs::write(rust_file_path, rust_file_contents).unwrap(); } /// Create write_default_rounding_mode.rs, containing definition of constant EXPONENTIAL_FORMAT_THRESHOLD loaded in src/impl_fmt.rs fn write_exponential_format_threshold_file(outdir: &Path) { let low_value = load_env!(env, "RUST_BIGDECIMAL_FMT_EXPONENTIAL_LOWER_THRESHOLD", FMT_EXPONENTIAL_LOWER_THRESHOLD); let high_value = load_env!(env, "RUST_BIGDECIMAL_FMT_EXPONENTIAL_UPPER_THRESHOLD", FMT_EXPONENTIAL_UPPER_THRESHOLD); let max_padding = load_env!(env, "RUST_BIGDECIMAL_FMT_MAX_INTEGER_PADDING", FMT_MAX_INTEGER_PADDING); let low_value: u32 = low_value .parse::() .expect("$RUST_BIGDECIMAL_FMT_EXPONENTIAL_LOWER_THRESHOLD must be an integer > 0") .into(); let high_value: u32 = high_value .parse::() .expect("$RUST_BIGDECIMAL_FMT_EXPONENTIAL_UPPER_THRESHOLD must be valid u32"); let max_padding: u32 = max_padding .parse::() .expect("$RUST_BIGDECIMAL_FMT_MAX_INTEGER_PADDING must be valid u32"); let rust_file_path = outdir.join("exponential_format_threshold.rs"); let rust_file_contents = [ format!("const EXPONENTIAL_FORMAT_LEADING_ZERO_THRESHOLD: usize = {};", low_value), format!("const EXPONENTIAL_FORMAT_TRAILING_ZERO_THRESHOLD: usize = {};", high_value), format!("const FMT_MAX_INTEGER_PADDING: usize = {};", max_padding), ]; std::fs::write(rust_file_path, rust_file_contents.join("\n")).unwrap(); } /// Create write_default_rounding_mode.rs, containing definition of constant EXPONENTIAL_FORMAT_THRESHOLD loaded in src/impl_fmt.rs fn write_max_serde_parsing_scale_limit(outdir: &Path) { let scale_limit = load_env!(env, "RUST_BIGDECIMAL_SERDE_SCALE_LIMIT", SERDE_MAX_SCALE); let scale_limit: u32 = scale_limit .parse::() .or_else(|e| if scale_limit.to_lowercase() == "none" { Ok(0) } else { Err(e) }) .expect("$RUST_BIGDECIMAL_SERDE_SCALE_LIMIT must be an integer"); let rust_file_path = outdir.join("serde_scale_limit.rs"); let rust_file_contents = [ format!("const SERDE_SCALE_LIMIT: i64 = {};", scale_limit), ]; std::fs::write(rust_file_path, rust_file_contents.join("\n")).unwrap(); } bigdecimal-0.4.10/src/arithmetic/addition.rs000064400000000000000000000071161046102023000170540ustar 00000000000000//! addition routines //! use crate::*; pub(crate) fn add_bigdecimals( mut a: BigDecimal, mut b: BigDecimal, ) -> BigDecimal { if b.is_zero() { a.extend_scale_to(b.scale); return a; } if a.is_zero() { b.extend_scale_to(a.scale); return b; } let (a, b) = match a.scale.cmp(&b.scale) { Ordering::Equal => (a, b), Ordering::Less => (a.take_and_scale(b.scale), b), Ordering::Greater => (b.take_and_scale(a.scale), a), }; add_aligned_bigdecimals(a, b) } fn add_aligned_bigdecimals( mut a: BigDecimal, mut b: BigDecimal, ) -> BigDecimal { debug_assert_eq!(a.scale, b.scale); if a.int_val.bits() >= b.int_val.bits() { a.int_val += b.int_val; a } else { b.int_val += a.int_val; b } } pub(crate) fn add_bigdecimal_refs<'a, 'b, Lhs, Rhs>( lhs: Lhs, rhs: Rhs, ctx: Option<&Context>, ) -> BigDecimal where Rhs: Into>, Lhs: Into>, { use stdlib::cmp::Ordering::*; let lhs = lhs.into(); let rhs = rhs.into(); if rhs.is_zero() { let scale_diff = rhs.scale.saturating_sub(lhs.scale).max(0).min(15); return lhs.to_owned_with_scale(lhs.scale + scale_diff); } if lhs.is_zero() { let scale_diff = lhs.scale.saturating_sub(rhs.scale).max(0).min(15); return rhs.to_owned_with_scale(rhs.scale + scale_diff); } match lhs.scale.cmp(&rhs.scale) { Equal => { add_aligned_bigdecimal_ref_ref(lhs, rhs) } Greater => { add_unaligned_bigdecimal_ref_ref(lhs, rhs, ctx) } Less => { add_unaligned_bigdecimal_ref_ref(rhs, lhs, ctx) } } } pub(crate) fn addassign_bigdecimals( lhs: &mut BigDecimal, rhs: BigDecimal, ) { if rhs.is_zero() { return; } if lhs.is_zero() { *lhs = rhs; return; } lhs.add_assign(rhs.to_ref()); } pub(crate) fn addassign_bigdecimal_ref<'a, T: Into>>( lhs: &mut BigDecimal, rhs: T, ) { // TODO: Replace to_owned() with efficient addition algorithm let rhs = rhs.into().to_owned(); match lhs.scale.cmp(&rhs.scale) { Ordering::Less => { let scaled = lhs.with_scale(rhs.scale); lhs.int_val = scaled.int_val + &rhs.int_val; lhs.scale = rhs.scale; } Ordering::Greater => { let scaled = rhs.with_scale(lhs.scale); lhs.int_val += scaled.int_val; } Ordering::Equal => { lhs.int_val += &rhs.int_val; } } } /// Add BigDecimal references which have the same scale (integer addition) fn add_aligned_bigdecimal_ref_ref( lhs: BigDecimalRef, rhs: BigDecimalRef ) -> BigDecimal { debug_assert!(!lhs.is_zero() && !rhs.is_zero()); debug_assert_eq!(lhs.scale, rhs.scale); if lhs.digits.bits() >= rhs.digits.bits() { lhs.to_owned() + rhs } else { rhs.to_owned() + lhs } } fn add_unaligned_bigdecimal_ref_ref( lhs: BigDecimalRef, rhs: BigDecimalRef, _ctx: Option<&Context>, ) -> BigDecimal { debug_assert!(!lhs.is_zero() && !rhs.is_zero()); debug_assert!(lhs.scale >= rhs.scale); let scale_diff = (lhs.scale - rhs.scale) as u64; let shifted_rhs_digits = rhs.digits * ten_to_the_uint(scale_diff); let shifted_rhs_int = BigInt::from_biguint(rhs.sign, shifted_rhs_digits); let shifted_rhs = BigDecimal::new(shifted_rhs_int, lhs.scale); shifted_rhs + lhs } #[cfg(test)] mod test { use super::*; include!("addition.tests.rs"); } bigdecimal-0.4.10/src/arithmetic/addition.tests.rs000064400000000000000000000036731046102023000202210ustar 00000000000000mod add_bigdecimals { use super::*; use paste::paste; macro_rules! impl_case { ( $name:ident: $a:literal + $b:literal = $c:literal ) => { #[test] fn $name() { let lhs: BigDecimal = $a.parse().unwrap(); let rhs: BigDecimal = $b.parse().unwrap(); let l_plus_r = add_bigdecimals(lhs.clone(), rhs.clone()); let r_plus_l = add_bigdecimals(rhs, lhs); let expected: BigDecimal = $c.parse().unwrap(); assert_eq!(expected.int_val, l_plus_r.int_val); assert_eq!(expected.scale, l_plus_r.scale); assert_eq!(expected.int_val, r_plus_l.int_val); assert_eq!(expected.scale, r_plus_l.scale); } paste! { #[test] fn [< $name _refs >]() { let lhs: BigDecimal = $a.parse().unwrap(); let rhs: BigDecimal = $b.parse().unwrap(); let l_plus_r = add_bigdecimal_refs(&lhs, &rhs, None); let r_plus_l = add_bigdecimal_refs(&rhs, &lhs, None); let expected: BigDecimal = $c.parse().unwrap(); assert_eq!(expected.int_val, l_plus_r.int_val); assert_eq!(expected.scale, l_plus_r.scale); assert_eq!(expected.int_val, r_plus_l.int_val); assert_eq!(expected.scale, r_plus_l.scale); } } }; } impl_case!(case_1d2345_123d45: "1.2345" + "123.45" = "124.6845"); impl_case!(case_123d43e5_1d2345: "123.43e5" + "1.2345" = "12343001.2345"); impl_case!(case_0_0: "0" + "0" = "0"); impl_case!(case_0_0d00: "0" + "0.00" = "0.00"); impl_case!(case_10_0d00: "10" + "0.00" = "10.00"); impl_case!(case_22132e2_0d0000: "22132e2" + "0.0000" = "2213200.0000"); impl_case!(case_n316d79_0en6: "-316.79" + "0e-6" = "-316.790000"); } bigdecimal-0.4.10/src/arithmetic/cbrt.rs000064400000000000000000000204131046102023000162060ustar 00000000000000//! Implementation of cube-root algorithm use crate::*; use num_bigint::BigUint; use rounding::NonDigitRoundingData; use stdlib::num::NonZeroU64; pub(crate) fn impl_cbrt_int_scale(n: &BigInt, scale: i64, ctx: &Context) -> BigDecimal { let rounding_data = NonDigitRoundingData { sign: n.sign(), mode: ctx.rounding_mode(), }; impl_cbrt_uint_scale((n.magnitude(), scale).into(), ctx.precision(), rounding_data) } /// implementation of cuberoot - always positive pub(crate) fn impl_cbrt_uint_scale( n: WithScale<&BigUint>, precision: NonZeroU64, // contains sign and rounding mode rounding_data: NonDigitRoundingData, ) -> BigDecimal { if n.is_zero() { let biguint = BigInt::from_biguint(Sign::Plus, n.value.clone()); return BigDecimal::new(biguint, n.scale / 3); } // count number of digits in the decimal let integer_digit_count = count_decimal_digits_uint(n.value); // extra digits to use for rounding let extra_rounding_digit_count = 4; // required number of digits for precision and rounding let required_precision = precision.get() + extra_rounding_digit_count; let required_precision = 3 * required_precision; // number of extra zeros to add to end of integer_digits let mut exp_shift = required_precision.saturating_sub(integer_digit_count); // effective scale after multiplying by 10^exp_shift // (we've added that many trailing zeros after) let shifted_scale = n.scale + exp_shift as i64; let (mut new_scale, remainder) = shifted_scale.div_rem(&3); match remainder.cmp(&0) { Ordering::Greater => { new_scale += 1; exp_shift += (3 - remainder) as u64; } Ordering::Less => { exp_shift += remainder.neg() as u64; } Ordering::Equal => { } } // clone-on-write copy of digits let mut integer_digits = stdlib::borrow::Cow::Borrowed(n.value); // add required trailing zeros to integer_digits if exp_shift > 0 { arithmetic::multiply_by_ten_to_the_uint( integer_digits.to_mut(), exp_shift ); } let result_digits = integer_digits.nth_root(3); let result_digits_count = count_decimal_digits_uint(&result_digits); debug_assert!(result_digits_count > precision.get()); let digits_to_trim = result_digits_count - precision.get(); debug_assert_ne!(digits_to_trim, 0); debug_assert!((result_digits_count as i64 - count_decimal_digits_uint(&integer_digits) as i64 / 3).abs() < 2); new_scale -= digits_to_trim as i64; let divisor = ten_to_the_uint(digits_to_trim); let (mut result_digits, remainder) = result_digits.div_rem(&divisor); let remainder_digits = remainder.to_radix_le(10); let insig_digit0; let trailing_digits; if remainder_digits.len() < digits_to_trim as usize { // leading zeros insig_digit0 = 0; trailing_digits = remainder_digits.as_slice(); } else { let (&d, rest) = remainder_digits.split_last().unwrap(); insig_digit0 = d; trailing_digits = rest; } let insig_data = rounding::InsigData::from_digit_and_lazy_trailing_zeros( rounding_data, insig_digit0, || { trailing_digits.iter().all(Zero::is_zero) } ); // lowest digit to round let sig_digit = (&result_digits % 10u8).to_u8().unwrap(); let rounded_digit = insig_data.round_digit(sig_digit); let rounding_term = rounded_digit - sig_digit; result_digits += rounding_term; let result = BigInt::from_biguint(rounding_data.sign, result_digits); BigDecimal::new(result, new_scale) } #[cfg(test)] mod test { use super::*; use stdlib::num::NonZeroU64; macro_rules! impl_test { ($name:ident; $input:literal => $expected:literal) => { #[test] fn $name() { let n: BigDecimal = $input.parse().unwrap(); let value = n.cbrt(); let expected: BigDecimal = $expected.parse().unwrap(); assert_eq!(value, expected); } }; ($name:ident; prec=$prec:literal; round=$round:ident; $input:literal => $expected:literal) => { #[test] fn $name() { let ctx = Context::new(NonZeroU64::new($prec).unwrap(), RoundingMode::$round); let n: BigDecimal = $input.parse().unwrap(); let value = n.cbrt_with_context(&ctx); let expected: BigDecimal = $expected.parse().unwrap(); assert_eq!(value, expected); } }; } mod default { use super::*; impl_test!(case_0; "0.00" => "0"); impl_test!(case_1; "1.00" => "1"); impl_test!(case_1d001; "1.001" => "1.000333222283909495175449559955220102010284758197360454054345461242739715702641939155238095670636841"); impl_test!(case_10; "10" => "2.154434690031883721759293566519350495259344942192108582489235506346411106648340800185441503543243276"); impl_test!(case_13409d179789484375; "13409.179789484375" => "23.7575"); impl_test!(case_n59283293e25; "-59283293e25" => "-84006090355.84281237113712383191213626687332139035750444925827809487776780721673264524620270275301685"); impl_test!(case_94213372931en127; "94213372931e-127" => "2.112049945275324414051072540210070583697242797173805198575907094646677475250362108901530353886613160E-39"); } impl_test!(case_prec15_down_10; prec=15; round=Down; "10" => "2.15443469003188"); impl_test!(case_prec6_up_0d979970546636727; prec=6; round=Up; "0.979970546636727" => "0.993279"); impl_test!(case_1037d495615705321421375_full; "1037.495615705321421375" => "10.123455"); impl_test!(case_1037d495615705321421375_prec7_halfdown; prec=7; round=HalfDown; "1037.495615705321421375" => "10.12345"); impl_test!(case_1037d495615705321421375_prec7_halfeven; prec=7; round=HalfEven; "1037.495615705321421375" => "10.12346"); impl_test!(case_1037d495615705321421375_prec7_halfup; prec=7; round=HalfUp; "1037.495615705321421375" => "10.12346"); impl_test!(case_0d014313506928855520728400001_full; "0.014313506928855520728400001" => "0.242800001"); impl_test!(case_0d014313506928855520728400001_prec6_down; prec=6; round=Down; "0.014313506928855520728400001" => "0.242800"); impl_test!(case_0d014313506928855520728400001_prec6_up; prec=6; round=Up; "0.014313506928855520728400001" => "0.242801"); impl_test!(case_4151902e20_prec16_halfup; prec=16; round=HalfUp; "4151902e20" => "746017527.6855992"); impl_test!(case_4151902e20_prec16_up; prec=16; round=Up; "4151902e20" => "746017527.6855993"); impl_test!(case_4151902e20_prec17_up; prec=17; round=Up; "4151902e20" => "746017527.68559921"); impl_test!(case_4151902e20_prec18_up; prec=18; round=Up; "4151902e20" => "746017527.685599209"); // impl_test!(case_4151902e20_prec18_up; prec=18; round=Up; "4151902e20" => "746017527.685599209"); impl_test!(case_1850846e201_prec14_up; prec=16; round=Up; "1850846e201" => "1.227788123885769e69"); impl_test!(case_6d3797558642427987505823530913e85_prec16_up; prec=160; round=Up; "6.3797558642427987505823530913E+85" => "3995778017e19"); impl_test!(case_88573536600476899341824_prec20_up; prec=20; round=Up; "88573536600476899341824" => "44576024"); impl_test!(case_88573536600476899341824_prec7_up; prec=7; round=Up; "88573536600476899341824" => "4457603e1"); impl_test!(case_833636d150970875_prec5_up; prec=5; round=Up; "833636.150970875" => "94.115000"); impl_test!(case_833636d150970875_prec5_halfup; prec=5; round=HalfUp; "833636.150970875" => "94.115"); impl_test!(case_833636d150970875_prec4_halfup; prec=4; round=HalfUp; "833636.150970875" => "94.12"); impl_test!(case_833636d150970875_prec20_up; prec=20; round=Up; "833636.150970875" => "94.115000"); #[cfg(property_tests)] mod prop { use super::*; use proptest::*; use num_traits::FromPrimitive; proptest! { #[test] fn cbrt_of_cube_is_self(f: f64, prec in 15..50u64) { // ignore non-normal numbers prop_assume!(f.is_normal()); let n = BigDecimal::from_f64(f).unwrap().with_prec(prec); let n_cubed = n.cube(); let x = n_cubed.cbrt(); prop_assert_eq!(x, n); } } } } bigdecimal-0.4.10/src/arithmetic/decimal.rs000064400000000000000000000143021046102023000166520ustar 00000000000000//! Algorithms for manipulating decimal digits //! //! Note: Many bit-optimizations don't apply when doing decimal //! math, as high-order bits affect low-order decimals //! /// Shift u32 right by *n* decimal digits #[allow(dead_code)] pub fn dec_shift_right_u32(x: u32, n: usize) -> u32 { match n { 0 => x, 1 => x / 10, 2 => x / 100, 3 => x / 1000, 4 => x / 10_000, 5 => x / 100_000, 6 => x / 1000_000, 7 => x / 10_000_000, 8 => x / 100_000_000, 9 => x / 1000_000_000, _ => 0, } } /// Shift u64 right by *n* decimal digits #[allow(dead_code)] pub fn dec_shift_right_u64(x: u64, n: usize) -> u64 { match n { 0 => x, 1 => x / 10, 2 => x / 100, 3 => x / 1000, 4 => x / 10_000, 5 => x / 100_000, 6 => x / 1000_000, 7 => x / 10_000_000, 8 => x / 100_000_000, 9 => x / 1000_000_000, 10 => x / 10_000_000_000, 11 => x / 100_000_000_000, 12 => x / 1000_000_000_000, 13 => x / 10_000_000_000_000, 14 => x / 100_000_000_000_000, 15 => x / 1000_000_000_000_000, 16 => x / 10_000_000_000_000_000, 17 => x / 100_000_000_000_000_000, 18 => x / 1000_000_000_000_000_000, 19 => x / 10_000_000_000_000_000_000, _ => 0, } } macro_rules! count_digits { ($n:ident : u128) => { if $n >= 100000000000000000000000000000000000000 { 39 } else if $n >= 10000000000000000000000000000000000000 { 38 } else if $n >= 1000000000000000000000000000000000000 { 37 } else if $n >= 100000000000000000000000000000000000 { 36 } else if $n >= 10000000000000000000000000000000000 { 35 } else if $n >= 1000000000000000000000000000000000 { 34 } else if $n >= 100000000000000000000000000000000 { 33 } else if $n >= 10000000000000000000000000000000 { 32 } else if $n >= 1000000000000000000000000000000 { 31 } else if $n >= 100000000000000000000000000000 { 30 } else if $n >= 10000000000000000000000000000 { 29 } else if $n >= 1000000000000000000000000000 { 28 } else if $n >= 100000000000000000000000000 { 27 } else if $n >= 10000000000000000000000000 { 26 } else if $n >= 1000000000000000000000000 { 25 } else if $n >= 100000000000000000000000 { 24 } else if $n >= 10000000000000000000000 { 23 } else if $n >= 1000000000000000000000 { 22 } else if $n >= 100000000000000000000 { 21 } else { count_digits!($n:u64) } }; ($n:ident : u64) => { if $n >= 10000000000000000000 { 20 } else if $n >= 1000000000000000000 { 19 } else if $n >= 100000000000000000 { 18 } else if $n >= 10000000000000000 { 17 } else if $n >= 1000000000000000 { 16 } else if $n >= 100000000000000 { 15 } else if $n >= 10000000000000 { 14 } else if $n >= 1000000000000 { 13 } else if $n >= 100000000000 { 12 } else if $n >= 10000000000 { 11 } else if $n >= 1000000000 { 10 } else { count_digits!($n:u32) } }; ($n:ident : u32) => { if $n >= 1000000000 { 10 } else if $n >= 100000000 { 9 } else if $n >= 10000000 { 8 } else if $n >= 1000000 { 7 } else if $n >= 100000 { 6 } else { count_digits!($n:u16) } }; ($n:ident : u16) => { if $n >= 100000 { 6 } else if $n >= 10000 { 5 } else if $n >= 1000 { 4 } else { count_digits!($n:u8) } }; ($n:ident : u8) => { if $n >= 100 { 3 } else if $n >= 10 { 2 } else { 1 } }; } /// Count digits in u32 (excluding leading-zeros) pub(crate) fn count_digits_u32(n: u32) -> usize { count_digits!(n:u32) } /// Count digits in u64 (excluding leading-zeros) pub(crate) fn count_digits_u64(n: u64) -> usize { if (n >> 32) == 0 { count_digits_u32(n as u32) } else { count_digits!(n:u64) } } /// Count digits in u128 (excluding leading-zeros) pub(crate) fn count_digits_u128(n: u128) -> usize { if (n >> 64) == 0 { count_digits_u64(n as u64) } else { count_digits!(n:u128) } } /// Return number of decimal digits in biginteger pub(crate) fn count_digits_bigint(n: &num_bigint::BigInt) -> u64 { count_digits_biguint(n.magnitude()) } /// Return number of significant decimal digits in unsigned big-integer pub(crate) fn count_digits_biguint(n: &num_bigint::BigUint) -> u64 { use num_traits::ToPrimitive; if let Some(n) = n.to_u64() { return count_digits_u64(n) as u64; } let mut digits = (n.bits() as f64 / super::LOG2_10) as u64; // guess number of digits based on number of bits in UInt let mut num = super::ten_to_the_uint(digits); debug_assert!(n * 10u8 >= num); while n >= &num { num *= 10u8; digits += 1; } digits } /// Return Some(exp) if n == 10^{exp}, otherwise None pub(crate) fn get_power_of_ten_u64(n: u64) -> Option { match n { 0 => Some(0), 10 => Some(1), 100 => Some(2), 1000 => Some(3), 10000 => Some(4), 100000 => Some(5), 1000000 => Some(6), 10000000 => Some(7), 100000000 => Some(8), 1000000000 => Some(9), 10000000000 => Some(10), n => { let (q, r) = num_integer::div_rem(n, 10000000000); if r == 0 { get_power_of_ten_u64(q).map(|p| p + 10) } else { None } } } } #[cfg(test)] mod test { use super::*; include!("decimal.tests.rs"); } bigdecimal-0.4.10/src/arithmetic/decimal.tests.rs000064400000000000000000000070171046102023000200200ustar 00000000000000use paste::*; macro_rules! impl_case { ($n:literal >> $s:literal => $expected:literal) => { paste! { #[test] fn [< case_ $n _ $s >]() { assert_eq!(TEST_FUNC($n, $s), $expected); } } }; ($n:literal => $expected:literal) => { paste! { #[test] fn [< case_ $n >]() { assert_eq!(TEST_FUNC($n), $expected); } } }; } mod count_digits_u32 { use super::*; const TEST_FUNC: fn(u32) -> usize = count_digits_u32; impl_case!(0 => 1); impl_case!(1 => 1); impl_case!(10 => 2); impl_case!(999999 => 6); impl_case!(4294967295 => 10); } mod count_digits_u64 { use super::*; const TEST_FUNC: fn(u64) -> usize = count_digits_u64; impl_case!(0 => 1); impl_case!(1 => 1); impl_case!(10 => 2); impl_case!(999999 => 6); impl_case!(4294967295 => 10); impl_case!(18446744073709551615 => 20); } mod count_digits_uint { use super::*; #[allow(non_snake_case)] fn TEST_FUNC(src: &str) -> u64 { let n = src.parse().unwrap(); count_digits_biguint(&n) } impl_case!("999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" => 99); impl_case!("9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" => 100); impl_case!("10000000000000000000000000000000000000000000000000000000000000000" => 65); } mod dec_shift_right_u32 { use super::*; const TEST_FUNC: fn(u32, usize) -> u32 = dec_shift_right_u32; impl_case!(0 >> 0 => 0); impl_case!(12345 >> 0 => 12345); impl_case!(12345 >> 1 => 1234); impl_case!(12345 >> 2 => 123); impl_case!(12345 >> 6 => 0); impl_case!(12345 >> 7 => 0); impl_case!(999999999 >> 1 => 99999999); impl_case!(999999999 >> 5 => 9999); impl_case!(999999999 >> 7 => 99); } mod dec_shift_right_u64 { use super::*; const TEST_FUNC: fn(u64, usize) -> u64 = dec_shift_right_u64; impl_case!(1234567890123 >> 0 => 1234567890123); impl_case!(1234567890123 >> 2 => 12345678901); impl_case!(1234567890123 >> 6 => 1234567); impl_case!(1234567890123 >> 7 => 123456); impl_case!(18446744073709551615 >> 1 => 1844674407370955161); impl_case!(18446744073709551615 >> 5 => 184467440737095); impl_case!(18446744073709551615 >> 6 => 18446744073709); impl_case!(18446744073709551615 >> 7 => 1844674407370); impl_case!(18446744073709551615 >> 9 => 18446744073); impl_case!(18446744073709551615 >> 10 => 1844674407); impl_case!(18446744073709551615 >> 19 => 1); impl_case!(18446744073709551615 >> 20 => 0); } #[cfg(property_tests)] mod prop { use super::*; use proptest::*; use proptest::num::f64::*; proptest! { #[test] fn check_dec_shift_right_u32(n: u32) { let mut x = 1; for s in 0..12 { let expected = if x > 0 { n / x } else { 0 }; x = x.checked_mul(10).unwrap_or(0); let value = dec_shift_right_u32(n, s); prop_assert_eq!(expected, value); } } #[test] fn check_dec_shift_right_u64(n: u64) { let mut x = 1; for s in 0..22 { let expected = if x > 0 { n / x } else { 0 }; x = x.checked_mul(10).unwrap_or(0); let value = dec_shift_right_u64(n, s); prop_assert_eq!(expected, value); } } } } bigdecimal-0.4.10/src/arithmetic/inverse.rs000064400000000000000000000273751046102023000167450ustar 00000000000000//! inverse implementation use crate::*; use super::exp2; use arithmetic::decimal::get_power_of_ten_u64; /// Implementation of inverse: (1/n) pub(crate) fn impl_inverse_uint_scale(n: &BigUint, scale: i64, ctx: &Context) -> BigDecimal { if let Some(small_pow_ten) = n.to_u64().and_then(get_power_of_ten_u64) { // optimized inversion for small power of ten: // 1/10^{pow - scale} = 10^{scale - pow} // create bigint with requested precision let prec = ctx.precision().get(); let inv_int = BigInt::from(10u8).pow(prec as u32 - 1); // increase inverted scale by requested precision let inv_scale = small_pow_ten as i64 - scale + prec as i64 - 1; return BigDecimal::new(inv_int, inv_scale); } // use f64 approximation to guess initial inverse let guess = n.to_f64() .filter(|f| f.is_normal()) .map(|f| 1.0 / f) .filter(|&f| f != 0.0 && f.is_finite()) .and_then(BigDecimal::from_f64) .map(|mut d| { d.scale -= scale; d }) .unwrap_or_else( // couldn't use floating point, so just approximate with number of bits || make_inv_guess(n.bits(), scale)); let max_precision = ctx.precision().get(); let s = BigDecimal::new(BigInt::from_biguint(Sign::Plus, n.clone()), scale); let two = BigDecimal::from(2); let next_iteration = move |r: BigDecimal| { let tmp = &two - &s * &r; r * tmp }; // calculate first iteration let mut running_result = next_iteration(guess); debug_assert!(!running_result.is_zero(), "Zero detected in inverse calculation of {}e{}", n, -scale); 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 + 2); // 'result' has clipped precision, 'running_result' has full precision result = if running_result.digits() > max_precision { running_result.with_precision_round(ctx.precision(), ctx.rounding_mode()) } else { running_result.clone() }; } return result; } /// guess inverse based on the number of bits in the integer and decimal's scale fn make_inv_guess(bit_count: u64, scale: i64) -> BigDecimal { // scale by ln(2) let magic_factor = stdlib::f64::consts::LN_2; let bit_count = bit_count as f64; let initial_guess = magic_factor * exp2(-bit_count); if initial_guess.is_finite() && initial_guess != 0.0 { if let Ok(mut result) = BigDecimal::try_from(initial_guess) { result.scale -= scale; return result; } } // backup guess for out-of-range integers let approx_scale = bit_count * stdlib::f64::consts::LOG10_2; let approx_scale_int = approx_scale.trunc(); let approx_scale_frac = approx_scale - approx_scale_int; let recip = libm::exp10(-approx_scale_frac); let mut res = BigDecimal::from_f32((magic_factor * recip) as f32).unwrap(); res.scale += approx_scale_int as i64; res.scale -= scale; return res; } #[cfg(test)] mod test_make_inv_guess { use super::*; use paste::paste; macro_rules! impl_case { ( $bin_count:literal, -$scale:literal => $expected:literal ) => { paste! { impl_case!( [< case_ $bin_count _n $scale >]: $bin_count, -$scale => $expected); } }; ( $bin_count:literal, $scale:literal => $expected:literal ) => { paste! { impl_case!( [< case_ $bin_count _ $scale >]: $bin_count, $scale => $expected); } }; ( $name:ident: $bin_count:expr, $scale:expr => $expected:literal ) => { impl_case!($name: $bin_count, $scale, prec=5 => $expected); }; ( $name:ident: $bin_count:expr, $scale:expr, prec=$prec:literal => $expected:literal ) => { #[test] fn $name() { let guess = make_inv_guess($bin_count, $scale); let expected: BigDecimal = $expected.parse().unwrap(); assert_eq!(guess.with_prec($prec), expected.with_prec($prec)); } }; } impl_case!(0, 0 => "0.69315"); impl_case!(1, 0 => "0.34657"); impl_case!(2, 0 => "0.17329"); impl_case!(2, 1 => "1.7329"); // 1 / (2^3 * 10^5) ~ impl_case!(3, -5 => "8.6643e-07"); // 2^-20 impl_case!(20, 0 => "6.6104e-07"); impl_case!(20, -900 => "6.6104E-907"); impl_case!(20, 800 => "6.6104E+793"); impl_case!(40, 10000 => "6.3041E+9987"); impl_case!(70, -5 => "5.8712e-27"); impl_case!(70, 5 => "5.8712e-17"); impl_case!(70, 50 => "5.8712e+28"); impl_case!(888, -300 => "3.3588E-568"); impl_case!(888, -19 => "3.3588E-287"); impl_case!(888, 0 => "3.3588E-268"); impl_case!(888, 270 => "335.88"); impl_case!(1022, 10 => "1.5423e-298"); impl_case!(1022, 308 => "1.5423"); impl_case!(1038, 316 => "2353.4"); impl_case!(case_31028_n659: 31028, -659 => "3.0347E-10000"); impl_case!(case_31028_0: 31028, 0 => "3.0347E-9341"); impl_case!(case_31028_1: 31028, 1 => "3.0347E-9340"); impl_case!(case_31028_9340: 31028, 9340 => ".30347"); impl_case!(case_31028_10000: 31028, 10000 => "3.0347E+659"); // impl_case!(case_max: u64::MAX, 270 => "335.88"); } #[cfg(test)] mod test { use super::*; use paste::paste; use stdlib::num::NonZeroU64; #[test] fn test_inverse_35543972957198043e291() { let v = vec![ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2324389888, 849200558 ]; let x = BigInt::new(Sign::Minus, v); let d = BigDecimal::from(x); let expected = "-2.813416500187520746852694701086705659180043761702417561798711758892800449936819185796527214192677476E-308".parse::().unwrap(); assert_eq!(d.inverse(), expected); assert_eq!(d.neg().inverse(), expected.neg()); } macro_rules! impl_case { ($name:ident: $prec:literal, $round:ident => $expected:literal) => { #[test] fn $name() { let n = test_input(); let prec = NonZeroU64::new($prec).unwrap(); let rounding = RoundingMode::$round; let ctx = Context::new(prec, rounding); let result = n.inverse_with_context(&ctx); let expected = $expected.parse::().unwrap(); assert_eq!(&result, &expected); let product = result * &n; let epsilon = BigDecimal::new(BigInt::one(), $prec - 1); let diff = (BigDecimal::one() - &product).abs(); assert!(diff < epsilon); } }; (prec=$prec:literal, round=$round:ident => $expected:literal) => { paste! { #[test] fn [< case_prec $prec _round_ $round:lower >] () { let n = test_input(); let prec = NonZeroU64::new($prec).unwrap(); let rounding = RoundingMode::$round; let ctx = Context::new(prec, rounding); let result = n.inverse_with_context(&ctx); let expected = $expected.parse::().unwrap(); assert_eq!(&result, &expected); assert_eq!(&result.scale, &expected.scale); } } }; (prec=$prec:literal, round=$($round:ident),+ => $expected:literal) => { $( impl_case!(prec=$prec, round=$round => $expected); )* }; } mod invert_one { use super::*; fn test_input() -> BigDecimal { 1u8.into() } impl_case!(prec=1, round=Up,Down => "1"); impl_case!(prec=2, round=Up,Down => "1.0"); impl_case!(prec=7, round=Up,Down => "1.000000"); } mod invert_n1d00 { use super::*; fn test_input() -> BigDecimal { "-1.00".parse().unwrap() } impl_case!(prec=1, round=Up,Down => "-1"); impl_case!(prec=5, round=Up,Down => "-1.0000"); } mod invert_n1000en8 { use super::*; fn test_input() -> BigDecimal { "1000e-8".parse().unwrap() } impl_case!(prec=1, round=Up,Down => "1e5"); impl_case!(prec=5, round=Up,Down => "10000e1"); impl_case!(prec=6, round=Up,Down => "100000"); impl_case!(prec=8, round=Up,Down => "100000.00"); } mod invert_seven { use super::*; fn test_input() -> BigDecimal { BigDecimal::from(7u8) } impl_case!(case_prec10_round_down: 10, Down => "0.1428571428"); impl_case!(case_prec10_round_up: 10, Up => "0.1428571429"); impl_case!(case_prec11_round_ceiling: 11, Ceiling => "0.14285714286"); } mod invert_ten { use super::*; fn test_input() -> BigDecimal { 10u8.into() } impl_case!(case_prec1_round_down: 1, Down => "0.1"); impl_case!(case_prec2_round_down: 2, Down => "0.10"); impl_case!(prec=10, round=Up, Down => "0.1000000000"); } mod invert_n3242342d34324 { use super::*; fn test_input() -> BigDecimal { "-3242342.34324".parse().unwrap() } // note: floor ceiling wrong impl_case!(prec=50, round=Up, Ceiling => "-3.0841900519385698894827476971712670726697831310897E-7"); impl_case!(prec=50, round=Down, Floor => "-3.0841900519385698894827476971712670726697831310896E-7"); } mod invert_2d8722377233432854650en126 { use super::*; fn test_input() -> BigDecimal { "28722377233432854650456573411382289859440620032075590707304700193738855195818029876568741547799767753181511758371393266031229989006058870578446812747289276920741036671713994469786904880406812933015496296559493964954240161851051500623562557032166800306346000498803201936493334049050141321136859175463065287081665388768669799901545047760009765625e-469" .parse().unwrap() } impl_case!(prec=1, round=Up => "4e125"); impl_case!(prec=5, round=Up => "3.4817e+125"); impl_case!(prec=25, round=Up => "3.481605968311006434080812E+125"); } #[test] fn inv_random_number() { let n = BigDecimal::try_from(0.08121970592310568).unwrap(); let ctx = Context::new(NonZeroU64::new(40).unwrap(), RoundingMode::Down); let i = n.inverse_with_context(&ctx); assert_eq!(&i, &"12.31228294456944530942557443718279245563".parse::().unwrap()); let product = i * &n; assert!(BigDecimal::one() - &product < "1e-39".parse::().unwrap()); } #[cfg(property_tests)] mod prop { use super::*; use proptest::*; use num_traits::FromPrimitive; proptest! { #[test] fn inverse_multiplies_to_one(f: f64, prec in 1..100u64) { // ignore non-normal numbers prop_assume!(f.is_normal()); prop_assume!(f != 0.0); let n = BigDecimal::from_f64(f).unwrap(); let ctx = Context::new(NonZeroU64::new(prec).unwrap(), RoundingMode::Up); let i = n.inverse_with_context(&ctx); let product = &i * &n; // accurate to precision minus one (due to rounding) let epsilon = BigDecimal::new(1.into(), prec as i64 - 1); let diff_from_one = BigDecimal::one() - &product; prop_assert!(diff_from_one.abs() < epsilon, "{} >= {}", diff_from_one.abs(), epsilon); } } } } bigdecimal-0.4.10/src/arithmetic/mod.rs000064400000000000000000000126301046102023000160350ustar 00000000000000//! arithmetic routines use crate::*; use num_traits::CheckedSub; use num_traits::AsPrimitive; pub(crate) mod decimal; pub(crate) mod addition; pub(crate) mod multiplication; pub(crate) mod modulo; pub(crate) mod sqrt; pub(crate) mod cbrt; pub(crate) mod inverse; pub(crate) mod pow; pub(crate) use self::decimal::{ count_digits_bigint as count_decimal_digits, count_digits_biguint as count_decimal_digits_uint, }; #[cfg(not(feature = "std"))] mod funcs { // f64::exp2 is only available in std, we have to use an external crate like libm pub fn exp2(x: f64) -> f64 { libm::exp2(x) } // f64::log10 is only available in std, we have to use an external crate like libm pub fn log10(x: f64) -> f64 { libm::log10(x) } } #[cfg(feature = "std")] mod funcs { pub fn exp2(x: f64) -> f64 { x.exp2() } pub fn log10(x: f64) -> f64 { x.log10() } } // rexport all funcs into this module pub(crate) use self::funcs::*; /// Return 10^pow /// /// Try to calculate this with fewest number of allocations /// pub(crate) fn ten_to_the(pow: u64) -> BigInt { ten_to_the_uint(pow).into() } /// Return 10^{pow} as u64 pub(crate) fn ten_to_the_u64(pow: u8) -> u64 { debug_assert!(pow < 20); 10u64.pow(pow as u32) } /// Return 10^{pow} as output pub(crate) fn ten_to_the_t(pow: u8) -> T where T: From + num_traits::Pow { debug_assert!((pow as f64) < stdlib::mem::size_of::() as f64 * 8.0 / LOG2_10); T::from(10u8).pow(pow) } /// Return 10^pow pub(crate) fn ten_to_the_uint(pow: u64) -> BigUint { if pow < 20 { return BigUint::from(10u64.pow(pow as u32)); } // linear case of 10^pow = 10^(19 * count + rem) if pow < 590 { let ten_to_nineteen = 10u64.pow(19); // count factors of 19 let (count, rem) = pow.div_rem(&19); let mut res = BigUint::from(ten_to_nineteen); for _ in 1..count { res *= ten_to_nineteen; } if rem != 0 { res *= 10u64.pow(rem as u32); } return res; } // use recursive algorithm where linear case might be too slow let (quotient, rem) = pow.div_rem(&16); let x = ten_to_the_uint(quotient); let x2 = &x * &x; let x4 = &x2 * &x2; let x8 = &x4 * &x4; let res = &x8 * &x8; if rem == 0 { res } else { res * 10u64.pow(rem as u32) } } pub(crate) fn multiply_by_ten_to_the_uint(n: &mut T, pow: P) where T: MulAssign + MulAssign, P: ToPrimitive, { let pow = pow.to_u64().expect("exponent overflow error"); if pow < 20 { *n *= 10u64.pow(pow as u32); } else { *n *= ten_to_the_uint(pow); } } /// Return difference of two numbers, returning diff as u64 pub(crate) fn diff(a: T, b: T) -> (Ordering, u64) where T: ToPrimitive + CheckedSub + stdlib::cmp::Ord, { use stdlib::cmp::Ordering::*; let (ord, diff) = checked_diff(a, b); (ord, diff.expect("subtraction overflow")) } /// Return difference of two numbers. If num doesn't fit in u64, return None pub(crate) fn checked_diff(a: T, b: T) -> (Ordering, Option) where T: ToPrimitive + CheckedSub + stdlib::cmp::Ord, { use stdlib::cmp::Ordering::*; let _try_subtracting = |x: T, y: T| x.checked_sub(&y).and_then(|diff| diff.to_u64()); match a.cmp(&b) { Less => (Less, _try_subtracting(b, a)), Greater => (Greater, _try_subtracting(a, b)), Equal => (Equal, Some(0)), } } /// Return difference of two numbers, returning diff as usize #[allow(dead_code)] pub(crate) fn diff_usize(a: T, b: T) -> (Ordering, usize) where T: AsPrimitive + stdlib::ops::Sub + stdlib::cmp::Ord, { use stdlib::cmp::Ordering::*; match a.cmp(&b) { Less => (Less, (b - a).as_()), Greater => (Greater, (a - b).as_()), Equal => (Equal, 0), } } /// Return absolute difference between two numbers #[cfg(rustc_1_60)] #[allow(clippy::incompatible_msrv)] #[allow(dead_code)] pub(crate) fn abs_diff(x: i64, y: i64) -> u64 { x.abs_diff(y) } #[cfg(not(rustc_1_60))] #[allow(dead_code)] pub(crate) fn abs_diff(x: i64, y: i64) -> u64 { (x as i128 - y as i128).to_u64().unwrap_or(0) } /// Add carry to given number, returning trimmed value and storing overflow back in carry /// pub(crate) fn add_carry(n: u8, carry: &mut u8) -> u8 { let s = n + *carry; if s < 10 { *carry = 0; s } else { debug_assert!(s < 20); *carry = 1; s - 10 } } /// If n is greater than 10, split and store overflow in carry /// /// No action if n is less than 10. /// /// Carry is not allowed to be 1 if n is two digits /// pub(crate) fn store_carry(n: u8, carry: &mut u8) -> u8 { if n < 10 { n } else { debug_assert!(n < 20); debug_assert_eq!(carry, &0); *carry = 1; n - 10 } } /// Extend destination vector with values in D, adding carry while carry is not zero /// /// If carry overflows, it is NOT pushed into the destination vector. /// pub(crate) fn extend_adding_with_carry>( dest: &mut Vec, mut digits: D, carry: &mut u8, ) { while *carry != 0 { match digits.next() { Some(d) => { dest.push(add_carry(d, carry)) } None => { return; } } } dest.extend(digits); } bigdecimal-0.4.10/src/arithmetic/modulo.rs000064400000000000000000000021041046102023000165500ustar 00000000000000use crate::*; /// optimized calculation of n % 10 #[allow(dead_code)] pub(crate) fn mod_ten_uint(n: &BigUint) -> u8 { mod_ten_2p64_le(n.iter_u64_digits()) } /// optimized calculation of n % 10 pub(crate) fn mod_ten_2p64_le(mut digits: impl Iterator) -> u8 { let d0 = digits.next().unwrap_or(0) % 10; let mut acc: u64 = digits.map(|d| d % 10).sum(); acc *= 6; acc += d0; (acc % 10) as u8 } /// optimized calculation of n % 100 pub(crate) fn mod_100_uint(n: &BigUint) -> u8 { mod_100_2p64_le(n.iter_u64_digits()) } /// optimized calculation of n % 100 /// TODO: compare implementations: https://rust.godbolt.org/z/Kcxor1MT5 pub(crate) fn mod_100_2p64_le(mut digits: impl Iterator) -> u8 { let mods_2p64 = [16, 56, 96, 36, 76]; let mut acc_v = [ 0, 0, 0, 0, 0]; let d0 = digits.next().unwrap_or(0) % 100; for (i, d) in digits.enumerate() { acc_v[i % 5] += d % 100; } let mut acc = d0; for (&a, m) in acc_v.iter().zip(mods_2p64.iter()) { acc += m * (a % 100); } (acc % 100) as u8 } bigdecimal-0.4.10/src/arithmetic/multiplication.rs000064400000000000000000001022741046102023000203170ustar 00000000000000//! Routines for multiplying numbers //! #![allow(dead_code)] #![allow(clippy::identity_op)] use stdlib::num::NonZeroU64; use num_traits::AsPrimitive; use crate::*; use crate::rounding::{NonDigitRoundingData, InsigData}; use super::log10; use crate::bigdigit::{ radix::{RadixType, RadixPowerOfTen, RADIX_u64, RADIX_10_u8, RADIX_10p19_u64}, endian::{Endianness, LittleEndian, BigEndian}, digitvec::{DigitVec, DigitSlice}, }; type BigDigitVec = DigitVec; type BigDigitVecBe = DigitVec; type BigDigitSliceU64<'a> = DigitSlice<'a, RADIX_u64, LittleEndian>; type BigDigitVecP19 = DigitVec; type BigDigitSliceP19<'a> = DigitSlice<'a, RADIX_10p19_u64, LittleEndian>; type SmallDigitVec = DigitVec; const BASE2_BIGINT_MUL_THRESHOLD: u64 = 128; pub(crate) fn multiply_decimals_with_context<'a, A, B>( dest: &mut BigDecimal, a: A, b: B, ctx: &Context, ) where A: Into>, B: Into>, { let a = a.into(); let b = b.into(); impl_multiply_decimals_with_context(dest, a, b, ctx); } pub fn impl_multiply_decimals_with_context( dest: &mut BigDecimal, a: BigDecimalRef, b: BigDecimalRef, ctx: &Context, ) { if a.is_zero() || b.is_zero() { *dest = BigDecimal::zero(); return; } let sign = a.sign() * b.sign(); let rounding_data = NonDigitRoundingData { sign: sign, mode: ctx.rounding_mode(), }; let a_uint = a.digits; let b_uint = b.digits; match (a, b.is_one_quickcheck(), b, a.is_one_quickcheck()) { (x, Some(true), _, _) | (_, _, x, Some(true)) => { let WithScale { value: rounded_uint, scale: rounded_scale, } = rounding_data.round_biguint_to_prec(x.digits.clone(), ctx.precision()); dest.scale = x.scale + rounded_scale; dest.int_val = BigInt::from_biguint(sign, rounded_uint); return; } _ => {} } if let (Some(x), Some(y)) = (a_uint.to_u64(), b_uint.to_u64()) { multiply_scaled_u64_into_decimal( dest, WithScale { value: x, scale: a.scale }, WithScale { value: y, scale: b.scale }, ctx.precision(), rounding_data, ); debug_assert_eq!(dest.sign(), sign); return; } let a_vec = BigDigitVec::from(a_uint); let b_vec = BigDigitVec::from(b_uint); let digit_vec = BigDigitVec::new(); let mut digit_vec_scale = WithScale::from((digit_vec, 0)); multiply_scaled_u64_slices_with_prec_into( &mut digit_vec_scale, WithScale { value: a_vec.as_digit_slice(), scale: a.scale }, WithScale { value: b_vec.as_digit_slice(), scale: b.scale }, ctx.precision(), rounding_data, ); dest.int_val = BigInt::from_biguint(sign, digit_vec_scale.value.into()); dest.scale = digit_vec_scale.scale; } pub(crate) fn multiply_scaled_u64_into_decimal( dest: &mut BigDecimal, a: WithScale, b: WithScale, prec: NonZeroU64, rounding_data: NonDigitRoundingData, ) { use crate::arithmetic::decimal::count_digits_u128; let mut product = a.value as u128 * b.value as u128; let digit_count = count_digits_u128(product) as u64; let mut digits_to_remove = digit_count.saturating_sub(prec.get()) as u32; if digits_to_remove == 0 { dest.int_val = BigInt::from_biguint(rounding_data.sign, product.into()); dest.scale = a.scale + b.scale; return; } let shifter = 10u128.pow(digits_to_remove - 1); let (hi, trailing) = product.div_rem(&shifter); let (shifted_product, insig_digit) = hi.div_rem(&10); let sig_digit = (shifted_product % 10) as u8; let rounded_digit = rounding_data.round_pair( (sig_digit, insig_digit as u8), trailing == 0, ); product = shifted_product - sig_digit as u128 + rounded_digit as u128; if rounded_digit >= 10 { debug_assert_eq!(rounded_digit, 10); let old_digit_count = digit_count - digits_to_remove as u64; debug_assert_eq!(old_digit_count, count_digits_u128(shifted_product) as u64); let rounded_digit_count = count_digits_u128(product) as u64; if old_digit_count != rounded_digit_count { debug_assert_eq!(rounded_digit_count, old_digit_count + 1); product /= 10; digits_to_remove += 1; } } let digit_array = mul_split_u128_to_u32x4(product); dest.int_val.assign_from_slice(rounding_data.sign, &digit_array); dest.scale = a.scale + b.scale - digits_to_remove as i64; } /// Multiply digits in slices a and b, ignoring all factors that come from /// digits "below" the given index (which is stored at index 0 in the dest) /// /// ```ignore /// a₀ a₁ a₂ a₃ ... /// b₀| 0 1 2 3 /// b₁| 1 2 3 4 <- indexes in vector of the 'full' product /// b₂| 2 3 4 5 ... /// ``` /// If given idx '3', `dest[0] = a₁b₂ + a₂b₁ + a₃b₀` and `dest[1] = a₂b₂+...` etc /// /// Carrying from lower digits is not calculated, so care must be given /// to ensure data enough digits are provided. /// pub(crate) fn multiply_at_product_index( dest: &mut DigitVec, a: DigitSlice, b: DigitSlice, idx: usize, ) where R: RadixType, E: Endianness, EA: Endianness, EB: Endianness, { debug_assert!(b.len() <= a.len()); dest.resize((a.len() + b.len()).saturating_sub(idx)); let b_idx_min = idx.saturating_sub(a.len() - 1); for (b_idx, &x) in b.iter_le().enumerate().skip(b_idx_min).rev() { let a_idx_min = idx.saturating_sub(b_idx); debug_assert!(a_idx_min < a.len()); let dest_idx = a_idx_min + b_idx - idx; let mut dest_digits = dest.iter_le_mut().skip(dest_idx); let mut carry = Zero::zero(); for &y in a.iter_le().skip(a_idx_min) { R::carrying_mul_add_inplace( x, y, dest_digits.next().unwrap(), &mut carry ); } R::add_carry_into(dest_digits, &mut carry); if !carry.is_zero() { dest.push_significant_digit(carry); } } } pub(crate) fn multiply_at_idx_into( dest: &mut DigitVec, a: DigitSlice, b: DigitSlice, idx: usize, ) { debug_assert!(a.len() + b.len() <= dest.len() + idx); for (ia, &da) in a.digits.iter().enumerate() { if da.is_zero() { continue; } let mut carry = Zero::zero(); for (&db, result) in b.digits.iter().zip(dest.digits.iter_mut().skip(idx + ia)) { R::carrying_mul_add_inplace(da, db, result, &mut carry); } dest.add_value_at(idx + ia + b.len(), carry); } } pub(crate) fn multiply_big_int_with_ctx(a: &BigInt, b: &BigInt, ctx: Context) -> WithScale { let sign = a.sign() * b.sign(); // Rounding prec: usize let rounding_data = NonDigitRoundingData { sign: sign, mode: ctx.rounding_mode(), }; // if bits are under this threshold, just multiply full integer and round if a.bits() + b.bits() < BASE2_BIGINT_MUL_THRESHOLD { return ctx.round_bigint(a * b); } let mut tmp = Vec::new(); let a_p19_vec = BigDigitVecP19::from_biguint_using_tmp(a.magnitude(), &mut tmp); let b_p19_vec = BigDigitVecP19::from_biguint_using_tmp(b.magnitude(), &mut tmp); let mut result = WithScale::default(); multiply_slices_with_prec_into_p19( &mut result, a_p19_vec.as_digit_slice(), b_p19_vec.as_digit_slice(), ctx.precision(), rounding_data ); WithScale { scale: result.scale, value: result.value.into_bigint(sign), } } /// Store product of 'a' & 'b' into dest, only calculating 'prec' /// number of digits /// /// Use 'rounding' to round at requested position. /// Assumes 'a' & 'b' are full numbers, so all insignificant digits /// are zero. /// pub(crate) fn multiply_slices_with_prec_into_p19( dest: &mut WithScale, a: BigDigitSliceP19, b: BigDigitSliceP19, prec: NonZeroU64, rounding: NonDigitRoundingData ) { multiply_slices_with_prec_into_p19_z(dest, a, b, prec, rounding, true) } /// Store product of 'a' & 'b' into dest, only calculating 'prec' number of digits /// /// Use 'rounding' information to round at requested position. /// The 'assume_trailing_zeros' parameter determines proper rounding technique if /// 'a' & 'b' are partial numbers, where trailing insignificant digits may or may /// not be zero. /// pub(crate) fn multiply_slices_with_prec_into_p19_z( dest: &mut WithScale, a: BigDigitSliceP19, b: BigDigitSliceP19, prec: NonZeroU64, rounding: NonDigitRoundingData, assume_trailing_zeros: bool, ) { use super::bigdigit::alignment::BigDigitSplitter; use super::bigdigit::alignment::BigDigitSliceSplitterIter; type R = RADIX_10p19_u64; if a.len() < b.len() { // ensure a is the longer of the two digit slices return multiply_slices_with_prec_into_p19_z(dest, b, a, prec, rounding, assume_trailing_zeros); } dest.value.clear(); if b.is_all_zeros() || a.is_all_zeros() { // multiplication by zero: return after clearing dest return; } debug_assert_ne!(a.len(), 0); debug_assert_ne!(b.len(), 0); let WithScale { value: dest, scale: result_scale } = dest; // minimum possible length of each integer, given length of bigdigit vecs let pessimistic_product_digit_count = (a.len() + b.len() - 2) * R::DIGITS + 1; // require more digits of precision for overflow and rounding // max number of digits produced by adding all bigdigits at any // particular "digit-index" i of the product // log10( Σ a_m × b_n (∀ m+n=i) ) let max_digit_sum_width = (2.0 * log10(R::max() as f64) + log10(b.len() as f64)).ceil() as usize; let max_bigdigit_sum_width = R::divceil_digit_count(max_digit_sum_width); // the "index" of the product which could affect the significant results let digits_to_skip = pessimistic_product_digit_count.saturating_sub(prec.get() as usize + 1); let bigdigits_to_skip = R::divceil_digit_count(digits_to_skip) .saturating_sub(max_bigdigit_sum_width); let a_start; let b_start; if bigdigits_to_skip == 0 { // we've requested more digits than product will produce; don't skip any digits a_start = 0; b_start = 0; } else { // the indices of the least significant bigdigits in a and b which may contribute // to the significant digits in the product a_start = bigdigits_to_skip.saturating_sub(b.len()); b_start = bigdigits_to_skip.saturating_sub(a.len()); } let a_sig = a.trim_insignificant(a_start); let b_sig = b.trim_insignificant(b_start); let a_sig_digit_count = a_sig.count_decimal_digits(); let b_sig_digit_count = b_sig.count_decimal_digits(); // calculate maximum number of digits from product let max_sigproduct_bigdigit_count = R::divceil_digit_count(a_sig_digit_count + b_sig_digit_count + 1); let mut product = BigDigitVecP19::with_capacity(max_sigproduct_bigdigit_count + max_bigdigit_sum_width + 1); *result_scale -= (R::DIGITS * bigdigits_to_skip) as i64; multiply_at_product_index(&mut product, a, b, bigdigits_to_skip); product.remove_leading_zeros(); let product_digit_count = product.count_decimal_digits(); // precision plus the rounding digit let digits_to_remove = product_digit_count.saturating_sub(prec.get() as usize); if digits_to_remove == 0 { debug_assert_eq!(a_start, 0); debug_assert_eq!(b_start, 0); debug_assert_eq!(bigdigits_to_skip, 0); // no need to trim the results, everything was significant; *dest = product; return; } // removing insignificant digits decreases the scale *result_scale -= digits_to_remove as i64; // keep adding more multiplication terms if the number ends with 999999...., until // the nines stop or it overflows. // NOTE: the insignificant digits in 'product' will be _wrong_ and must be ignored let trailing_zeros = assume_trailing_zeros && calculate_partial_product_trailing_zeros( &mut product, a, b, bigdigits_to_skip, digits_to_remove ); // remove the digits, returning the top one to be used let insig_digit = product.shift_n_digits_returning_high(digits_to_remove); let sig_digit = (product.digits[0] % 10) as u8; let insig_rounding_data = InsigData { rounding_data: rounding, digit: insig_digit, trailing_zeros, }; let rounded_digit = insig_rounding_data.round_digit(sig_digit); let mut carry = rounded_digit as u64; product.digits[0] -= sig_digit as u64; R::add_carry_into_slice( &mut product.digits, &mut carry ); if carry != 0 { debug_assert!(product.digits.iter().all(|&d| d == 0)); *result_scale -= 1; *product.digits.last_mut().unwrap() = (R::RADIX as u64) / 10; } if rounded_digit == 10 && product.count_decimal_digits() != prec.get() as usize { *result_scale -= 1; if let Some((hi, zeros)) = product.digits.split_last_mut() { debug_assert!(*hi >= 10); debug_assert!(zeros.iter().all(|&d| d == 0)); *hi /= 10; } else { unreachable!(); } } *dest = product; } /// Store `a * b` into dest, to limited precision pub(crate) fn multiply_scaled_u64_slices_with_prec_into( dest: &mut WithScale, a: WithScale, b: WithScale, prec: NonZeroU64, rounding: NonDigitRoundingData, ) { let a_base10: BigDigitVecP19 = a.value.into(); let b_base10: BigDigitVecP19 = b.value.into(); let mut product = WithScale::default(); multiply_slices_with_prec_into_p19( &mut product, a_base10.as_digit_slice(), b_base10.as_digit_slice(), prec, rounding, ); dest.scale = a.scale + b.scale + product.scale; dest.value = product.value.into(); } /// Calculate the 'backwards' product of a & b, stopping when it can be /// proven that no further overflow can happen /// /// Return true if the product after overflow-calculation has all /// trailing zeros. /// /// Parameter 'v' here is the pre-calculated "extended" product of a & b, /// extended meaning it has incorrect insignificant digits that were /// calculated to add overflow/carrys into the significant digits. /// This function continues multiplying trailing digits if there is a /// chance that a rounding. /// /// 'product_idx' is the index of the true product where v starts /// (i.e. v[0] corresponds to true_product[product_idx], used here for /// calculating the insignificant product of a and b, backwards. /// /// 'digits_to_remove' is the number of digits in v that should be /// considered insignificant, and may be changed by this function. /// fn calculate_partial_product_trailing_zeros( v: &mut BigDigitVecP19, a: BigDigitSliceP19, b: BigDigitSliceP19, product_idx: usize, digits_to_remove: usize, ) -> bool { type R = RADIX_10p19_u64; if digits_to_remove == 0 { return true; } debug_assert!(b.len() <= a.len()); debug_assert!(digits_to_remove <= v.count_decimal_digits()); let (insig_bd_count, insig_d_count) = R::divmod_digit_count(digits_to_remove); debug_assert!(insig_bd_count > 0 || insig_d_count > 0); let trailing_zeros; let trailing_nines; // index of the first "full" insignificant big-digit let top_insig_idx; match (insig_bd_count, insig_d_count as u8) { (0, 0) => unreachable!(), (0, 1) => { return true; } (0, 2) => { return v.digits[0] % 10 == 0; } (0, n) => { let splitter = ten_to_the_u64(n - 1); return v.digits[0] % splitter == 0; } (1, 0) => { let splitter = ten_to_the_u64(R::DIGITS as u8 - 1); return v.digits[0] % splitter == 0; } (1, 1) => { return v.digits[0] == 0; } (i, 1) => { // special case when the 'top' insignificant digit is // with the other digits trailing_zeros = v.digits[i - 1] == 0; trailing_nines = v.digits[i - 1] == R::max(); top_insig_idx = i - 1; } (i, 0) => { // split on a boundary, check previous bigdigit let insig = v.digits[i - 1]; let splitter = ten_to_the_u64(R::DIGITS as u8 - 1); let insig_digits = insig % splitter; trailing_zeros = insig_digits == 0 && v.iter_le().take(i - 1).all(Zero::is_zero); trailing_nines = insig_digits == splitter - 1; top_insig_idx = i - 2; } (i, n) => { let insig = v.digits[i]; let splitter = ten_to_the_u64(n - 1); let insig_digits = insig % splitter; trailing_zeros = insig_digits == 0 && v.iter_le().take(i).all(Zero::is_zero); trailing_nines = insig_digits == splitter - 1; top_insig_idx = i - 1; } } // the insignificant digits should be at least one bigdigit wider // than the maximum overflow from one iteration of preceding digits // debug_assert!(insig_bd_count >= max_bigdigit_sum_width, "{}, {}", insig_bd_count, max_bigdigit_sum_width); // not zero and no chance for overflow if !trailing_zeros && !trailing_nines { return false; } if product_idx == 0 { // no new multiplications needs to happen, just return if // product has trailing zeros return trailing_zeros && v.digits[..top_insig_idx].iter().all(|&d| d == 0); } // check if last bigdigit in product is not zero before iterative multiplication if trailing_zeros && (a.digits[0].saturating_mul(b.digits[0])) != 0 { return false; } for idx in (0..product_idx).rev() { let a_range; let b_range; if idx < b.len() { // up to and including 'idx' a_range = 0..idx + 1; b_range = 0..idx + 1; } else if idx < a.len() { a_range = idx - b.len() + 1..idx + 1; b_range = 0..b.len(); } else { a_range = idx - b.len() + 1..a.len(); b_range = idx - a.len() + 1..b.len(); } debug_assert_eq!( a_range.end - a_range.start, b_range.end - b_range.start, ); let a_start = a_range.start; let b_start = b_range.start; let a_digits = a.digits[a_range].iter(); let b_digits = b.digits[b_range].iter().rev(); let mut d0 = 0; let mut carry = Zero::zero(); for (&x, &y) in a_digits.zip(b_digits) { R::carrying_mul_add_inplace(x, y, &mut d0, &mut carry); R::add_carry_into(v.digits.iter_mut(), &mut carry); } debug_assert_eq!(carry, 0); let top_insig = v.digits[top_insig_idx]; if top_insig != R::max() { // we have overflowed! return v.least_n_are_zero(top_insig_idx) && a.least_n_are_zero(a_start) && b.least_n_are_zero(b_start); } // shift the insignificant digits in the vector by one // (i.e. the '9999999' in highest insig bigdigit may be ignored) v.digits.copy_within(..top_insig_idx, 1); v.digits[0] = d0; } // never overflowed, therefore "trailing zeros" is false return false; } /// Calculate dest = a * b to at most 'prec' number of bigdigits, truncating (not rounding) /// the results. /// /// The scale of these vector/slices is number of *bigdigits*, not number of digits. /// /// Returns the number of 'skipped' bigdigits in the result. /// pub(crate) fn mul_scaled_slices_truncating_into( dest: &mut WithScale>, a: WithScale>, b: WithScale>, prec: u64, ) -> usize where R: RadixType, E: Endianness, EA: Endianness, EB: Endianness, { use super::bigdigit::alignment::BigDigitSplitter; use super::bigdigit::alignment::BigDigitSliceSplitterIter; type R = RADIX_10p19_u64; if a.value.len() < b.value.len() { // ensure a is the longer of the two digit slices return mul_scaled_slices_truncating_into(dest, b, a, prec); } let WithScale { value: product, scale: dest_scale } = dest; let WithScale { value: a, scale: a_scale } = a; let WithScale { value: b, scale: b_scale } = b; *dest_scale = a_scale + b_scale; product.clear(); if b.is_all_zeros() || a.is_all_zeros() { // multiplication by zero: return after clearing dest return 0; } debug_assert_ne!(a.len(), 0); debug_assert_ne!(b.len(), 0); // require more digits of precision for overflow and rounding // max number of digits produced by adding all bigdigits at any // particular "digit-index" i of the product // log10( Σ a_m × b_n (∀ m+n=i) ) let max_digit_sum_width = (2.0 * log10(R::max() as f64) + log10(b.len() as f64)).ceil() as usize; let max_bigdigit_sum_width = R::divceil_digit_count(max_digit_sum_width); let max_product_size = a.len() + b.len(); let max_vector_size = prec as usize + max_bigdigit_sum_width; let bigdigits_to_skip = max_product_size.saturating_sub(max_vector_size); *dest_scale -= bigdigits_to_skip as i64; multiply_at_product_index(product, a, b, bigdigits_to_skip); product.remove_leading_zeros(); let extra_digit_count = product.len().saturating_sub(prec as usize); product.remove_insignificant_digits(extra_digit_count); *dest_scale -= extra_digit_count as i64; return bigdigits_to_skip; } /// split u64 into high and low bits fn split_u64(x: u64) -> (u64, u64) { x.div_rem(&(1 << 32)) } fn mul_split_u64_u64(a: u64, b: u64) -> [u32; 4] { let p = u128::from(a) * u128::from(b); mul_split_u128_to_u32x4(p) } fn mul_split_u128_to_u32x4(n: u128) -> [u32; 4] { [ (n >> 0).as_(), (n >> 32).as_(), (n >> 64).as_(), (n >> 96).as_(), ] } /// Add carry into dest #[inline] fn _apply_carry_u64(dest: &mut [u32], mut idx: usize, mut carry: u64) { while carry != 0 { idx += 1; let (c, r) = split_u64(dest[idx] as u64 + carry); dest[idx] = r as u32; carry = c; } } /// Evaluate (a + (b << 64))^2, where a and b are u64's, storing /// the result as u32's in *dest*, starting at location *idx* /// /// This is useful for a and b as adjacent big-digits in a big- /// number, or components of a u128, squared. /// /// (a + (b << 64))^2 = a^2 + (2 ab) << 64 + (b^2) << 128 /// pub(crate) fn multiply_2_u64_into_u32( dest: &mut [u32], mut idx: usize, a: u64, b: u64 ) { let [aa0, aa1, aa2, aa3] = mul_split_u64_u64(a, a); let [ab0, ab1, ab2, ab3] = mul_split_u64_u64(a, b); let [bb0, bb1, bb2, bb3] = mul_split_u64_u64(b, b); let (carry, r0) = split_u64(dest[idx] as u64 + aa0 as u64); dest[idx] = r0 as u32; idx += 1; let (carry, r1) = split_u64(dest[idx] as u64 + carry + aa1 as u64); dest[idx] = r1 as u32; idx += 1; let (carry, r2) = split_u64(dest[idx] as u64 + carry + aa2 as u64 + ab0 as u64 * 2); dest[idx] = r2 as u32; idx += 1; let (carry, r3) = split_u64(dest[idx] as u64 + carry + aa3 as u64 + ab1 as u64 * 2); dest[idx] = r3 as u32; idx += 1; let (carry, r4) = split_u64(dest[idx] as u64 + carry + ab2 as u64 * 2 + bb0 as u64); dest[idx] = r4 as u32; idx += 1; let (carry, r5) = split_u64(dest[idx] as u64 + carry + ab3 as u64 * 2 + bb1 as u64); dest[idx] = r5 as u32; idx += 1; let (carry, r6) = split_u64(dest[idx] as u64 + carry + bb2 as u64); dest[idx] = r6 as u32; idx += 1; let (carry, r7) = split_u64(dest[idx] as u64 + carry + bb3 as u64); dest[idx] = r7 as u32; _apply_carry_u64(dest, idx + 1, carry); } /// dest += ((b<<64) + a) * ((z<<64) + y) pub(crate) fn _multiply_into_4_u64( dest: &mut [u32], idx: usize, a: u64, b: u64, y: u64, z: u64 ) { let [ay0, ay1, ay2, ay3] = mul_split_u64_u64(a, y); let [az0, az1, az2, az3] = mul_split_u64_u64(a, z); let [by0, by1, by2, by3] = mul_split_u64_u64(b, y); let [bz0, bz1, bz2, bz3] = mul_split_u64_u64(b, z); let (carry, r0) = split_u64(dest[idx + 0] as u64 + (ay0 as u64 ) * 2); dest[idx + 0] = r0 as u32; let (carry, r1) = split_u64(dest[idx + 1] as u64 + carry + (ay1 as u64 ) * 2); dest[idx + 1] = r1 as u32; let (carry, r2) = split_u64(dest[idx + 2] as u64 + carry + (ay2 as u64 + az0 as u64 + by0 as u64 ) * 2); dest[idx + 2] = r2 as u32; let (carry, r3) = split_u64(dest[idx + 3] as u64 + carry + (ay3 as u64 + az1 as u64 + by1 as u64 ) * 2); dest[idx + 3] = r3 as u32; let (carry, r4) = split_u64(dest[idx + 4] as u64 + carry + ( az2 as u64 + by2 as u64 + bz0 as u64) * 2); dest[idx + 4] = r4 as u32; let (carry, r5) = split_u64(dest[idx + 5] as u64 + carry + ( az3 as u64 + by3 as u64 + bz1 as u64) * 2); dest[idx + 5] = r5 as u32; let (carry, r6) = split_u64(dest[idx + 6] as u64 + carry + ( bz2 as u64) * 2); dest[idx + 6] = r6 as u32; let (carry, r7) = split_u64(dest[idx + 7] as u64 + carry + ( bz3 as u64) * 2); dest[idx + 7] = r7 as u32; _apply_carry_u64(dest, idx + 8, carry); } /// dest[idx..] += a ** 2 pub(crate) fn _multiply_1_u64_into_u32( dest: &mut [u32], mut idx: usize, a: u64 ) { let [a0, a1, a2, a3] = mul_split_u64_u64(a, a); let (carry, r0) = split_u64(dest[idx] as u64 + a0 as u64); dest[idx] = r0 as u32; idx += 1; let (carry, r1) = split_u64(dest[idx] as u64 + carry + a1 as u64); dest[idx] = r1 as u32; idx += 1; let (carry, r2) = split_u64(dest[idx] as u64 + carry + a2 as u64); dest[idx] = r2 as u32; idx += 1; let (carry, r3) = split_u64(dest[idx] as u64 + carry + a3 as u64); dest[idx] = r3 as u32; _apply_carry_u64(dest, idx + 1, carry); } /// Evaluate (a + b << 64)^2 and store in dest at location idx pub(crate) fn _multiply_2_u64_into_u32( dest: &mut [u32], mut idx: usize, a: u64, b: u64, ) { let [aa0, aa1, aa2, aa3] = mul_split_u64_u64(a, a); let [ab0, ab1, ab2, ab3] = mul_split_u64_u64(a, b); let [bb0, bb1, bb2, bb3] = mul_split_u64_u64(b, b); let (carry, r0) = split_u64(dest[idx] as u64 + aa0 as u64); dest[idx] = r0 as u32; idx += 1; let (carry, r1) = split_u64(dest[idx] as u64 + carry + aa1 as u64); dest[idx] = r1 as u32; idx += 1; let (carry, r2) = split_u64(dest[idx] as u64 + carry + aa2 as u64 + ab0 as u64 * 2); dest[idx] = r2 as u32; idx += 1; let (carry, r3) = split_u64(dest[idx] as u64 + carry + aa3 as u64 + ab1 as u64 * 2); dest[idx] = r3 as u32; idx += 1; let (carry, r4) = split_u64(dest[idx] as u64 + carry + ab2 as u64 * 2 + bb0 as u64); dest[idx] = r4 as u32; idx += 1; let (carry, r5) = split_u64(dest[idx] as u64 + carry + ab3 as u64 * 2 + bb1 as u64); dest[idx] = r5 as u32; idx += 1; let (carry, r6) = split_u64(dest[idx] as u64 + carry + bb2 as u64); dest[idx] = r6 as u32; idx += 1; let (carry, r7) = split_u64(dest[idx] as u64 + carry + bb3 as u64); dest[idx] = r7 as u32; _apply_carry_u64(dest, idx + 1, carry); } /// Evaluate z * (a + b << 64) and store in dest at location idx pub(crate) fn _multiply_3_u64_into_u32( dest: &mut [u32], mut idx: usize, a: u64, b: u64, z: u64, ) { let [az0, az1, az2, az3] = mul_split_u64_u64(a, z); let [bz0, bz1, bz2, bz3] = mul_split_u64_u64(b, z); let (carry, r0) = split_u64(dest[idx] as u64 + (az0 as u64 ) * 2); dest[idx] = r0 as u32; idx += 1; let (carry, r1) = split_u64(dest[idx] as u64 + carry + (az1 as u64 ) * 2); dest[idx] = r1 as u32; idx += 1; let (carry, r2) = split_u64(dest[idx] as u64 + carry + (az2 as u64 + bz0 as u64) * 2); dest[idx] = r2 as u32; idx += 1; let (carry, r3) = split_u64(dest[idx] as u64 + carry + (az3 as u64 + bz1 as u64) * 2); dest[idx] = r3 as u32; idx += 1; let (carry, r4) = split_u64(dest[idx] as u64 + carry + ( bz2 as u64) * 2); dest[idx] = r4 as u32; idx += 1; let (carry, r5) = split_u64(dest[idx] as u64 + carry + ( bz3 as u64) * 2); dest[idx] = r5 as u32; _apply_carry_u64(dest, idx + 1, carry); } /// dest[idx0..] += (a + (b << 64)) * z pub(crate) fn multiply_thrup_spread_into( dest: &mut [u32], idx0: usize, a: u32, b: u32, z: u32, ) { let a = a as u64; let b = b as u64; let z = z as u64; let az = a * z; let bz = b * z; let (azh, azl) = split_u64(az); let (bzh, bzl) = split_u64(bz); let (carry, r0) = split_u64(dest[idx0 + 0] as u64 + azl * 2); dest[idx0 + 0] = r0 as u32; let (carry, r1) = split_u64(dest[idx0 + 1] as u64 + carry + (azh + bzl) * 2); dest[idx0 + 1] = r1 as u32; let (mut carry, r2) = split_u64(dest[idx0 + 2] as u64 + carry + bzh * 2); dest[idx0 + 2] = r2 as u32; let mut idx = idx0 + 3; while carry != 0 { let (c, overflow) = split_u64(dest[idx] as u64 + carry); dest[idx] = overflow as u32; carry = c; idx += 1; } } /// Multiply two pairs of bigdigits, storing carries into dest, /// pub(crate) fn multiply_thrup_spread_into_wrapped( dest: &mut [u32], idx0: usize, a: u32, b: u32, z: u32, ) { let a = a as u64; let b = b as u64; let z = z as u64; let az = a * z; let bz = b * z; let (azh, azl) = split_u64(az); let (bzh, bzl) = split_u64(bz); let (carry, r0) = split_u64(dest[idx0 + 0] as u64 + azl * 2); dest[idx0 + 0] = r0 as u32; let (carry, r1) = split_u64(dest[idx0 + 1] as u64 + carry + (azh + bzl) * 2); dest[idx0 + 1] = r1 as u32; let (mut carry, r2) = split_u64(dest[idx0 + 2] as u64 + carry + bzh * 2); dest[idx0 + 2] = r2 as u32; let mut idx = idx0 + 3; while carry != 0 { let (c, overflow) = split_u64(dest[idx] as u64 + carry); dest[idx] = overflow as u32; carry = c; idx += 1; } } /// Multiply two pairs of bigdigits, storing carries into dest, /// /// Used for multiplying `(a + b) * (y + z) => (ay + by + az + bz)` /// Where (a,b) and (x,y) pairs are consecutive bigdigits. /// /// Results of the multiplication are stored in 'dest' starting /// with ay at index 'idx' /// pub(crate) fn multiply_quad_spread_into( dest: &mut [u32], idx0: usize, a: u32, b: u32, y: u32, z: u32, ) { let ay = a as u64 * y as u64; let az = a as u64 * z as u64; let by = b as u64 * y as u64; let bz = b as u64 * z as u64; let (ayh, ayl) = split_u64(ay); let (azh, azl) = split_u64(az); let (byh, byl) = split_u64(by); let (bzh, bzl) = split_u64(bz); let (carry, r0) = split_u64(dest[idx0 + 0] as u64 + ayl * 2); dest[idx0 + 0] = r0 as u32; let (carry, r1) = split_u64(dest[idx0 + 1] as u64 + carry + (ayh + azl + byl) * 2); dest[idx0 + 1] = r1 as u32; let (carry, r2) = split_u64(dest[idx0 + 2] as u64 + carry + (azh + byh + bzl) * 2); dest[idx0 + 2] = r2 as u32; let (mut carry, r3) = split_u64(dest[idx0 + 3] as u64 + carry + bzh * 2); dest[idx0 + 3] = r3 as u32; let mut idx = idx0 + 4; while carry != 0 { let (c, overflow) = split_u64(dest[idx] as u64 + carry); dest[idx] = overflow as u32; carry = c; idx += 1; } } /// multiply_quad_spread_into /// pub(crate) fn multiply_quad_spread_into_wrapping( dest: &mut [u32], idx: usize, a: u32, b: u32, y: u32, z: u32, ) { let ay = a as u64 * y as u64; let az = a as u64 * z as u64; let by = b as u64 * y as u64; let bz = b as u64 * z as u64; let (ayh, ayl) = split_u64(ay); let (azh, azl) = split_u64(az); let (byh, byl) = split_u64(by); let (bzh, bzl) = split_u64(bz); let wrap = dest.len(); let mut idx = idx % wrap; let (carry, r0) = split_u64(dest[idx] as u64 + ayl * 2); dest[idx] = r0 as u32; idx = (idx + 1) % wrap; let (carry, r1) = split_u64(dest[idx] as u64 + carry + (ayh + azl + byl) * 2); dest[idx] = r1 as u32; idx = (idx + 1) % wrap; let (carry, r2) = split_u64(dest[idx] as u64 + carry + (azh + byh + bzl) * 2); dest[idx] = r2 as u32; idx = (idx + 1) % wrap; let (mut carry, r3) = split_u64(dest[idx] as u64 + carry + bzh * 2); dest[idx] = r3 as u32; while carry != 0 { idx = (idx + 1) % wrap; let (c, overflow) = split_u64(dest[idx] as u64 + carry); dest[idx] = overflow as u32; carry = c; } } #[cfg(test)] mod test { use super::*; include!("multiplication.tests.rs"); } bigdecimal-0.4.10/src/arithmetic/multiplication.tests.rs000064400000000000000000000772471046102023000214730ustar 00000000000000use paste::paste; mod multiply_scaled_u64_slices_with_prec_into { use super::*; macro_rules! impl_case { ($name:ident: $prec:literal => [$($le_d:literal),*] E $exp:literal) => { impl_case!($name: round=Up; $prec => [$($le_d),*] E $exp); }; ($name:ident: round=$round:ident; $prec:literal => [$($le_d:literal),*] E $exp:literal) => { impl_case!($name: round=$round; $prec => Plus [$($le_d),*] E $exp); }; ($name:ident: round=$round:ident; $prec:literal => $sign:ident [$($expected:literal),*] E $exp:literal) => { #[test] fn $name() { let a = input_a(); let b = input_b(); let prec = NonZeroU64::new($prec).unwrap(); let expected: &[u64] = &[$($expected),*]; let expected_scale = -$exp; let rounding = NonDigitRoundingData { mode: RoundingMode::$round, sign: Sign::$sign, }; let mut product = WithScale::default(); multiply_scaled_u64_slices_with_prec_into( &mut product, a.as_digit_slice(), b.as_digit_slice(), prec, rounding ); assert_eq!(&product.value.digits[..], &expected[..]); assert_eq!(product.scale, expected_scale); } }; } mod case_1667660160137446952e158 { use super::*; fn input_a() -> WithScale> { WithScale { scale: 34, value: DigitVec::from_vec(vec![ 16175263208544711346, 5279606946643537445, 15341572592040251541, 10541804148642044343, 7522665456306621740, 13427633752471237939, 16469249152156353442, 11787750781150891403, 3583949032441389106, 18383297448742447850, 365519312995810676, ]), } } mod times_2d998213en173 { use super::*; fn input_b() -> WithScale> { WithScale { scale: 272, value: DigitVec::from_vec(vec![ 1344009339610453499, 6464650240578252661, 13739370975302393952, 1107949409989368443, 12288971738008765224, 1403 ]), } } impl_case!(prec19_roundup: round=Up; 19 => [5000000000000000001] E -15); impl_case!(prec20_roundup: round=Up; 20 => [13106511852580896769, 2] E -16); impl_case!(prec100_roundup: round=Up; 100 => [1, 6059390473091416064, 5120748075179647364, 14006871066438625056, 15461642991872345491, 2340] E -96); impl_case!(neg_prec100_roundceiling: round=Ceiling; 100 => Minus [0, 6059390473091416064, 5120748075179647364, 14006871066438625056, 15461642991872345491, 2340] E -96); impl_case!(neg_prec100_roundfloor: round=Floor; 100 => Minus [1, 6059390473091416064, 5120748075179647364, 14006871066438625056, 15461642991872345491, 2340] E -96); } mod times_5996425554en186 { use super::*; fn input_b() -> WithScale> { WithScale { scale: 204, value: DigitVec::from_vec( vec![12019064456476625820, 325066880] ), } } impl_case!(prec1_roundup: round=Up; 1 => [1] E 0); impl_case!(prec1_rounddown: round=Down; 1 => [9] E -1); impl_case!(prec1_roundfloor: round=Floor; 1 => [9] E -1); impl_case!(neg_prec1_rounddown: round=Down; 1 => Minus [9] E -1); impl_case!(neg_prec1_roundfloor: round=Floor; 1 => Minus [1] E 0); impl_case!(prec10_roundup: round=Floor; 10 => Minus [1000000000] E -9); impl_case!(prec25_roundup: round=Floor; 25 => Minus [2003764205206896640, 54210] E -24); impl_case!(prec40_roundup: round=Up; 40 => [13399721896776114178, 7145508105175220139, 29] E -40); } mod times_7303919561276644672e10 { use super::*; fn input_b() -> WithScale> { WithScale { scale: 7, value: DigitVec::from_vec( vec![16568107915372457172, 39594627279977552] ), } } impl_case!(prec1_up: round=Up; 1 => [2] E 205); impl_case!(prec1_down: round=Down; 1 => [1] E 205); impl_case!(prec11_up: round=Up; 11 => [12180455666] E 195); impl_case!(prec25: 25 => [7055331922361162211, 66030] E 181); impl_case!(prec_30_up: 30 => [571648947000381622, 6603038247] E 176); impl_case!(prec_31_up: 31 => [5716489470003816211, 66030382470] E 175); impl_case!(prec_57_up: 57 => [3586467374344137641, 14971304827359975165, 357951420621793766] E 149); impl_case!(prec_75_up: 75 => [16970166308972310451, 15246513073646694077, 13267213422529722744, 19404585394121069] E 131); } } mod random_values { use super::*; fn input_a() -> WithScale { let a = vec![ 1745623865429447471, 9152528756446785169, 791242510259261833, 8695454801466577396, 8392994416015036890, 2912771882945679798, 8993891992610859856, 8294679885144779824, 8631634693823981953, 366928013, ]; WithScale { value: BigDigitVec::from_vec(a), scale: 100, } } fn input_b() -> WithScale { let b = vec![ 518171251856216712, 8211715648977239115, 1585852536764360977, 1552672896608399639, 1044291249247, ]; WithScale { value: BigDigitVec::from_vec(b), scale: -5, } } impl_case!(prec100: 100 => [ 7841754692876239913, 2960052148898606502, 16409584969160271562, 16913806906493283056, 14019529503395454758, 513 ] E 77); impl_case!(prec10_rd: round=Down; 10 => [ 1097384700 ] E 167); impl_case!(prec20_rd: round=Down; 20 => [ 10973847000387492259 ] E 157); impl_case!(prec20_ru: round=Up; 20 => [ 10973847000387492260 ] E 157); impl_case!(prec45: 45 => [ 14618765252943857298, 6989353086943465649, 322492 ] E 132); impl_case!(prec46: 46 => [ 17060444013471711666, 14553298648306001649, 3224923 ] E 131); } } mod multiply_at_product_index { use super::*; macro_rules! impl_case { ($name:ident: $idx:literal => $expected:expr) => { #[test] fn $name() { let (a, b) = test_input(); let a = BigDigitSliceP19::from_slice(&a); let b = BigDigitSliceP19::from_slice(&b); let mut product = DigitVec::::new(); let expected: &[u64] = &$expected; multiply_at_product_index(&mut product, a, b, $idx); assert_eq!(product.digits, expected); } }; } mod random_values { use super::*; fn test_input() -> (Vec, Vec) { let a = vec![ 1745623865429447471, 9152528756446785169, 791242510259261833, 8695454801466577396, 8392994416015036890, 2912771882945679798, 8993891992610859856, 8294679885144779824, 8631634693823981953, 366928013, ]; let b = vec![ 518171251856216712, 8211715648977239115, 1585852536764360977, 1552672896608399639, 1044291249247, ]; (a, b) } impl_case!(case_1: 1 => [ 3259170168870572493, 8530725771486096200, 2353601569174537990, 9915907985447408257, 5505012768436728039, 3337388859546710366, 1787670230149175286, 7565280555772427422, 7309104897441821141, 4201853743352582046, 9605931707432557799, 9324155135517901886, 3179713980940485874, 38 ]); impl_case!(case_3: 3 => [ 4519975091742652829, 9915907985447408256, 5505012768436728039, 3337388859546710366, 1787670230149175286, 7565280555772427422, 7309104897441821141, 4201853743352582046, 9605931707432557799, 9324155135517901886, 3179713980940485874, 38 ]); impl_case!(case_9: 9 => [ 8171925425020376989, 4201853743352582045, 9605931707432557799, 9324155135517901886, 3179713980940485874, 38 ]); impl_case!(case_12: 12 => [ 7983943745001026698, 3179713980940485874, 38 ]); impl_case!(case_20: 20 => []); } } mod multiply_big_int_with_ctx { use super::*; macro_rules! impl_case { (full => $expected:literal) => { #[test] fn case_full() { let (x, y) = test_input(); let product = &x * &y; let expected: BigInt = $expected.parse().unwrap(); assert_eq!(&expected, &product); } }; ($prec:literal => $expected:literal E $exp:literal) => { paste! { #[test] fn [< case_prec $prec >] () { impl_case!( IMPL; ctx=Context::default().with_prec($prec); $expected; $exp ); } } }; ($prec:literal; $mode:ident => $expected:literal E $exp:literal) => { paste! { #[test] fn [< case_prec $prec _ $mode:lower >]() { impl_case!( IMPL; ctx=Context::default().with_rounding_mode(RoundingMode::$mode).with_prec($prec); $expected; $exp ); } } }; ($prec:literal; $($modes:ident),+ => $expected:literal E $exp:literal) => { $( impl_case!($prec; $modes => $expected E $exp); )* }; (IMPL; ctx=$ctx:expr; $expected:literal; $exp:literal) => { let (x, y) = test_input(); let ctx = $ctx.unwrap(); let product = multiply_big_int_with_ctx(&x, &y, ctx); let expected: BigInt = $expected.parse().unwrap(); let scale = -$exp; assert_eq!(&expected, &product.value); assert_eq!(&scale, &product.scale); }; } mod mul_577874872717e492_696712038e285 { use super::*; fn test_input() -> (BigInt, BigInt) { let x: BigInt = "577874872717466911184559916156758198495131305219358809343652669536302387743158062880956367761473177845712351639985492473123959095758451817231985325403278703100241171849679780394380997111752306496891336078616237486336807931580623365870368160556723018500080769313066709500174011587939745841025646291922884710337974681230011250190261422246454991091897190225976651017177719025146752407491035501139104790891684620162820417602920652689929206945524922873810759445524737158705885775589194963686168193817138671875".parse().unwrap(); let y: BigInt = "696712038660547059904752779034165119484624188403362872193018065005292090954487758438349971006124876297418423724096428714200094204277821355374358649621264188134962601815256767310343261823948242351360751280910536781247104655969073243119218479973070589731361603163735999605615737734639873901461504".parse().unwrap(); (x, y) } impl_case!(100; Down => "4026123806616905180553157364566020245817156933504926464873554931196880658239704482799527614035787776" E 698); impl_case!(20; Down => "40261238066169051805" E 778); } mod mul_1442862119e445_1049464e105 { use super::*; fn test_input() -> (BigInt, BigInt) { let x: BigInt = "14428621197889752189861398972981082461843826128512116303033203450866726426082853906596666646209600245865382634277766055876367040002473414960534339870779684891851540020597214991380071631960919603045037521801802725511393621544601218214902662462163496096667869677784522965589318809320143842055299565296240744974377213638202218555750884767181679713147685927591605307661717624963762005955819493848581352190387436454778284644628882915640133433043956756591796875".parse().unwrap(); let y: BigInt = "1049464598544894921302784839734515848195965967618699631485860068380390543981052363225912818001120911046454804480".parse().unwrap(); (x, y) } impl_case!(20; HalfEven => "15142327152999729642" E 546); impl_case!(138; HalfDown => "151423271529997296423843423920943952557791563643246327643459830966880329966739641792530818647522102274133154353120322001711481566221946243" E 428); impl_case!(246; Up, HalfUp => "151423271529997296423843423920943952557791563643246327643459830966880329966739641792530818647522102274133154353120322001711481566221946242709348400715315872658516242116494741084148721184917688258189092970640993174313848612655419856309890747070313" E 320); impl_case!(246; Down, HalfDown, HalfEven => "151423271529997296423843423920943952557791563643246327643459830966880329966739641792530818647522102274133154353120322001711481566221946242709348400715315872658516242116494741084148721184917688258189092970640993174313848612655419856309890747070312" E 320); impl_case!(247; Up, Down => "1514232715299972964238434239209439525577915636432463276434598309668803299667396417925308186475221022741331543531203220017114815662219462427093484007153158726585162421164947410841487211849176882581890929706409931743138486126554198563098907470703125" E 319); impl_case!(248; Up, Down => "15142327152999729642384342392094395255779156364324632764345983096688032996673964179253081864752210227413315435312032200171148156622194624270934840071531587265851624211649474108414872118491768825818909297064099317431384861265541985630989074707031250" E 318); impl_case!(357; Down => "151423271529997296423843423920943952557791563643246327643459830966880329966739641792530818647522102274133154353120322001711481566221946242709348400715315872658516242116494741084148721184917688258189092970640993174313848612655419856309890747070312500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" E 209); } mod mul_11552262607819902e131_75e161 { use super::*; fn test_input() -> (BigInt, BigInt) { let x: BigInt = "1155226260781990200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".parse().unwrap(); let y: BigInt = "7500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".parse().unwrap(); (x, y) } impl_case!(20 => "86641969558649265000" E 290); impl_case!(18; HalfUp => "866419695586492650" E 292); impl_case!(17; HalfUp, HalfDown => "86641969558649265" E 293); impl_case!(16; Up, HalfUp => "8664196955864927" E 294); impl_case!(16; Down, HalfDown, HalfEven => "8664196955864926" E 294); impl_case!(15; Up, HalfDown => "866419695586493" E 295); impl_case!(15; Down => "866419695586492" E 295); impl_case!( 3; HalfUp => "866" E 307); } mod mul_2301346222e107_14293213e315 { use super::*; fn test_input() -> (BigInt, BigInt) { let x: BigInt = "230134622236549555995211986626222699902919552403311068655782487235360869740373750138395520899795192776856789295000000".parse().unwrap(); let y: BigInt = "14293213600958985303333846898378944669728091790434135672846064625014252175269303162751477769546102012233954333273726511104485055758813349716438744379331517132722718015116165694607959258435272025702738339275667597501313358033107443840555382841970678973851997248262639615206455939322314712306500000000000000000000000000000000".parse().unwrap(); (x, y) } impl_case!(1 => "3" E 438); impl_case!(10 => "3289363313" E 429); impl_case!(20 => "32893633126030082513" E 419); impl_case!(401 => "32893633126030082513378632456028104243338158146601751534822570641115861940893690474203736021657204584394456560452273117013862292944834269220913901434456366640765512794407601501204644375698772310462659595240672712968083946415944676232524453019368460583076233422452053267394081654933088569072574309446551869537537085955808336137944176420693881753901339121561334586231165213326029020686758979692139589175" E 38); impl_case!(400; HalfUp => "3289363312603008251337863245602810424333815814660175153482257064111586194089369047420373602165720458439445656045227311701386229294483426922091390143445636664076551279440760150120464437569877231046265959524067271296808394641594467623252445301936846058307623342245205326739408165493308856907257430944655186953753708595580833613794417642069388175390133912156133458623116521332602902068675897969213958918" E 39); impl_case!(400; HalfDown => "3289363312603008251337863245602810424333815814660175153482257064111586194089369047420373602165720458439445656045227311701386229294483426922091390143445636664076551279440760150120464437569877231046265959524067271296808394641594467623252445301936846058307623342245205326739408165493308856907257430944655186953753708595580833613794417642069388175390133912156133458623116521332602902068675897969213958917" E 39); } mod mul_166282988e757_855704757e288 { use super::*; fn test_input() -> (BigInt, BigInt) { let x: BigInt = "1662829881972302555130573804034884736045567192245210098539333943847359516964532887814910330238584574704591142597582120739098300776070255016531228502052315027932433758655554089934478913134076538917555237055311466963257200943418192284685329544412527781851150111516400149208425751400577475249704818681525213682644230996369594895101870162749874014287967075708189893449815333186508386746072349175785274400940465234953370696338639401851764570625527530834473094592285942335138352231629223479010378029739170207319201385183107178796700474330961290205720379495017762115091196226436689486111860406277126830834375106428374156802498831754786978409114271376697671477362897657305451012544150393117399631804227698370258868601667565428070820650330308154707381618209183216094970703125".parse().unwrap(); let y: BigInt = "855704757901450759869356338513283551486583906378815084661323942969666040804246301726741288371813738860776552307977511102966634857016690379580472911872149121752146077285669707976656886280326152572122998172317660237359659093011810926589974967764428889136711853677544671180201059446857211098370670592".parse().unwrap(); (x, y) } impl_case!(132 => "142289144158440709930589101331424815642676467582494920860869705909839132157013788030340030454912181312465691007673740386962890625000" E 931); impl_case!(63 => "142289144158440709930589101331424815642676467582494920860869706" E 1000); impl_case!(30 => "142289144158440709930589101331" E 1033); impl_case!(20 => "14228914415844070993" E 1043); impl_case!(19 => "1422891441584407099" E 1044); } // test (2^5000-1) * (2^1500-1) mod mul_2p5000m1_2p1501m1 { use super::*; fn test_input() -> (BigInt, BigInt) { let x: BigInt = "141246703213942603683520966701614733366889617518454111681368808585711816984270751255808912631671152637335603208431366082764203838069979338335971185726639923431051777851865399011877999645131707069373498212631323752553111215372844035950900535954860733418453405575566736801565587405464699640499050849699472357900905617571376618228216434213181520991556677126498651782204174061830939239176861341383294018240225838692725596147005144243281075275629495339093813198966735633606329691023842454125835888656873133981287240980008838073668221804264432910894030789020219440578198488267339768238872279902157420307247570510423845868872596735891805818727796435753018518086641356012851302546726823009250218328018251907340245449863183265637987862198511046362985461949587281119139907228004385942880953958816554567625296086916885774828934449941362416588675326940332561103664556982622206834474219811081872404929503481991376740379825998791411879802717583885498575115299471743469241117070230398103378615232793710290992656444842895511830355733152020804157920090041811951880456705515468349446182731742327685989277607620709525878318766488368348965015474997864119765441433356928012344111765735336393557879214937004347568208665958717764059293592887514292843557047089164876483116615691886203812997555690171892169733755224469032475078797830901321579940127337210694377283439922280274060798234786740434893458120198341101033812506720046609891160700284002100980452964039788704335302619337597862052192280371481132164147186514169090917191909375".parse().unwrap(); let y: BigInt = "35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150406795437517399294548941469959754171038918004700847889956485329097264486802711583462946536682184340138629451355458264946342525383619389314960644665052551751442335509249173361130355796109709885580674313954210217657847432626760733004753275317192133674703563372783297041993227052663333668509952000175053355529058880434182538386715523683713208549375".parse().unwrap(); (x, y) } impl_case!(100 => "4954180389441794407302644533158844937036173071799942385207702899881096950794929284226174201155309760" E 1857); impl_case!(70 => "4954180389441794407302644533158844937036173071799942385207702899881097" E 1887); impl_case!(20 => "49541803894417944073" E 1937); } mod multiply_313313e185_140912e85 { use super::*; fn test_input() -> (BigInt, BigInt) { let x: BigInt = "31331330514777647459696918012218766637269396231379435058341584170846149718531941093035596483272466942484919002494751588025494203950111183556196762802239021663296916615390846043521157975900649".parse().unwrap(); let y: BigInt = "1409125393389843319552855599302577071349036214812589000980540875883362915766473073232671889".parse().unwrap(); (x, y) } impl_case!(full => "44149773437063254678149469396251230458443452710019771114377331920312228495036605502543146558201981056772851870606187717471634519393139631393769297684773531284154562671396651882745113413784696354015721073630190690162770887707923095632780007819514677121000367593109419444597479155961"); impl_case!(100 => "4414977343706325467814946939625123045844345271001977111437733192031222849503660550254314655820198106" E 181); impl_case!(50 => "44149773437063254678149469396251230458443452710020" E 231); impl_case!(21 => "441497734370632546781" E 260); } mod mul_354436071780069e151_282138326095801e70 { use super::*; fn test_input() -> (BigInt, BigInt) { let x: BigInt = "3544360717800690051921825754840028412915557760215486673759084471433756826848643934952495657908167389640789167410480517347773985344060322134315971203024120535921247142".parse().unwrap(); let y: BigInt = "2821383260958014531084804730393168953719437088977599878666724657220634716408631037763".parse().unwrap(); (x, y) } impl_case!(200; Up => "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999979587838286624448431722853801267006" E 50); impl_case!(200; Down => "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999979587838286624448431722853801267005" E 50); impl_case!(166; Up => "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999998" E 84); impl_case!(166; Down => "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999997" E 84); impl_case!(165; Up => "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" E 86); impl_case!(165; Down => "999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" E 85); impl_case!(42; Up => "100000000000000000000000000000000000000000" E 209); impl_case!(22; Up => "1000000000000000000000" E 229); impl_case!(21; Up => "100000000000000000000" E 230); impl_case!(20; Up => "10000000000000000000" E 231); impl_case!(19; Up => "1000000000000000000" E 232); impl_case!(12; Up => "100000000000" E 239); impl_case!(12; Down => "999999999999" E 238); impl_case!(2; Up => "10" E 249); impl_case!(2; Down => "99" E 248); impl_case!(1; Up, HalfUp => "1" E 250); impl_case!(1; Down => "9" E 249); } mod mul_3721418e448_3844674e161 { use super::*; fn test_input() -> (BigInt, BigInt) { let x: BigInt = "37214180020990129688144525415958680174157975522481928636541900907279612101437934903263895850798267657684166647521832553912867028735643169656904261854440137332351057065885513562123737325309196016024433700918100990040278606068777262035069231336055867161206731423272839919925319426271071135470308154818218588125994382305796706103307807638138902394400413759405500315832312273461261134673346351894542208780520017757692703697092184711436857469379901885986328125".parse().unwrap(); let y: BigInt = "384467472657945478705050171808793258461219095507172038645145218810507057013081321321499154743364560076819504633305258370960191863566109907922325021911311899034388627258125176177530017308946900981633538093921103514946225947524282186623225866254314533377160053778776276453031176006567736506050524284200740234201681989688527171382167496044598504125969423204217194885709731987591265467004291805188733436497695584275662479958826872492302565650006868261814480548258209741016215533270514872064920715433587381471128142127411378792338183702243894864240468654283770230621234327560844588972472126092496338279872812038026604640358131717471991285825660709098949913655676881776223568791337070502357370402925535826378792284995488461006043177936586374698890722356736660003662109375".parse().unwrap(); (x, y) } impl_case!(1220 => "14307641739707883586679338985784075376978599376076587159440407707473484422913380008679767889422355347578618773517358618682873816807001368824338399142290429730889921795132627329720311739245335457279882660403134178519487192193894827422017154794231967246548713182248254712192749435152248607256549045476459086684404679865181612177150422506682419296142751964295148026282623865246096746974909857474439409542650897431239188074724043848310873968922165900982577988822068956986831441597090874147542405989083220921853122209746471544669432201826149806457043393719329728030519620309220466905001009022724582301547918511296250822446396192324003728354373460047809727056243017571910340832631321081615757824717334420837535928747492488405758229871707378866111943107064677309884245984942614408304014573934636656429274910312463230088178109721849404398091245972145748205556337972593506762958354058055515482983023700007919157035627908661458407216568244912244912595573815702329952766665565695461070495291089051793343278543261429000685884437880347246913152237805580594025316169462092558252280687656044981784943452157349160827416439182889565322019088971898689733394885908687909675808992617947650750136428902947738350803774665109813213348388671875" E 0); } } mod test_multiply_quad_spread_into { use super::*; macro_rules! impl_case { ( wrapping: $($toks:tt)* ) => { impl_case!(multiply_quad_spread_into_wrapping; $($toks)*); }; ( $func:ident; $s:literal @ $n:literal, [ $a:literal, $b:literal, $y:literal, $z:literal] => $expected:expr ) => { paste!{ #[test] fn [< case_ $n _ $a _ $b _ $y _ $z >]() { let mut result = vec![0; $s]; $func(&mut result, $n, $a, $b, $y, $z); let expected = &$expected; assert_eq!(expected, result.as_slice()); } } }; ( $($toks:tt)* ) => { impl_case!(multiply_quad_spread_into; $($toks)*); }; } impl_case!( 8 @ 2, [2559712337, 684026673, 1163340730, 1823138616] => [0u32, 0, 3001179060, 4203670869, 1059648540, 580714756, 0, 0]); impl_case!( 6 @ 1, [4294967295, 4294967295, 4294967295, 4294967295] => [0u32, 2, 0, 4294967292, 4294967295, 1]); impl_case!( wrapping: 8 @ 6, [2559712337, 684026673, 1163340730, 1823138616] => [1059648540u32, 580714756, 0, 0, 0, 0, 3001179060, 4203670869]); } #[cfg(all(test, property_tests))] mod props { use super::*; use proptest::{self as pt}; use proptest::prelude::*; use num_traits::FromPrimitive; fn random_f64() -> pt::num::f64::Any { use proptest::num::f64::*; NORMAL | SUBNORMAL | ZERO | NEGATIVE } fn rounding_modes() -> impl Strategy { prop_oneof![ Just(RoundingMode::Down), Just(RoundingMode::Up), Just(RoundingMode::HalfEven), ] } proptest! { #![proptest_config(ProptestConfig::with_cases(10_000))] #[test] fn test_multiply_f64_decimals_with_context( a in random_f64(), b in random_f64(), prec in 1..6000u64, mode in rounding_modes() ) { let prec = NonZeroU64::new(prec).unwrap(); let a: BigDecimal = BigDecimal::from_f64(a).unwrap(); let b: BigDecimal = BigDecimal::from_f64(b).unwrap(); let a_times_b = &a * &b; let a_times_b_rounded = a_times_b.with_precision_round(prec, mode); let mut dest = BigDecimal::default(); let ctx = Context::new(prec, mode); super::multiply_decimals_with_context(&mut dest, &a, &b, &ctx); prop_assert_eq!(a_times_b_rounded, dest) } } } bigdecimal-0.4.10/src/arithmetic/pow.rs000064400000000000000000000242451046102023000160700ustar 00000000000000//! pow implementation use stdlib::num::NonZeroU64; use crate::*; use super::log10; use super::multiplication::{ multiply_decimals_with_context, multiply_slices_with_prec_into_p19_z, }; use bigdigit::digitvec::{DigitVec, DigitSlice}; use bigdigit::radix::{RadixType, RadixPowerOfTen, RADIX_u64, RADIX_10p19_u64}; use bigdigit::endian::{Endianness, LittleEndian}; use arithmetic::multiplication::mul_scaled_slices_truncating_into; /// Compute bd**exp using exponentiation by squaring algorithm, while maintaining the /// precision specified in ctx (the number of digits would otherwise explode). /// /// Algorithm comes from https://en.wikipedia.org/wiki/Exponentiation_by_squaring pub(crate) fn impl_powi_with_context<'a>( bd: impl Into>, exp: i64, ctx: &Context, ) -> BigDecimal { powi_with_context(bd.into(), exp, ctx) } /// Calculate BigDecimalRef `bd` to power of signed integer, using context /// to set precision fn powi_with_context( bd: BigDecimalRef, exp: i64, ctx: &Context, ) -> BigDecimal { match exp.cmp(&0) { Ordering::Equal => BigDecimal::one(), Ordering::Greater => pow_u64_with_context(bd, exp as u64, ctx), Ordering::Less => { if exp == -1 { return bd.inverse_with_context(&ctx); } // create truncating "double wide" context for inverting let inv_ctx = Context::new_truncating( (ctx.precision().get() * 2) .max((bd.digits.bits() as f64 * LOG10_2 * 2.0).ceil() as u64) .max(38) // always at least 2 u64 'big-digits' wide ); let inverted_bd = bd.inverse_with_context(&inv_ctx); // requested context when taking the power of inverted value pow_u64_with_context(inverted_bd.to_ref(), unsigned_abs(exp), &ctx) } } } /// Calculate BigDecimalRef `bd` to power of positive integer, using context /// to set precision /// /// The case where exp==0 (therefore result is 1) must be handled /// before calling this pow impl fn pow_u64_with_context( bd: BigDecimalRef, exp: u64, ctx: &Context, ) -> BigDecimal { type R = RADIX_10p19_u64; debug_assert_ne!(exp, 0); if exp == 1 { return ctx.round_decimal_ref(bd); } // bd^exp guaranteed to fit within precision: use roundless pow if (bd.digits.bits() as f64 * exp as f64) < (ctx.precision().get() as f64 * LOG2_10) { return pow_u64_no_context(bd, exp); } let mut tmp = Vec::new(); let bd_as_base10p19 = DigitVec::from_biguint_using_tmp(bd.digits, &mut tmp); debug_assert_eq!(tmp.len(), 0); let mut prec = RunningPrecision::new( bd_as_base10p19.as_digit_slice(), NonZeroU64::new(exp).unwrap(), ctx.precision(), ); // Count the number of multiplications we're going to perform, one per "1" binary digit // in exp, and the number of times we can divide exp by 2. let mut n = exp; // factor product into bdⁿ => bdˣ·bdʸ where x is largest // power of two which fits into 'n' let final_x_pow = 1 << (63 - n.leading_zeros() as u64); let final_y_pow = n - final_x_pow; // if final_y_pow == 0, then 'y' digits is never used and // we will use x*x as final multiplication, otherwise // final product is x*y let final_x_times_y = final_y_pow != 0; let mut y_vec = Vec::new(); if final_x_times_y { y_vec.reserve(bd_as_base10p19.len()); y_vec.push(1); } else { // no final multiplication by y, so decrease number of squarings // by one so we do (x/2 * x/2) rather than (x * 1) n >>= 1; } let mut digits_x = WithScale { value: bd_as_base10p19, scale: 0, }; let mut digits_y = WithScale { value: DigitVec::from_vec(y_vec), scale: 0, }; // temporary storage for results of multiplications let mut prod = WithScale { value: DigitVec::from_vec(tmp), scale: 0, }; // tracks if skipped insignificant digits are zero for final rounding let mut trailing_zeros = true; while n > 1 { if n % 2 == 1 { // 'prod' is now product y * x, swap with 'y' let skipped_bigdigit_count = mul_scaled_slices_truncating_into( &mut prod, digits_y.as_digit_slice(), digits_x.as_digit_slice(), prec.next(), ); trailing_zeros = trailing_zeros && { let skipped = skipped_bigdigit_count.saturating_sub(digits_y.value.len() - 1); digits_x.value.least_n_are_zero(skipped) } && { let skipped = skipped_bigdigit_count.saturating_sub(digits_x.value.len() - 1); digits_y.value.least_n_are_zero(skipped) }; // now 'digits_y <- prod = digits_y * digits_x' stdlib::mem::swap(&mut prod, &mut digits_y); } // TODO: optimized algorithm for squaring a scaled digitslice to requested precision let skipped_bigdigits = mul_scaled_slices_truncating_into( &mut prod, digits_x.as_digit_slice(), digits_x.as_digit_slice(), prec.next(), ); // detect if truncated digits were non-zero trailing_zeros = trailing_zeros && { let skipped = skipped_bigdigits.saturating_sub(digits_x.value.len() - 1); digits_x.value.least_n_are_zero(skipped) }; // digits_x <- prod = digits_x * digits_x stdlib::mem::swap(&mut prod, &mut digits_x); // shift lowest bit out of multiplication counter n >>= 1; } let sign = if exp % 2 == 0 { Sign::Plus } else { bd.sign() }; let rounding = crate::rounding::NonDigitRoundingData { mode: ctx.rounding_mode(), sign: sign, }; prod.value.clear(); prod.scale = 0; let x_slice = digits_x.value.as_digit_slice(); let y_slice = if final_x_times_y { digits_y.value.as_digit_slice() } else { // raised to a power-of-two: y-slice was never touched so // we reuse x-slice here for final multiplication debug_assert_eq!(digits_y.value.digits.capacity(), 0); digits_y.scale = digits_x.scale; x_slice }; multiply_slices_with_prec_into_p19_z( &mut prod, x_slice, y_slice, ctx.precision(), rounding, trailing_zeros, ); let mut scale = bd.scale * exp as i64 + prod.scale; scale += (digits_x.scale + digits_y.scale) * R::DIGITS as i64; let int_val = BigInt::from_biguint(sign, prod.value.into_biguint()); BigDecimal::new(int_val, scale) } /// Simple implementation of exponentiation-by-squaring, /// with no precision/rounding involved fn pow_u64_no_context(bd: BigDecimalRef, exp: u64) -> BigDecimal { debug_assert_ne!(exp, 0); if exp == 1 { return bd.to_owned(); } let mut x = bd.digits.clone(); let mut y: BigUint = 1u8.into(); let mut n = exp; while n > 1 { if n % 2 == 1 { y *= &x; } x = x.pow(2u8); n >>= 1; } // final product let p = x * y; let sign = if exp % 2 == 0 { Sign::Plus } else { bd.sign() }; let scale = bd.scale * exp as i64; let int_val = BigInt::from_biguint(sign, p); BigDecimal::new(int_val, scale) } #[cfg(not(has_unsigned_abs))] fn unsigned_abs(n: i64) -> u64 { if n != i64::MIN { n.abs() as u64 } else { (i64::MIN as i128).abs() as u64 } } #[cfg(has_unsigned_abs)] #[allow(clippy::incompatible_msrv)] fn unsigned_abs(n: i64) -> u64 { n.unsigned_abs() } /// Struct housing the 'margin' information for calculating the required /// precision while doing sequential multiplications for pow /// /// Currently uses a naive scheme: calculating the widest required /// margin, and multiplying the number of multiplications by that width. /// Then we linearly decrease the margin so we end up near the requested /// precision by the time we get to the final product. /// struct RunningPrecision { /// Minimum precision min: u64, /// Current margin margin: u64, /// number of digits to decrease each time `next()` is called margin_per_mul: u64, } impl RunningPrecision { /// Create from requiring 'prec' digits of precision of digits^exp fn new<'a, R: RadixPowerOfTen, E: Endianness>( digits: DigitSlice<'a, R, E>, exp: NonZeroU64, prec: NonZeroU64, ) -> Self { // number of big-digits required to fit requested precision, plus a few // extra for guaranteed rounding digits let prec_bigdigit_count = R::divceil_digit_count(prec.get() as usize + 3) as u64; // length of 'digits' in big digits (floating-point) let digit_count_f = digits.count_decimal_digits() as f64 ; let count_squarings = 63 - exp.get().leading_zeros(); let count_non_squarings = exp.get().count_ones() - 1; // total number of multiplications let muls = (count_non_squarings + count_squarings) as u64; // aⁿ => aˣ·aʸ, n = x+y let max_partial_pow = { let x = 1 << count_squarings; let y = exp.get() - x; (x / 2).max(y) }; // number of digits of multiplicand in the final product let max_width_digits_f = digit_count_f * max_partial_pow as f64; // length in digits of kmaximum sum of digits let diag_sum_digit_len = 2.0 * log10(R::max().to_f64().unwrap()) + log10(max_width_digits_f); let diag_sum_bigdigit_len = R::divceil_digit_count(diag_sum_digit_len.ceil() as usize) as u64; let margin_per_mul = diag_sum_bigdigit_len + 1; Self { min: prec_bigdigit_count, margin: (muls + 1) * margin_per_mul, margin_per_mul: margin_per_mul, } } /// update margin and return precision fn next(&mut self) -> u64 { self.margin = self.margin.saturating_sub(self.margin_per_mul); self.margin + self.min } } #[cfg(test)] mod test { use super::*; include!("pow.tests.rs"); } bigdecimal-0.4.10/src/arithmetic/pow.tests.rs000064400000000000000000000260231046102023000172250ustar 00000000000000use paste::paste; #[allow(non_snake_case)] mod powi_with_context { use super::*; macro_rules! impl_cases { ( pow= - $pow:literal : $( prec=$prec:literal, round=$($round:ident),+ => $expected:literal ; )+ ) => { $( paste!{ impl_cases!([]; -$pow; $($round),*; $prec; $expected); } )* }; ( pow=$pow:literal : $( prec=$prec:literal, round=$($round:ident),+ => $expected:literal ; )+ ) => { $( paste!{ impl_cases!([]; $pow; $($round),*; $prec; $expected); } )* }; ($name:ident; $pow:literal; $round:ident; $prec:literal; $expected:literal) => { paste!{ #[test] fn [< $name _prec $prec _round_ $round >]() { let n = test_input(); let prec = $prec; let exp = $pow; let ctx = Context::default() .with_rounding_mode(RoundingMode::$round) .with_prec(prec).unwrap(); let value = n.powi_with_context(exp, &ctx); let expected: BigDecimal = $expected.parse().unwrap(); assert_eq!(value, expected); assert_eq!(value.scale, expected.scale); } } }; ($name:ident; $pow:literal; $($round:ident),+; $prec:literal; $expected:literal) => { $( impl_cases!($name; $pow; $round; $prec; $expected); )* }; } mod case_999en3 { use super::*; fn test_input() -> BigDecimal { "0.999".parse().unwrap() } impl_cases!( pow=100 : prec=1, round=Up => "1"; prec=1, round=Down => "0.9"; prec=2, round=Up => "0.91"; prec=2, round=Down => "0.90"; prec=10, round=Up => "0.9047921472"; ); impl_cases!( pow=1001 : prec=30, round=Up => "0.367327729346193080582179333082"; prec=38, round=Up => "0.36732772934619308058217933308124088263"; ); impl_cases!( pow=30_000_000 : prec=1, round=Up => "5E-13036"; prec=1, round=Down => "4E-13036"; prec=2, round=Down => "4.4E-13036"; prec=20, round=Up => "4.4338344072941502620E-13036"; ); } mod case_1d5319977452724413736 { use super::*; fn test_input() -> BigDecimal { "1.5319977452724413736".parse().unwrap() } impl_cases!( pow=1: prec=5, round=Up => "1.5320"; prec=5, round=Down => "1.5319"; ); impl_cases!( pow=580: prec=5, round=Up => "2.8166E+107"; prec=5, round=Down => "2.8165E+107"; ); impl_cases!( pow=-580: prec=5, round=Up => "3.5505E-108"; prec=5, round=Down => "3.5504E-108"; ); } mod case_neg1040582726326750d5484 { use super::*; fn test_input() -> BigDecimal { "-1040582726326750.5484".parse().unwrap() } impl_cases!( pow=4: prec=19, round=Up, Ceiling => "1.172482715963826257E+60"; prec=19, round=Down, HalfEven => "1.172482715963826256E+60"; ); impl_cases!( pow=-51: prec=19, round=Up, Floor => "-1.314900138431188004E-766"; prec=19, round=Down, Ceiling => "-1.314900138431188003E-766"; ); } mod case_4d135846964 { use super::*; fn test_input() -> BigDecimal { "4.135846964236207374549487108400332686443027446631549764347102855558635985583587468810645966176878292".parse().unwrap() } impl_cases!( pow=52 : prec=30, round=Up => "1.15173335866675718975392626426e32"; prec=52, round=Up => "115173335866675718975392626425044.8429283056873556580"; prec=100, round=Up => "115173335866675718975392626425044.8429283056873556579339935191839667843520503303080335324003379361749"; prec=100, round=Down => "115173335866675718975392626425044.8429283056873556579339935191839667843520503303080335324003379361748"; prec=220, round=Up => "115173335866675718975392626425044.8429283056873556579339935191839667843520503303080335324003379361748091953445157717419294900287105759027634531967229789408468617796286936526237706376914237296824445112814900146493371906508"; ); impl_cases!( pow=400 : prec=30, round=Down => "4.22458642351596686588868351991e246"; prec=50, round=Up => "4.2245864235159668658886835199155003081243046945638e246"; prec=100, round=Down => "4.224586423515966865888683519915500308124304694563763586647543454119991635745909994893495905909587954e246"; ); impl_cases!( pow=527 : prec=1, round=Up => "9e324"; prec=1, round=HalfUp => "9e324"; prec=15, round=Down => "8.50101303706824E+324"; prec=19, round=Down => "8.501013037068242474E+324"; prec=20, round=Down => "8.5010130370682424747E+324"; ); impl_cases!( pow=550 : prec=1, round=Up => "2e339"; prec=5, round=Down => "1.2895e339"; prec=15, round=Down => "1.28959480113192E+339"; ); } mod case_23994 { use super::*; fn test_input() -> BigDecimal { "23994".parse().unwrap() } impl_cases!( pow=6 : prec=1, round=Up => "2e26"; prec=6, round=Down => "1.90816E+26"; prec=6, round=HalfDown => "1.90817E+26"; prec=15, round=Down => "1.90816500635331E+26"; prec=30, round=Up => "190816500635331516320302656"; ); impl_cases!( pow=20 : prec=2, round=Down => "3.9E+87"; prec=2, round=HalfEven => "4.0E+87"; prec=6, round=Down => "3.99993E+87"; prec=15, round=Down => "3.99993644008739E+87"; prec=30, round=Down => "3.99993644008739657595647874758E+87"; ); } } #[cfg(not(feature = "std"))] macro_rules! println { ( $( $x:expr ),* ) => {} } // Test that the 2 numbers are the same, assuming precision in ctx. fn compare(bd: BigDecimal, bd_expected: BigDecimal, ctx: &Context) { let bd_expected_round = bd_expected.with_precision_round(ctx.precision(), ctx.rounding_mode()); println!("100d 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"); println!("exp {}", bd_expected); println!("val {}", bd); println!("exprd {}", bd_expected_round); assert_eq!(bd, bd_expected_round); } macro_rules! impl_case { ($name:ident: $start:expr, $exp:literal => $expected:literal) => { #[test] fn $name() { let start = BigDecimal::from($start); let exp = $exp; let expected = $expected; let ctx = Context::default(); println!("Compute {}**{}", start, exp); let bd = start.powi_with_context(exp, &ctx); let bd_expected = BigDecimal::from_str(expected).unwrap(); compare(bd, bd_expected, &ctx); } }; } mod pow_known { use super::*; // Wolfram Alpha can get us to these precise values with a bit of log trickery, e.g.: // 2**3000000000 = 10**log_10(2**3000000000) = 10**(3000000000 * log_10(2)) impl_case!(case_2_3000: 2, 3000 => "1.230231922161117176931558813276752514640713895736833715766118029160058800614672948775360067838593459582429649254051804908512884180898236823e903"); impl_case!(case_2_2048: 2, 2048 => "3.231700607131100730071487668866995196044410266971548403213034542752465513886789089319720141152291346368871796092189801949411955915049092109e616"); impl_case!(case_2_2001: 2, 2001 => "2.296261390548509048465666402355363968044635404177390400955285473651532522784740627713318972633012539836891929277974925546894237921726110662e602"); impl_case!(case_2_3000000000: 2, 3000000000 => "9.8162042336235053508313854078782835648991393286913072670026492205522618203568834202759669215027003865712110468405800021098042607617495e903089986"); // This works as 2 can be exactly inverted with only 1 digit (0.5). impl_case!(case_0_5_30000000: BigDecimal::from(2).inverse(), 30000000 => "1.34921314623699835510360889355448887159595110457423959780496317685705095413905406464421931122265203166201415504288117880522818881981650e-9030900"); impl_case!(case_0_5_minus3000000000: BigDecimal::from(2).inverse(), -3000000000 => "9.8162042336235053508313854078782835648991393286913072670026492205522618203568834202759669215027003865712110468405800021098042607617495e903089986"); impl_case!(case_2_minus30000000: 2, -30000000 => "1.34921314623699835510360889355448887159595110457423959780496317685705095413905406464421931122265203166201415504288117880522818881981650e-9030900"); // This tests that the inverse operation carries enough digits to keep the precision. impl_case!(case_3_minus30000000: 3, -30000000 => "2.2824965348198962029744520058679746159742143842721452620663907608967745444344346503448190515521985159162206416095535917875712100566195e-14313638"); } macro_rules! impl_case { ($name:ident: $start:expr, $exp:expr) => { #[test] fn $name() { let start = BigDecimal::from_str($start).unwrap(); let exp = $exp.into(); let ctx = Context::new(NonZeroU64::new(50).unwrap(), RoundingMode::HalfEven); let ctx_large = Context::new(NonZeroU64::new(500).unwrap(), RoundingMode::HalfEven); println!("Compute {}**{}", start, exp); let bd = start.powi_with_context(exp, &ctx); let bd_expected = start.powi_with_context(exp, &ctx_large); compare(bd, bd_expected, &ctx); } }; } mod pow_misc { use super::*; // Test a few more misc values, checking that contexts with 50 or 500 precision // get the same number, after scaling down the 500 precision result to 50. impl_case!(case_misc_1: "-1.87421916986125215986", 3000912415i64); impl_case!(case_misc_2: "230231922161117176931558813276752514640713895736833715766118029160058800614672948775360067838593459582429649254051804908512884180898236823e903", 1000151); impl_case!(case_misc_3: "9.4215159218712961e-123", u32::MAX); impl_case!(case_misc_4: "213", 3); impl_case!(case_misc_5: "230231922161117176931558813276752514640713895736833715766118029160058800614672948775360067838593459582429649254051804908512884180898236823e903", -1000151); impl_case!(case_misc_6: "9.4215159218712961e-123", i32::MIN); // This test case fails without some extra margin (the number ends with 8.489 and gets rounded to 9 instead of 8) impl_case!(case_misc_7: "-946773878.6364634037017822265625", 4294967295i64); } bigdecimal-0.4.10/src/arithmetic/sqrt.rs000064400000000000000000000030241046102023000162440ustar 00000000000000//! square root implementation use crate::*; pub(crate) fn impl_sqrt(n: &BigUint, scale: i64, ctx: &Context) -> BigDecimal { // Calculate the number of digits and the difference compared to the scale let num_digits = count_decimal_digits_uint(n); let scale_diff = BigInt::from(num_digits) - scale; // Calculate the number of wanted digits and the exponent we need to raise the original value to // We want twice as many digits as the precision because sqrt halves the number of digits // We add an extra one for rounding purposes let prec = ctx.precision().get(); let extra_rounding_digit_count = 5; let wanted_digits = 2 * (prec + extra_rounding_digit_count); let exponent = wanted_digits.saturating_sub(num_digits) + u64::from(scale_diff.is_odd()); let sqrt_digits = (n * ten_to_the_uint(exponent)).sqrt(); // Calculate the scale of the result let result_scale_digits = 2 * (2 * prec - scale_diff) - 1; let result_scale_decimal: BigDecimal = BigDecimal::new(result_scale_digits, 0) / 4.0; let mut result_scale = result_scale_decimal.with_scale_round(0, RoundingMode::HalfEven).int_val; // Round the value so it has the correct precision requested result_scale += count_decimal_digits_uint(&sqrt_digits).saturating_sub(prec); let unrounded_result = BigDecimal::new(sqrt_digits.into(), result_scale.to_i64().unwrap()); unrounded_result.with_precision_round(ctx.precision(), ctx.rounding_mode()) } #[cfg(test)] mod test { use super::*; include!("sqrt.tests.rs"); } bigdecimal-0.4.10/src/arithmetic/sqrt.tests.rs000064400000000000000000000227141046102023000174140ustar 00000000000000 macro_rules! impl_case { ($name:ident; $input:literal => $expected:literal) => { #[test] fn $name() { let n: BigDecimal = $input.parse().unwrap(); let value = n.sqrt().unwrap(); let expected: BigDecimal = $expected.parse().unwrap(); assert_eq!(value, expected); assert_eq!(value.scale, expected.scale); } }; ($name:ident; prec=$prec:literal; round=$round:ident; $input:literal => $expected:literal) => { #[test] fn $name() { let ctx = Context::default() .with_prec($prec).unwrap() .with_rounding_mode(RoundingMode::$round); let n: BigDecimal = $input.parse().unwrap(); let value = n.sqrt_with_context(&ctx).unwrap(); let expected: BigDecimal = $expected.parse().unwrap(); assert_eq!(value, expected); assert_eq!(value.scale, expected.scale); } }; } impl_case!(case_0d000; "0.000" => "0.000"); impl_case!(case_1en232; "1e-232" => "1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e-116"); impl_case!(case_1d00; "1.00" => "1.00"); impl_case!(case_1d001; "1.001" => "1.000499875062460964823258287700109753027590031219780479551442971840836093890879944856933288426795152"); impl_case!(case_100d0; "100" => "10.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); impl_case!(case_49; "49" => "7.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); impl_case!(case_d25; ".25" => ".5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); impl_case!(case_0d0152399025; "0.0152399025" => ".1234500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); impl_case!(case_0d00400; "0.00400" => "0.06324555320336758663997787088865437067439110278650433653715009705585188877278476442688496216758600590"); impl_case!(case_0d1; "0.1" => "0.3162277660168379331998893544432718533719555139325216826857504852792594438639238221344248108379300295"); impl_case!(case_152399025; "152399025" => "12345.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); impl_case!(case_2; "2" => "1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573"); impl_case!(case_125348; "125348" => "354.0451948551201563108487193176101314241016013304294520812832530590100407318465590778759640828114535"); impl_case!(case_121d000242000121; "121.000242000121000000" => "11.00001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); impl_case!(case_0d01234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901; "0.01234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901" => "0.1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"); impl_case!(case_2e70; "2e70" => "141421356237309504880168872420969807.8569671875376948073176679737990732478462107038850387534327641573"); impl_case!(case_8d9793115997963468544185161590576171875en11; "8.9793115997963468544185161590576171875e-11" => "0.000009475922962855041517561783740144225422359796851494316346796373337470068631250135521161989831460407155"); impl_case!(case_18446744073709551616d1099511; "18446744073709551616.1099511" => "4294967296.000000000012799992691725492477397918722952224079252026972356303360555051219312462698703293"); impl_case!(case_3d1415926; "3.141592653589793115997963468544185161590576171875" => "1.772453850905515992751519103139248439290428205003682302442979619028063165921408635567477284443197875"); impl_case!(case_0d71777001; "0.7177700109762963922745342343167413624881759290454997218753321040760896053150388903350654937434826216803814031987652326749140535150336357405672040727695124057298138872112244784753994931999476811850580200000000000000000000000000000000" => "0.8472130847527653667042980517799020703921106560594525833177762276594388966885185567535692987624493813"); impl_case!(case_0d110889ddd444; "0.1108890000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000444" => "0.3330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000667"); impl_case!(case_3e170; "3e170" => "17320508075688772935274463415058723669428052538103806280558069794519330169088000370811.46186757248576"); impl_case!(case_9e199; "9e199" => "9486832980505137995996680633298155601158665417975650480572514558377783315917714664032744325137900886"); impl_case!(case_7e200; "7e200" => "2645751311064590590501615753639260425710259183082450180368334459201068823230283627760392886474543611e1"); impl_case!(case_777e204; "777e204" => "2.787471972953270789531596912111625325974789615194854615319795902911796043681078997362635440358922503E+103"); impl_case!(case_777e600; "7e600" => "2.645751311064590590501615753639260425710259183082450180368334459201068823230283627760392886474543611E+300"); impl_case!(case_2e900; "2e900" => "1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573E+450"); impl_case!(case_7e999; "7e999" => "8.366600265340755479781720257851874893928153692986721998111915430804187725943170098308147119649515362E+499"); impl_case!(case_74908163946345982392040522594123773796e999; "74908163946345982392040522594123773796e999" => "2.736935584670307552030924971360722787091742391079630976117950955395149091570790266754718322365663909E+518"); impl_case!(case_20e1024; "20e1024" => "4.472135954999579392818347337462552470881236719223051448541794490821041851275609798828828816757564550E512"); impl_case!(case_3en1025; "3e-1025" => "5.477225575051661134569697828008021339527446949979832542268944497324932771227227338008584361638706258E-513"); impl_case!(case_3242053850483855en13_prec11_round_down; prec=11; round=Down; "324.2053850483855" => "18.005704236"); impl_case!(case_3242053850483855en13_prec11_round_up; prec=11; round=Up; "324.2053850483855" => "18.005704237"); impl_case!(case_3242053850483855en13_prec31_round_up; prec=31; round=Up; "324.2053850483855" => "18.00570423639090823994825477228"); impl_case!(case_5d085019992340351en10_prec25_round_down; prec=25; round=Down; "5.085019992340351e-10" => "0.00002254998889653906459324292"); impl_case!(case_3025d13579652399025_prec3_round_up; prec=3; round=Up; "3025.13579652399025" => "55.1"); impl_case!(case_3025d13579652399025_prec9_round_down; prec=9; round=Down; "3025.13579652399025" => "55.0012345"); impl_case!(case_3025d13579652399025_prec9_round_up; prec=9; round=Up; "3025.13579652399025" => "55.0012345"); impl_case!(case_3025d13579652399025_prec8_round_halfdown; prec=8; round=HalfDown; "3025.13579652399025" => "55.001234"); impl_case!(case_3025d13579652399025_prec8_round_halfeven; prec=8; round=HalfEven; "3025.13579652399025" => "55.001234"); impl_case!(case_3025d13579652399025_prec8_round_halfup; prec=8; round=HalfUp; "3025.13579652399025" => "55.001235"); #[test] fn test_sqrt_rounding() { let vals = vec![ // sqrt(1.21) = 1.1, [Ceiling, Up] should round up ("1.21", "2", "1", "1", "1", "1", "1", "2"), // sqrt(2.25) = 1.5, [Ceiling, HalfEven, HalfUp, Up] should round up ("2.25", "2", "1", "1", "1", "2", "2", "2"), // sqrt(6.25) = 2.5, [Ceiling, HalfUp, Up] should round up ("6.25", "3", "2", "2", "2", "2", "3", "3"), // sqrt(8.41) = 2.9, [Ceiling, HalfDown, HalfEven, HalfUp, Up] should round up ("8.41", "3", "2", "2", "3", "3", "3", "3"), ]; for &(val, ceiling, down, floor, half_down, half_even, half_up, up) in vals.iter() { let val = BigDecimal::from_str(val).unwrap(); let ceiling = BigDecimal::from_str(ceiling).unwrap(); let down = BigDecimal::from_str(down).unwrap(); let floor = BigDecimal::from_str(floor).unwrap(); let half_down = BigDecimal::from_str(half_down).unwrap(); let half_even = BigDecimal::from_str(half_even).unwrap(); let half_up = BigDecimal::from_str(half_up).unwrap(); let up = BigDecimal::from_str(up).unwrap(); let ctx = Context::default().with_prec(1).unwrap(); assert_eq!(val.sqrt_with_context(&ctx.with_rounding_mode(RoundingMode::Ceiling)).unwrap(), ceiling); assert_eq!(val.sqrt_with_context(&ctx.with_rounding_mode(RoundingMode::Down)).unwrap(), down); assert_eq!(val.sqrt_with_context(&ctx.with_rounding_mode(RoundingMode::Floor)).unwrap(), floor); assert_eq!(val.sqrt_with_context(&ctx.with_rounding_mode(RoundingMode::HalfDown)).unwrap(), half_down); assert_eq!(val.sqrt_with_context(&ctx.with_rounding_mode(RoundingMode::HalfEven)).unwrap(), half_even); assert_eq!(val.sqrt_with_context(&ctx.with_rounding_mode(RoundingMode::HalfUp)).unwrap(), half_up); assert_eq!(val.sqrt_with_context(&ctx.with_rounding_mode(RoundingMode::Up)).unwrap(), up); } } #[cfg(property_tests)] mod prop { use super::*; use proptest::*; use num_traits::FromPrimitive; proptest! { #[test] fn sqrt_of_square_is_self(f: f64, prec in 15..50u64) { // ignore non-normal numbers prop_assume!(f.is_normal()); let n = BigDecimal::from_f64(f.abs()).unwrap().with_prec(prec); let n_squared = n.square(); let x = n_squared.sqrt().unwrap(); prop_assert_eq!(x, n); } } } bigdecimal-0.4.10/src/bigdigit/alignment.rs000064400000000000000000000341341046102023000166700ustar 00000000000000//! Splitting and shifting bigdigits for alignment //! #![allow(dead_code)] use crate::*; use super::radix::RadixPowerOfTen; use super::endian::LittleEndian; use crate::arithmetic::diff_usize; type BigDigitVec = super::digitvec::DigitVec; /// The cases resulting from applying (lhs += rhs * offset) /// #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) enum AddAssignSliceAlignment { /// [rrrrrrrr] | [rrr] | [rrrrrrr] /// [lllllll] | [lllllll] | [lllll] RightOverlap { count: usize, }, /// [rrrrr] /// [lllllll] /// ^count ^0 RightDisjoint { count: usize, }, /// Left starts with the more significant digits /// [rrrrrrr] | [rrrrrrr] /// [llllllll] | [lll] LeftOverlap { count: usize, }, /// Disjoint, left more significant /// [rrrrrrr] /// [lllll] /// ^count ^0 LeftDisjoint { count: usize, }, } impl AddAssignSliceAlignment { /// Determine relative alignment of digit-arrays of given length /// and scale (exponent of the least significant digit) pub fn from_lengths_and_scales(lhs: WithScale, rhs: WithScale) -> Self { use cmp::Ordering::*; match diff_usize(rhs.scale, lhs.scale) { (Equal, _) => { Self::RightOverlap { count: 0, } } (Less, count) => { if count < lhs.value { Self::RightOverlap { count, } } else { Self::RightDisjoint { count, } } } (Greater, count) => { if count < rhs.value { Self::LeftOverlap { count, } } else { Self::LeftDisjoint { count, } } } } } /// Determine relative alignment of digit-arrays of given length /// and number of integer bigdigits pub fn from_lengths_and_icount(lhs: WithIntCount, rhs: WithIntCount) -> Self { // position of least-significant digits Self::from_lengths_and_scales( WithScale { scale: lhs.value as i64 - lhs.count as i64, value: lhs.value, }, WithScale { scale: rhs.value as i64 - rhs.count as i64, value: rhs.value, }, ) } } #[derive(Copy, Clone, Debug)] pub(crate) struct BigDigitSplitterIter where R: RadixPowerOfTen, I: Iterator, { shift: ShiftState, digits: I, } impl BigDigitSplitterIter where R: RadixPowerOfTen, I: Iterator, { /// Wrap iterator with on shifting pub fn new(iter: I) -> Self { Self::from_shifter_and_iter(ShiftState::Zero, iter) } /// Wrap iterator, shifting by shift-state pub fn from_shifter_and_iter(shifter: ShiftState, iter: I) -> Self { Self { shift: shifter, digits: iter, } } /// Return the internal 'mask' value pub fn mask(&self) -> R::Base { match self.shift { ShiftState::Zero => Zero::zero(), ShiftState::Shifted { mask: BigDigitSplitter { mask, .. }, .. } => mask, } } /// Returns the value of the 'shift' with one subtracted /// /// Useful for adding nines to first result of `from_slice_starting_bottom` /// pub fn shift_minus_one(&self) -> R::Base { match self { BigDigitSplitterIter { shift: ShiftState::Zero, .. } => R::max(), BigDigitSplitterIter { shift: ShiftState::Shifted { mask, .. }, .. } => mask.shift - One::one(), } } /// Copy all remaining digits into destination vector pub fn extend_vector(self, dest: &mut BigDigitVec) { if let Self { shift: ShiftState::Zero, digits, .. } = self { dest.digits.extend(digits); } else { dest.digits.extend(self); } } /// Copy all remaining digits into destination vector, adding carry /// /// Note: carry is not zeroed after being pushed into the vector /// pub(crate) fn extend_vector_adding_carry( mut self, mut carry: R::Base, dest: &mut BigDigitVec, ) { while !carry.is_zero() { if let Some(mut next_digit) = self.next() { R::addassign_carry(&mut next_digit, &mut carry); dest.push_significant_digit(next_digit); } else { dest.push_significant_digit(carry); return; } } self.extend_vector(dest) } /// Extend vector with digits in self, adding carry and subtracting borrow pub(crate) fn extend_vector_with_carry_borrow( mut self, carry: &mut R::Base, borrow: &mut R::Base, dest: &mut BigDigitVec, ) { use num_traits::WrappingSub; if borrow.is_zero() && carry.is_zero() { return self.extend_vector(dest); } // the two cancel if carry == borrow { *borrow = Zero::zero(); *carry = Zero::zero(); return self.extend_vector(dest); } match self.next() { Some(digit) => { let d = R::sub_with_carry_borrow(digit, R::Base::zero(), carry, borrow); dest.push_significant_digit(d); // TODO: is there a cost to recursion? self.extend_vector_with_carry_borrow(borrow, carry, dest); } None if carry == borrow => {} None if carry > borrow => { dest.push_significant_digit(carry.wrapping_sub(borrow)); *carry = Zero::zero(); *borrow = Zero::zero(); } None => { unreachable!("borrow underflow"); } } } /// skip n digits pub fn advance_by_n(&mut self, n: usize) { // naive loop implementation for _ in 0..n { if self.next().is_none() { break; } } } /// called when there's further digits to iterate fn on_next_digit(&mut self, digit: R::Base) -> R::Base { if let ShiftState::Shifted { ref mut prev, ref mask, } = self.shift { let (hi, mut lo) = mask.split_and_shift(digit); lo += *prev; *prev = hi; lo } else { digit } } /// called when internal iterator is exhausted, returning final /// shifted digits fn on_last_digit(&mut self) -> Option { match self.shift { ShiftState::Shifted { ref mut prev, .. } if !prev.is_zero() => { let result = *prev; *prev = Zero::zero(); Some(result) } _ => None, } } } impl Iterator for BigDigitSplitterIter where R: RadixPowerOfTen, I: Iterator, { type Item = R::Base; fn next(&mut self) -> Option { self.digits .next() .map(|digit| self.on_next_digit(digit)) .or_else(|| self.on_last_digit()) } } type CopiedDigitSlice<'a, R> = stdlib::iter::Copied::Base>>; pub(crate) type BigDigitSliceSplitterIter<'a, R> = BigDigitSplitterIter>; impl<'a, R: RadixPowerOfTen> BigDigitSliceSplitterIter<'a, R> { /// Return the complimentary size to 'n' fn comp_n(n: usize) -> usize { debug_assert!(n < R::DIGITS); if n == 0 { 0 } else { R::DIGITS - n } } /// Build without shifting digits pub fn from_slice(slice: &'a [R::Base]) -> Self { Self { shift: ShiftState::Zero, digits: slice.iter().copied(), } } /// Stream will behave as if adding n zeros to beginning of digits /// /// ```ignore /// [987654321, ...] : n=3 => [654321000, xxxxxx987, ...] /// ``` /// pub(crate) fn from_slice_shifting_left(slice: &'a [R::Base], n: usize) -> Self { Self::from_slice_starting_bottom(slice, Self::comp_n(n)) } /// Stream will behave as if removing first n-digits from the slice /// /// ```ignore /// [987654321, ...] : n=3 => [xxx987654, ...] /// ``` /// /// This is the second digit of `from_slice_starting_bottom` /// pub(crate) fn from_slice_shifting_right(slice: &'a [R::Base], n: usize) -> Self { Self::from_slice_starting_top(slice, Self::comp_n(n)) } /// First digit will be the bottom n digits shifted to top /// /// ```ignore /// [987654321, ...] : n=3 => [321000000, xxx987654, ...] /// ``` /// pub(crate) fn from_slice_starting_bottom(slice: &'a [R::Base], n: usize) -> Self { Self::from_shifter_and_iter(ShiftState::starting_with_bottom(n), slice.iter().copied()) } /// First digit will be the highest n-digits shifted to bottom /// /// ```ignore /// [987654321, ...] : n=3 => [xxxxxx987, ...] /// ``` /// /// This is the second digit of `from_slice_shifting_left` /// The bottom digits will be lost. /// pub(crate) fn from_slice_starting_top(slice: &'a [R::Base], n: usize) -> Self { let mut digits = slice.iter().copied(); let shifter = ShiftState::starting_with_top(n, &mut digits); Self::from_shifter_and_iter(shifter, digits) } /// True if iterator has no more values pub fn is_exhausted(&self) -> bool { match self.shift { ShiftState::Zero => self.digits.len() == 0, _ => self.peek_next().is_none(), } } /// Return the next bigdigit (if available) without advancing the internal value pub fn peek_next(&self) -> Option { self.clone().next() } } /// Wrap shift-and-mask type with special-case for zero shift /// #[derive(Copy, Clone, Debug)] pub(crate) enum ShiftState { Zero, Shifted { mask: BigDigitSplitter, prev: R::Base, }, } impl ShiftState { /// Start with the lower n digits of the first bigdigit, shifted up /// /// ```ignore /// Self::starting_with_top([987654321, ...], 3) => [32100000, xxx987654, ...] /// ``` /// 987654321, 3 => /// fn starting_with_bottom(n: usize) -> Self { if n == 0 { Self::Zero } else { Self::Shifted { mask: BigDigitSplitter::mask_low(n as u8), prev: R::Base::zero(), } } } /// Start with high n digits of the first bigdigit /// /// ```ignore /// Self::starting_with_top([987654321, ...], 3) => [xxxxxx987, ...] /// ``` /// fn starting_with_top>(n: usize, digits: &mut I) -> Self { if n == 0 { Self::Zero } else { let mask = BigDigitSplitter::mask_high(n); let first_digit = digits.next().map(|d| d / mask.mask).unwrap_or(Zero::zero()); Self::Shifted { mask: mask, prev: first_digit, } } } } /// Splits a bigdigit into pieces, used when aligning #[derive(Copy, Clone, Debug)] pub(crate) struct BigDigitSplitter { /// dividend to split a bigdigit into high and low digits mask: R::Base, /// multiplication shifts high bigdigit to correct place after split shift: R::Base, } impl BigDigitSplitter { /// Build such that (X % mask) 'keeps' n digits of X pub fn mask_low(n: u8) -> Self { use crate::arithmetic::ten_to_the_t; debug_assert!((n as usize) < R::DIGITS); let mask = ten_to_the_t(n); let shift = ten_to_the_t(R::DIGITS as u8 - n); Self { shift, mask, } } /// Build such that (X / mask) 'keeps' n digits of X pub fn mask_high(n: usize) -> Self { Self::mask_low((R::DIGITS - n) as u8) } /// Split bigdigit into high and low digits /// /// BigDigitSplitter::mask_high(3).split(987654321) => (987000000, 000654321) /// BigDigitSplitter::mask_low(3).split(987654321) => (987654000, 000000321) /// pub fn split(&self, n: R::Base) -> (R::Base, R::Base) { let lo = n % self.mask; (n - lo, lo) } /// Split and shift such that the n "high" bits are on low /// side of digit and low bits are at the high end /// /// BigDigitSplitter::mask_high(3).split_and_shift(987654321) => (000000987, 654321000) /// BigDigitSplitter::mask_low(3).split_and_shift(987654321) => (000987654, 321000000) /// pub fn split_and_shift(&self, n: R::Base) -> (R::Base, R::Base) { let (hi, lo) = self.div_rem(n); (hi, lo * self.shift) } pub fn div_rem(&self, n: R::Base) -> (R::Base, R::Base) { n.div_rem(&self.mask) } pub fn div(&self, n: R::Base) -> R::Base { n / self.mask } } /// Wrap a container of bigidigts with a count of how /// many are integer /// /// i.e. The digits are aligned with zero /// #[derive(Clone, Copy, Debug, Default)] pub(crate) struct WithIntCount { /// number of big-digits in value to treat as integer count: i32, /// Slice of bigdigits value: T, } #[cfg(test)] #[allow(clippy::zero_prefixed_literal)] mod test { use super::*; include!("alignment.tests.rs"); } bigdecimal-0.4.10/src/bigdigit/alignment.tests.rs000064400000000000000000000130141046102023000200230ustar 00000000000000use bigdigit::radix::RADIX_10p9_u32; use bigdigit::radix::RADIX_10p19_u64; #[test] fn split_987654321_low_3() { let (hi, lo) = BigDigitSplitter::::mask_low(3).split(987654321); assert_eq!(hi, 987654000); assert_eq!(lo, 000000321) } #[test] fn split_987654321_high_3() { let (hi, lo) = BigDigitSplitter::::mask_high(3).split(987654321); assert_eq!(hi, 987000000); assert_eq!(lo, 000654321) } #[test] fn split_and_shift_987654321_high_3() { let (hi, lo) = BigDigitSplitter::::mask_high(3).split_and_shift(987654321); assert_eq!(hi, 000000987); assert_eq!(lo, 654321000) } #[test] fn split_and_shift_987654321_low_3() { let (hi, lo) = BigDigitSplitter::::mask_low(3).split_and_shift(987654321); assert_eq!(hi, 000987654); assert_eq!(lo, 321000000) } mod from_lengths_and_scales { use super::*; use paste::*; macro_rules! impl_test { (($x:literal, -$y:literal) += $($t:tt)*) => { paste! { impl_test!([< case_ $x _n$y >]; ($x, -$y); $($t)*); } }; (($x:literal, $y:literal) += $($t:tt)*) => { paste! { impl_test!([< case_ $x _$y >]; ($x, $y); $($t)*); } }; ($name:ident; ($x:literal, $y:literal); ($a:literal, -$b:literal) => $e:expr ) => { paste! { impl_test!([< $name _ $a _n $b >]; ($x, $y); ($a, -$b); $e); } }; ($name:ident; ($x:literal, $y:literal); ($a:literal, $b:literal) => $e:expr ) => { paste! { impl_test!([< $name _ $a _ $b >]; ($x, $y); ($a, $b); $e); } }; ($name:ident; ($x:literal, $y:literal); ($a:literal, $b:literal); $expected:expr) => { #[test] fn $name() { use self::AddAssignSliceAlignment::*; let alignment = AddAssignSliceAlignment::from_lengths_and_scales( WithScale { value: $x, scale: $y }, WithScale { value: $a, scale: $b }, ); assert_eq!(alignment, $expected); } }; } // ll.llllllll // r.rrrrrrr impl_test!((10, 8) += (8, 7) => RightOverlap { count: 1 }); // lllllll. // rrrrr0. impl_test!((7, 0) += (5, -1) => RightOverlap { count: 1 }); // lll. // rrrrrr.rrr impl_test!((3, 0) += (9, 3) => LeftOverlap { count: 3 }); // lll.l // .000000rrr impl_test!((4, 1) += (3, 9) => LeftDisjoint { count: 8 }); // 0.00000llll // rrrr.rr impl_test!((4, 9) += (6, 2) => RightDisjoint{ count: 7 }); } mod from_lengths_and_icount { use super::*; use paste::*; macro_rules! impl_test { (($x:literal, -$y:literal) += $($t:tt)*) => { paste! { impl_test!([< case_ $x _n$y >]; ($x, -$y); $($t)*); } }; (($x:literal, $y:literal) += $($t:tt)*) => { paste! { impl_test!([< case_ $x _$y >]; ($x, $y); $($t)*); } }; ($name:ident; ($x:literal, $y:literal); ($a:literal, -$b:literal) => $e:expr ) => { paste! { impl_test!([< $name _ $a _n $b >]; ($x, $y); ($a, -$b); $e); } }; ($name:ident; ($x:literal, $y:literal); ($a:literal, $b:literal) => $e:expr ) => { paste! { impl_test!([< $name _ $a _ $b >]; ($x, $y); ($a, $b); $e); } }; ($name:ident; ($x:literal, $y:literal); ($a:literal, $b:literal); $expected:expr) => { #[test] fn $name() { use self::AddAssignSliceAlignment::*; let alignment = AddAssignSliceAlignment::from_lengths_and_icount( WithIntCount { value: $x, count: $y }, WithIntCount { value: $a, count: $b }, ); assert_eq!(alignment, $expected); } }; } // ll.llllllll // r.rrrrrrr impl_test!((10, 2) += (8, 1) => RightOverlap { count: 1 }); // ll.lllllll // .rrrrrrr impl_test!((9, 2) += (7, 0) => RightOverlap { count: 0 }); // ll.ll // rrrrr.rr impl_test!((4, 2) += (7, 5) => RightOverlap { count: 0 }); // lllll000. // .00rrrrrrr impl_test!((5, 8) += (7, -2) => LeftDisjoint { count: 12 }); // l0. // .0rrrrrrr impl_test!((1, 2) += (7, -1) => LeftDisjoint { count: 9 }); // ll.lllllllll // .0rrrrrrr impl_test!((11, 2) += (7, -1) => RightOverlap { count: 1 }); // ll.llllllll // .0rrrrrrr impl_test!((10, 2) += (7, -1) => RightOverlap { count: 0 }); // ll.lllllll // .0rrrrrrr impl_test!((9, 2) += (7, -1) => LeftOverlap { count: 1 }); // ll.ll // .0rrrrrrr impl_test!((4, 2) += (7, -1) => LeftOverlap { count: 6 }); // ll.l // .0rrrrrrr impl_test!((3, 2) += (7, -1) => LeftDisjoint { count: 7 }); // ll. // .0rrrrrrr impl_test!((2, 2) += (7, -1) => LeftDisjoint { count: 8 }); // rrrrr000. // .00lllllll impl_test!((7, -2) += (5, 8) => RightDisjoint { count: 12 }); // lllll.ll // r.rrrr impl_test!((7, 5) += (5, 1) => LeftOverlap { count: 2 }); // lllll.l // r.rrrr impl_test!((6, 5) += (5, 1) => LeftOverlap { count: 3 }); // lllll. // r.rrrr impl_test!((5, 5) += (5, 1) => LeftOverlap { count: 4 }); // llll0. // r.rrrr impl_test!((4, 5) += (5, 1) => LeftDisjoint { count: 5 }); // l.llll // rrr0000. impl_test!((5, 1) += (3, 7) => RightDisjoint { count: 8 }); } bigdecimal-0.4.10/src/bigdigit/digitvec.rs000064400000000000000000000734151046102023000165150ustar 00000000000000//! Digit vectors (and slices) of arbitrary radix and endianness use crate::*; use stdlib::marker::PhantomData; use stdlib::num::NonZeroU64; use super::radix::*; use super::endian::*; use crate::rounding::NonDigitRoundingData; /// Vector of integers, interpreted as bigdigits in an integer /// /// Value of the integer is defined by the radix and endianness /// type parameters. /// #[derive(Clone, Default)] pub(crate) struct DigitVec { pub digits: Vec, _radix: PhantomData, _endian: PhantomData, } #[allow(dead_code)] impl DigitVec { /// Create new vector pub fn new() -> Self { Self::from_vec(Vec::new()) } /// Create new vector with capacity pub fn with_capacity(n: usize) -> Self { Self::from_vec(Vec::with_capacity(n)) } /// construct from vector of digits pub fn from_vec(v: Vec) -> Self { debug_assert!(R::validate_digits(v.iter()), "{:?}", v); Self { digits: v, _radix: PhantomData {}, _endian: PhantomData {}, } } /// allocate with n bigdigits and fill with zeros pub fn from_zero_count(n: usize) -> Self { Self::from_vec(vec![Zero::zero(); n]) } /// Number of bigdigits in the vector pub fn len(&self) -> usize { self.digits.len() } /// Remove all bigdigits pub fn clear(&mut self) { self.digits.clear() } /// Resize inner vector, filling new values with zero pub fn resize(&mut self, n: usize) { self.digits.resize(n, Zero::zero()) } /// Shrink inner vectory to new size pub fn truncate(&mut self, n: usize) { self.digits.truncate(n); } /// construct digitvec with u128 pub(crate) fn from_u128(n: u128) -> Self { let mut v = Self::new(); v.fill_with_u128(n); v } /// create vector of bigdigits from u128 pub(crate) fn fill_with_u128(&mut self, n: u128) { E::fill_vec_with_u128::(&mut self.digits, n); } /// Remove 'n' insignificant from the vector /// /// BigEndian vectors truncate. LittleEndian vectors shift and truncate, and /// remove significant zeros to reduce potential copy space /// /// If 'n' is larger than the vector, the vector is cleared. /// pub fn remove_insignificant_digits(&mut self, n: usize) { if n == 0 { return; } E::remove_insignificant_digits(&mut self.digits, n) } /// Borrow inner vectory as immutable digit-slice pub fn as_digit_slice(&self) -> DigitSlice<'_, R, E> { DigitSlice::from_slice(&self.digits[..]) } /// Return slice skipping first n bigdigits pub fn as_digit_slice_at(&self, n: usize) -> DigitSlice<'_, R, E> { DigitSlice::from_slice(&self.digits[n..]) } /// Borrow inner vectory as mutable digit-slice pub fn as_digit_slice_mut(&mut self) -> DigitSliceMut<'_, R, E> { DigitSliceMut::from_slice(&mut self.digits[..]) } /// Split slice at 'pos' least-significant digits pub fn split_le_at( &self, pos: usize ) -> (DigitSlice<'_, R, E>, DigitSlice<'_, R, E>) { let (lo, hi) = E::split_least_significant(&self.digits[..], pos); (DigitSlice::from_slice(lo), DigitSlice::from_slice(hi)) } /// Split slice at 'pos' least-significant digits pub fn split_le_at_mut( &mut self, pos: usize, ) -> (DigitSliceMut<'_, R, E>, DigitSliceMut<'_, R, E>) { let (lo, hi) = E::split_least_significant_mut(&mut self.digits[..], pos); (DigitSliceMut::from_slice(lo), DigitSliceMut::from_slice(hi)) } /// Return the number of significant zeros in vector pub fn count_significant_zeros(&self) -> usize { E::count_significant_zeros(self.digits.as_slice()) } /// true if empty or all zeros pub fn is_all_zeros(&self) -> bool { self.digits.iter().all(|&d| d.is_zero()) } /// Return self, ignoring any significant zeros pub fn least_n_are_zero(&self, n: usize) -> bool { self.iter_le().take(n).all(Zero::is_zero) } /// Convert to inner vector pub fn into_vec(self) -> Vec { self.digits } /// Add bigdigit into this vector, starting from index of least significance /// /// Any "overflow" is pushed to most significant end of the vector /// pub fn add_value(&mut self, n: R::Base) { self.add_value_at(0, n); } /// Add bigdigit into this vector (idexing from least-significant digit) /// /// TODO: Should vector resize if index is larger than size of vector? /// pub fn add_value_at(&mut self, idx: usize, n: R::Base) { debug_assert!(idx <= self.digits.len()); if n.is_zero() { return; } let overflow = self.as_digit_slice_mut().add_value_at(idx, n); if !overflow.is_zero() { self.push_significant_digit(overflow); } } /// Add bigdigit to the significant end of the vec pub fn push_significant_digit(&mut self, n: R::Base) { E::push_significant_digit(&mut self.digits, n); } /// remove significant zeros pub fn remove_leading_zeros(&mut self) { E::strip_significant_zeros(&mut self.digits) } #[cfg(rustc_1_75)] pub fn iter_le(&self) -> impl LeBigDigitIterator<'_, &R::Base> { E::iter_slice(&self.digits[..]) } #[cfg(not(rustc_1_75))] pub fn iter_le(&self) -> LittleEndianBigDigitIter<'_, &R::Base> { E::iter_slice(&self.digits[..]) } #[cfg(rustc_1_75)] pub fn iter_le_mut(&mut self) -> impl LeBigDigitIterator<'_, &mut R::Base> { E::iter_slice_mut(&mut self.digits[..]) } #[cfg(not(rustc_1_75))] pub fn iter_le_mut(&mut self) -> LittleEndianBigDigitIter<'_, &mut R::Base> { E::iter_slice_mut(&mut self.digits[..]) } } impl DigitVec { pub fn count_decimal_digits(&self) -> usize { self.as_digit_slice().count_decimal_digits() } } #[allow(dead_code)] impl DigitVec { /// allocate with n bigdigits and fill with zeros pub fn remove_significant_digits(&mut self) { if let Some(idx) = self.digits.iter().rposition(|d| !d.is_zero()) { self.digits.truncate(idx); } } } #[allow(dead_code)] impl DigitVec { pub fn remove_significant_digits(&mut self) { if let Some(idx) = self.digits.iter().position(|d| !d.is_zero()) { self.digits.copy_within(idx.., 0); self.digits.truncate(self.len() - idx); } } } #[allow(dead_code)] impl DigitVec { /// multiply this vector by 'n' fn mulassign_u64(&mut self, n: u64) { let mut carry = 0u64; for digit in self.iter_le_mut() { RADIX_u64::mulassign_add_carry(digit, n, &mut carry); } if !carry.is_zero() { E::push_significant_digit(&mut self.digits, carry); } } } #[allow(dead_code)] impl DigitVec { /// Convert to signed big integer pub fn into_bigint(self, sign: Sign) -> BigInt { BigInt::from_biguint(sign, self.into()) } /// Construct vector from iterator of base-10^{19} bigdigits #[allow(dead_code)] pub fn from_10p19_digits>(mut digits: I) -> Self { type R2p64 = RADIX_u64; type R10p19 = RADIX_10p19_u64; let mut v = vec![digits.next().unwrap_or(0)]; if let Some(d) = digits.next() { let mut carry = 0; R2p64::carrying_mul_add_inplace( d, R10p19::RADIX as u64, &mut v[0], &mut carry ); if carry != 0 { v.push(carry); } } let mut d = match digits.next() { Some(d) => d, None => { return Self::from_vec(v); } }; let mut shifter = BigUint::from(R10p19::RADIX * R10p19::RADIX); loop { v.push(0); if d != 0 { let mut carry = 0; let mut dest_digits = v.iter_mut(); let mut shifter_digits = shifter.iter_u64_digits(); loop { match (dest_digits.next(), shifter_digits.next()) { (Some(p), Some(s)) => { R2p64::carrying_mul_add_inplace(d, s, p, &mut carry); } (None, Some(mut s)) => { loop { let (hi, lo) = R2p64::fused_mul_add(s, d, carry); v.push(lo); carry = hi; s = match shifter_digits.next() { None => break, Some(x) => x, }; } break; } (Some(p), None) if carry != 0 => { R2p64::addassign_carry(p, &mut carry); } _ => { break; } } } if !carry.is_zero() { v.push(carry); } } d = match digits.next() { Some(d) => d, None => { let zero_idx = v.iter().rposition(|&d| d != 0).unwrap_or(0); v.truncate(zero_idx + 1); return Self::from_vec(v); } }; shifter *= R10p19::RADIX as u64; } } } impl From<&num_bigint::BigUint> for DigitVec { fn from(n: &num_bigint::BigUint) -> Self { Self::from_vec(n.iter_u64_digits().collect()) } } impl From> for num_bigint::BigUint { fn from(v: DigitVec) -> Self { // TODO: Can we do this conversion in place? let mut digits = Vec::with_capacity(v.len() * 2); for d in v.digits.into_iter() { digits.push(d as u32); digits.push((d >> 32) as u32); } Self::new(digits) } } impl From<&DigitVec> for num_bigint::BigUint { fn from(v: &DigitVec) -> Self { let mut digits = Vec::with_capacity(v.len() * 2); for &d in v.digits.iter() { digits.push(d as u32); digits.push((d >> 32) as u32); } Self::new(digits) } } impl DigitVec { /// Convert a num biguint into DigitVec, using tmp as scratchpad pub(crate) fn from_biguint_using_tmp( n: &num_bigint::BigUint, tmp: &mut Vec, ) -> Self { tmp.clear(); tmp.extend(n.iter_u64_digits()); let result = Self::from_2p64le_vec(tmp); // clear tmp so any residual digits are not accessible tmp.clear(); result } /// remove the bottom 'n' digits in the vector, returning the highest pub fn shift_n_digits_returning_high(&mut self, n: usize) -> u8 { use bigdigit::alignment::BigDigitSplitter; type Splitter = BigDigitSplitter; if n == 0 { return 0; } let (bd_count, d_count) = n.div_rem(&19); if d_count == 0 { // insig is top digit on previous bigdigit let ret = self.digits[bd_count - 1] / (RADIX_10p19_u64::RADIX as u64 / 10); self.digits.copy_within(bd_count.., 0); self.digits.truncate(self.len() - bd_count); return ret as u8; } let mask = Splitter::mask_low(d_count as u8); let (d0, insig) = mask.div_rem(self.digits[bd_count]); let ret = mask.div(insig * 10) as u8; let mut prev = d0; let mut j = 0; loop { if let Some(&d) = self.digits.get(bd_count + 1 + j) { let (hi, lo) = mask.split_and_shift(d); self.digits[j] = lo + prev; prev = hi; j += 1; } else { if prev != 0 { self.digits[j] = prev; j += 1; } self.digits.truncate(j); return ret; } } } /// Convert a base-2^64 DigitVec to 10^19 DigitVec fn from_2p64le_vec(src: &mut Vec) -> Self { type R = RADIX_10p19_u64; let mut result: Vec; match src.split_last() { None => { return Self::default(); } Some((&top_digit, &[])) => { let result = if top_digit < R::RADIX as u64 { vec![top_digit] } else { let (hi, lo) = top_digit.div_rem(&(R::RADIX as u64)); vec![lo, hi] }; return Self::from_vec(result); } Some((&top_digit, digits)) => { let bit_count = (64 * digits.len()) + (64 - top_digit.leading_zeros() as usize); let base2p64_bigdigit_count = (bit_count as f64) / (LOG2_10 * R::DIGITS as f64); result = Vec::with_capacity(base2p64_bigdigit_count.ceil() as usize); } } while let Some(pos) = src.iter().rposition(|&d| d != 0) { src.truncate(pos + 1); let rem: u64 = src.iter_mut().rev().fold(0, |acc, d| { R::rotating_div_u64_radix(acc, d) }); result.push(rem); } Self::from_vec(result) } /// Convert to a num BigInt with given sign pub fn into_bigint(self, sign: Sign) -> BigInt { let uint = self.into_biguint(); BigInt::from_biguint(sign, uint) } /// Convert to BigUint pub fn into_biguint(self) -> BigUint { use num_integer::div_rem; let radix = ::RADIX; let mut digits = self.digits.into_iter(); let d0 = digits.next().unwrap_or(0); let mut result = BigUint::from(d0); let n = match digits.next() { None => { return result; } Some(n) => n, }; let mut scale = BigUint::from(radix); result += n * &scale; for digit in digits { scale *= radix; match digit { 0 => {} 1 => { result += &scale; } n => { result += n * &scale; } } } return result; } } impl From> for num_bigint::BigUint { fn from(v: DigitVec) -> Self { Self::new(v.digits) } } impl From> for num_bigint::BigUint { fn from(v: DigitVec) -> Self { type R = RADIX_10p19_u64; let radix = R::RADIX as u64; match v.digits.as_slice() { &[] => { Self::zero() } &[d] => { Self::from(d) } &[d0, d1] => { let mut result = Self::from(d1); result *= radix; result += d0; return result; } _ => { let mut shifter = Self::one(); let mut digits = v.digits.iter().rev(); let mut result: Self = digits.next().copied().unwrap().into(); for &d in digits { shifter *= radix; result *= &shifter; result += d; } result } } } } impl From> for DigitVec { fn from(v: DigitSlice<'_, RADIX_u64, LittleEndian>) -> Self { let mut src = Vec::from(v.digits); Self::from_2p64le_vec(&mut src) } } impl From> for DigitVec { fn from(mut src: DigitVec) -> Self { type R2p64 = RADIX_u64; let radix = RADIX_10p19_u64::RADIX as u64; match src.digits.len() { 0 | 1 => { Self::from_vec(src.digits) } 2 => { let (hi, lo) = R2p64::expanding_mul(src.digits[1], radix); let (sum, overflow) = src.digits[0].overflowing_add(lo); src.digits[0] = sum; src.digits[1] = hi + u64::from(overflow); if src.digits[1] == 0 { src.digits.truncate(1); } Self::from_vec(src.digits) } _ => { let mut result = vec![0; src.len()]; result[0] = src.digits[0]; let mut scaler = BigInt::from(radix); let mut base10_digits = src.digits.iter().skip(1); let mut base10_digit = base10_digits.next().copied().unwrap_or(0); loop { for (i, base2_digit) in scaler.iter_u64_digits().enumerate() { let (hi, lo) = R2p64::expanding_mul(base10_digit, base2_digit); let (sum, overflow) = result[i].overflowing_add(lo); result[i] = sum; let mut j = i + 1; let (sum, overflow) = result[j].overflowing_add(hi + u64::from(overflow)); result[j] = sum; let mut carry = u64::from(overflow); while carry != 0 { j += 1; let (sum, overflow) = result[j].overflowing_add(carry); result[j] = sum; carry = u64::from(overflow); } } match base10_digits.next() { None => break, Some(&d) => base10_digit = d, } scaler *= radix; } Self::from_vec(result) } } } } /// Convert BigUint to base-10 digits impl From<&num_bigint::BigUint> for DigitVec { fn from(n: &num_bigint::BigUint) -> Self { Self::from_vec(n.to_radix_le(10)) } } #[cfg(test)] mod test_from_biguint_using_tmp { use super::*; use crate::bigdigit::radix::RADIX_10p19_u64; macro_rules! impl_case { ($name:ident: $input:literal => $result:expr) => { #[test] fn $name() { let n: BigUint = $input.parse().unwrap(); let mut tmp = Vec::new(); let vec = DigitVec::from_biguint_using_tmp(&n, &mut tmp); let expected: &[u64] = &$result; assert_eq!(vec.digits.as_slice(), expected); } }; } impl_case!(test_zero: "0" => []); impl_case!(test_3888089293362626678: "3888089293362626678" => [3888089293362626678]); impl_case!(test_10000000000000000000: "10000000000000000000" => [0, 1]); impl_case!(test_141905914: "1419059141115374799211309048234647259918822773497033524702964376392264024748829821875106774" => [ 4748829821875106774, 2470296437639226402, 2599188227734970335, 4799211309048234647, 141905914111537, ]); } /// Vector of base-10 digits #[allow(dead_code)] impl DigitVec { /// splits digits into `prec` significant digits, returning the lowest significant digit, /// highest insignificant digit, and the remaining insignificant digits in little endian order /// pub fn get_rounding_digits_at_prec( &self, prec: NonZeroU64, ) -> (u8, u8, DigitSlice<'_, RADIX_10_u8, LittleEndian>) { let trimmed = self.digits.len().saturating_sub(prec.get() as usize); if trimmed == 0 { return (0, 0, DigitSlice::from_slice(&[])); } let (insig_digits, sig_digits) = self.digits.split_at(trimmed); debug_assert_eq!(trimmed, insig_digits.len()); let (insig_digit, trailing_digits) = insig_digits.split_last().unwrap_or((&0, &[])); (sig_digits[0], *insig_digit, DigitSlice::from_slice(trailing_digits)) } /// Round the digits in this vec, returning slice of the digits /// /// Note: this changes the value of 'self', and should be considered as /// just a buffer of bytes after rounding in place. /// pub fn round_at_prec_inplace( &mut self, prec: NonZeroU64, rounding: NonDigitRoundingData, ) -> (DigitSlice<'_, RADIX_10_u8, LittleEndian>, usize) { // count number of insignificant digits to remove let mut trimmed = self.digits.len().saturating_sub(prec.get() as usize); if trimmed == 0 { return (DigitSlice::from_slice(&self.digits), 0); } let (insig_digits, sig_digits) = self.digits.split_at_mut(trimmed); debug_assert_eq!(trimmed, insig_digits.len()); let (&insig_digit, insig_digits) = insig_digits.split_last().unwrap_or((&0, &[])); let trailing_zeros = insig_digits.iter().all(|&d| d == 0); let round = rounding.round_pair((sig_digits[0], insig_digit), trailing_zeros); if round != 10 { sig_digits[0] = round; } else { match sig_digits.iter().position(|&d| d != 9) { Some(idx) => { sig_digits[idx] += 1; fill_slice_with_zero(&mut sig_digits[..idx]); } None => { fill_slice_with_zero(sig_digits); *sig_digits.last_mut().unwrap() = 1; trimmed += 1; } } } debug_assert_eq!(prec.get() as usize, sig_digits.len()); return (DigitSlice::from_slice(sig_digits), trimmed); } } #[cfg(rustc_1_50)] #[allow(clippy::incompatible_msrv)] #[allow(dead_code)] fn fill_slice_with_zero(s: &mut [D]) { s.fill(Zero::zero()); } #[cfg(not(rustc_1_50))] #[allow(dead_code)] fn fill_slice_with_zero(s: &mut [D]) { for r in s.iter_mut() { *r = Zero::zero(); } } /// Immutable slice of digits /// /// Operations on the bigdigit values are defined by the /// radix and endianness traits. /// #[derive(Clone, Copy)] pub(crate) struct DigitSlice<'a, R: RadixType, E: Endianness> { pub digits: &'a [R::Base], _radix: PhantomData, _endian: PhantomData, } #[allow(dead_code)] impl<'a, R: RadixType, E: Endianness> DigitSlice<'a, R, E> { /// Wrap slice of numbers as a slice of big-digits with given radix /// and endianness /// /// This does no validation, so the digits may be outside the bounds /// of the radix and may have leading significant zeros. /// pub fn from_slice(d: &'a [R::Base]) -> Self { Self { digits: d, _radix: PhantomData {}, _endian: PhantomData {}, } } /// Wrap slice of numbers, ignoring significant zeros pub fn from_sig_slice(d: &'a [R::Base]) -> Self { let (nonzero, _) = E::split_significant_zeros(d); Self::from_slice(nonzero) } /// Number of bigdigits in slice pub fn len(&self) -> usize { self.digits.len() } /// Return self, ignoring any significant zeros pub fn without_leading_zeros(&self) -> Self { let (digits, _) = E::split_significant_zeros(self.digits); Self::from_slice(digits) } /// Split splice into 'pos' least-significant bigdigits, and remaining pub fn split_le_at(&'a self, pos: usize) -> (Self, Self) { let (lo, hi) = E::split_least_significant(self.digits, pos); (Self::from_slice(lo), Self::from_slice(hi)) } /// Return the number of significant zeros pub fn count_significant_zeros(&self) -> usize { E::count_significant_zeros(self.digits) } /// true if empty or all zeros pub fn is_all_zeros(&self) -> bool { self.digits.iter().all(|&d| d.is_zero()) } /// Return self, ignoring any significant zeros pub fn least_n_are_zero(&self, n: usize) -> bool { self.iter_le().take(n).all(Zero::is_zero) } #[cfg(rustc_1_75)] pub fn iter_le(&self) -> impl LeBigDigitIterator<'_, &R::Base> { E::iter_slice(self.digits) } #[cfg(not(rustc_1_75))] pub fn iter_le(&self) -> LittleEndianBigDigitIter<'_, &R::Base> { E::iter_slice(self.digits) } } #[allow(dead_code)] impl DigitSlice<'_, R, LittleEndian> { /// Return subslice of digits with the 'n' least significant bigdigits removed pub fn trim_insignificant(&self, n: usize) -> Self { Self::from_slice(&self.digits[n..]) } pub fn find_least_significant_nonzero(&self) -> Option { self.digits.iter().position(|&d| !d.is_zero()) } } #[allow(dead_code)] impl<'a, E: Endianness> From<&'a DigitVec> for DigitSlice<'a, RADIX_u64, E> { fn from(v: &'a DigitVec) -> Self { v.as_digit_slice() } } impl<'a, R: RadixPowerOfTen, E: Endianness> DigitSlice<'a, R, E> { pub fn count_decimal_digits(&self) -> usize { use crate::arithmetic::decimal::count_digits_u64; let (top_digit, trailing) = E::split_most_significant_digit(self.digits); R::DIGITS * trailing.len() + count_digits_u64(top_digit.to_u64().unwrap()) } } impl DigitSlice<'_, RADIX_10_u8, LittleEndian> { /// fill digitvec with value contained in this digit-slice #[allow(dead_code)] pub fn fill_vec_u64(&self, dest: &mut DigitVec) { let n = num_bigint::BigUint::from_radix_le(self.digits, 10).unwrap(); *dest = (&n).into(); } } /// Mutable slice of bigdigit values pub(crate) struct DigitSliceMut<'a, R: RadixType, E: Endianness> { pub digits: &'a mut [R::Base], _radix: PhantomData, _endian: PhantomData, } #[allow(dead_code)] impl<'a, R: RadixType, E: Endianness> DigitSliceMut<'a, R, E> { /// Construct from mutable slice of numbers pub fn from_slice(v: &'a mut [R::Base]) -> Self { Self { digits: v, _radix: PhantomData {}, _endian: PhantomData {}, } } /// Number of bigdigits in slice pub fn len(&self) -> usize { self.digits.len() } /// From digitvec, offset from the true index (independent of endianness) pub fn from_vec_offset(v: &'a mut DigitVec, offset: usize) -> Self { Self::from_slice(&mut v.digits[offset..]) } /// Cast to immutable slice pub fn as_digit_slice(&'a self) -> DigitSlice<'a, R, E> { DigitSlice::from_slice(self.digits) } /// Split, returning 'pos' little-endian pub fn split_le_at(&'a self, pos: usize) -> (DigitSlice<'a, R, E>, DigitSlice<'a, R, E>) { let (lo, hi) = E::split_least_significant(&self.digits[..], pos); (DigitSlice::from_slice(lo), DigitSlice::from_slice(hi)) } /// Split, returning 'pos' little-endian pub fn split_le_at_mut(&'a mut self, pos: usize) -> (Self, Self) { let (lo, hi) = E::split_least_significant_mut(self.digits, pos); (Self::from_slice(lo), Self::from_slice(hi)) } /// Add bigdigit 'n' into this slice, returning overflow pub fn add_value_at(&mut self, idx: usize, mut n: R::Base) -> R::Base { if n.is_zero() { return n; } E::addassign_carry_into_slice_at::(self.digits, &mut n, idx); n } /// Add bigdigit into vector, storing overflow back in c pub fn addassign_carry(&mut self, c: &mut R::Base) { E::addassign_carry_into_slice_at::(self.digits, c, 0); } #[cfg(rustc_1_75)] pub fn iter_le(&self) -> impl LeBigDigitIterator<'_, &R::Base> { E::iter_slice(self.digits) } #[cfg(not(rustc_1_75))] pub fn iter_le(&self) -> LittleEndianBigDigitIter<'_, &R::Base> { E::iter_slice(self.digits) } #[cfg(rustc_1_75)] pub fn iter_le_mut(&mut self) -> impl LeBigDigitIterator<'_, &mut R::Base> { E::iter_slice_mut(self.digits) } #[cfg(not(rustc_1_75))] pub fn iter_le_mut(&mut self) -> LittleEndianBigDigitIter<'_, &mut R::Base> { E::iter_slice_mut(self.digits) } } #[allow(dead_code)] impl DigitSliceMut<'_, R, E> { pub fn count_decimal_digits(&self) -> usize { self.as_digit_slice().count_decimal_digits() } } impl<'a, R: RadixType, E: Endianness> From<&'a mut Vec> for DigitSliceMut<'a, R, E> { fn from(digits: &'a mut Vec) -> Self { Self::from_slice(&mut digits[..]) } } impl fmt::Debug for DigitVec { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "DigitVec({}, {:?})", E::NAME, self.digits) } } impl fmt::Debug for DigitSlice<'_, R, E> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "DigitSlice({}, {:?})", E::NAME, self.digits) } } impl fmt::Debug for DigitSliceMut<'_, R, E> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "DigitSliceMut({}, {:?})", E::NAME, self.digits) } } /// Add method to easily transform scaled DigitVec to scaled DigitSlice impl crate::WithScale> { pub fn as_digit_slice(&self) -> crate::WithScale> { WithScale { scale: self.scale, value: self.value.as_digit_slice(), } } } bigdecimal-0.4.10/src/bigdigit/endian.rs000064400000000000000000000342671046102023000161570ustar 00000000000000//! Structs and traits for generic operations on big or little endian ints use crate::*; use crate::stdlib; use crate::stdlib::fmt; use crate::stdlib::Vec; #[cfg(not(rustc_1_75))] use stdlib::Box; use num_traits::{Zero, PrimInt}; use super::radix::RadixType; /// Trait to allow generic parameterization of significant digit ordering #[allow(dead_code)] pub(crate) trait Endianness: Copy + Clone + Default + fmt::Debug { /// Name to use for debugging const NAME: &'static str; /// Iterate over digits in vec from least to most significance #[cfg(rustc_1_75)] fn into_iter<'a, D: 'a>(digits: Vec) -> impl LeBigDigitIterator<'a, D>; /// Iterate in slice from least to most significance #[cfg(rustc_1_75)] fn iter_slice(digits: &[D]) -> impl LeBigDigitIterator<'_, &D>; /// Iterate over mut digits in slice from least to most significance #[cfg(rustc_1_75)] fn iter_slice_mut(digits: &mut [D]) -> impl LeBigDigitIterator<'_, &mut D>; #[cfg(not(rustc_1_75))] fn into_iter<'a, D: 'a>(digits: Vec) -> LittleEndianBigDigitIter<'a, D>; #[cfg(not(rustc_1_75))] fn iter_slice(digits: &[D]) -> LittleEndianBigDigitIter<'_, &D>; #[cfg(not(rustc_1_75))] fn iter_slice_mut(digits: &mut [D]) -> LittleEndianBigDigitIter<'_, &mut D>; #[cfg(rustc_1_75)] fn addassign_carry_into_slice_at( digits: &mut [R::Base], carry: &mut R::Base, idx: usize, ) { for dest in Self::iter_slice_mut(digits).skip(idx) { R::addassign_carry(dest, carry); if carry.is_zero() { return; } } } #[cfg(not(rustc_1_75))] fn addassign_carry_into_slice_at( digits: &mut [R::Base], carry: &mut R::Base, idx: usize, ); /// Place given digit at the most-significant end of the vecor fn push_significant_digit(digits: &mut Vec, d: D); /// Split slice into most-significant digit and 'the rest' /// /// If slice is empty zero and empty-slice is returned fn split_most_significant_digit(digits: &[D]) -> (D, &[D]); /// Split significant zeros from digits returning pair (digits, zeros) fn split_significant_zeros(digits: &[D]) -> (&[D], &[D]); /// Split slice into 'count' low-significant digits, and remaining /// significant digits fn split_least_significant(digits: &[D], count: usize) -> (&[D], &[D]); /// Split mutable slice into 'count' low-significant digits, and /// remaining significant digits fn split_least_significant_mut(digits: &mut [D], count: usize) -> (&mut [D], &mut [D]); /// Remove any zeros at the location of highest significance, if all zeros /// the vector will be cleared fn strip_significant_zeros(digits: &mut Vec); /// return number of consecutive zeros starting at significant fn count_significant_zeros(digits: &[D]) -> usize { Self::iter_slice(digits).rev().position(|d| !d.is_zero()).unwrap_or(digits.len()) } /// Remove 'n' insignificant digits from the vector, and MAY remove leading significant zeros fn remove_insignificant_digits(digits: &mut Vec, n: usize); /// Correctly order a slice of little endian digits /// /// Reverses for BigEndian, no-op for LittleEndian fn reorder_le_digits(digits: &mut [D]); /// Reorder vector of big-endian digits to this endianness /// /// Removes trailing zeros fn reorder_be_vec(digits: &mut Vec); /// Consider digits in slice past 'idx' to be little-endian digits /// of higher significance than those below; move them to correct /// position in the slice /// /// This will be a no-op for LittleEndian, and a rotate and reverse for BigEndian /// fn rotate_trailing_le_digits_at(digits: &mut [D], idx: usize); /// Extract digits in correct order from bigiuint fn bigint_to_digits(n: &num_bigint::BigUint) -> Vec; /// Build BigUint from base-10 digits in slice fn biguint_from_digits(n: &[u8]) -> Option; /// Split u128 and store in vector fn fill_vec_with_u128(vec: &mut Vec, n: u128); } /// Empty struct indicating most-significant bigdigit first #[derive(Copy, Clone, Debug, Default)] pub(crate) struct BigEndian {} /// Empty struct indicating least-significant bigdigit first #[derive(Copy, Clone, Debug, Default)] pub(crate) struct LittleEndian {} impl Endianness for BigEndian { const NAME: &'static str = "BE"; #[cfg(rustc_1_75)] fn into_iter<'a, D: 'a>(digits: Vec) -> impl LeBigDigitIterator<'a, D> { digits.into_iter().rev() } #[cfg(rustc_1_75)] fn iter_slice(digits: &[D]) -> impl LeBigDigitIterator<'_, &D> { digits.iter().rev() } #[cfg(rustc_1_75)] fn iter_slice_mut(digits: &mut [D]) -> impl LeBigDigitIterator<'_, &mut D> { digits.iter_mut().rev() } #[cfg(not(rustc_1_75))] fn into_iter<'a, D: 'a>(digits: Vec) -> LittleEndianBigDigitIter<'a, D> { LittleEndianBigDigitIter { digits: Box::new(digits.into_iter().rev()), } } #[cfg(not(rustc_1_75))] fn iter_slice(digits: &[D]) -> LittleEndianBigDigitIter<'_, &D> { LittleEndianBigDigitIter { digits: Box::new(digits.iter().rev()), } } #[cfg(not(rustc_1_75))] fn iter_slice_mut(digits: &mut [D]) -> LittleEndianBigDigitIter<'_, &mut D> { LittleEndianBigDigitIter { digits: Box::new(digits.iter_mut().rev()), } } #[cfg(not(rustc_1_75))] fn addassign_carry_into_slice_at( digits: &mut [R::Base], carry: &mut R::Base, idx: usize, ) { for dest in digits.iter_mut().rev().skip(idx) { R::addassign_carry(dest, carry); if carry.is_zero() { return; } } } fn push_significant_digit(digits: &mut Vec, d: D) { digits.insert(0, d); } fn split_least_significant(digits: &[D], count: usize) -> (&[D], &[D]) { let (hi, lo) = digits.split_at(digits.len() - count); (lo, hi) } fn split_least_significant_mut(digits: &mut [D], count: usize) -> (&mut [D], &mut [D]) { let (hi, lo) = digits.split_at_mut(digits.len() - count); (lo, hi) } fn split_most_significant_digit(digits: &[D]) -> (D, &[D]) { digits.split_first().map(|(&d, r)| (d, r)).unwrap_or((Zero::zero(), &[])) } fn strip_significant_zeros(digits: &mut Vec) { if let Some(idx) = digits.iter().position(|d| !d.is_zero()) { digits.copy_within(idx.., 0); digits.truncate(digits.len() - idx); } else { digits.clear(); } } fn split_significant_zeros(digits: &[D]) -> (&[D], &[D]) { if let Some(idx) = digits.iter().position(|d| !d.is_zero()) { let (sig_zeros, digits) = digits.split_at(idx); (digits, sig_zeros) } else { (&[], digits) } } fn remove_insignificant_digits(digits: &mut Vec, n: usize) { // TODO: Does truncate need - 1? digits.truncate(digits.len() - n); } fn reorder_le_digits(digits: &mut [D]) { digits.reverse() } fn reorder_be_vec(digits: &mut Vec) { match digits.iter().position(|&d| !d.is_zero()) { Some(0) => {} Some(idx) => { digits.copy_within(idx.., 0); digits.truncate(digits.len() - idx); } None => digits.clear(), } } fn rotate_trailing_le_digits_at(digits: &mut [D], idx: usize) { Self::reorder_le_digits(&mut digits[idx..]); digits.rotate_left(idx); } fn bigint_to_digits(n: &num_bigint::BigUint) -> Vec { n.to_radix_be(10) } fn biguint_from_digits(n: &[u8]) -> Option { num_bigint::BigUint::from_radix_be(n, 10) } fn fill_vec_with_u128(vec: &mut Vec, n: u128) { LittleEndian::fill_vec_with_u128::(vec, n); vec.reverse(); } } impl Endianness for LittleEndian { const NAME: &'static str = "LE"; #[cfg(rustc_1_75)] fn into_iter<'a, D: 'a>(digits: Vec) -> impl LeBigDigitIterator<'a, D> { digits.into_iter() } #[cfg(rustc_1_75)] fn iter_slice(digits: &[D]) -> impl LeBigDigitIterator<'_, &D> { digits.iter() } #[cfg(rustc_1_75)] fn iter_slice_mut(digits: &mut [D]) -> impl LeBigDigitIterator<'_, &mut D> { digits.iter_mut() } #[cfg(not(rustc_1_75))] fn into_iter<'a, D: 'a>(digits: Vec) -> LittleEndianBigDigitIter<'a, D> { LittleEndianBigDigitIter { digits: Box::new(digits.into_iter()), } } #[cfg(not(rustc_1_75))] fn iter_slice(digits: &[D]) -> LittleEndianBigDigitIter<'_, &D> { LittleEndianBigDigitIter { digits: Box::new(digits.iter()), } } #[cfg(not(rustc_1_75))] fn iter_slice_mut(digits: &mut [D]) -> LittleEndianBigDigitIter<'_, &mut D> { LittleEndianBigDigitIter { digits: Box::new(digits.into_iter()), } } #[cfg(not(rustc_1_75))] fn addassign_carry_into_slice_at( digits: &mut [R::Base], carry: &mut R::Base, idx: usize, ) { for dest in digits.iter_mut().skip(idx) { R::addassign_carry(dest, carry); if carry.is_zero() { return; } } } fn push_significant_digit(digits: &mut Vec, d: D) { digits.push(d); } fn split_least_significant(digits: &[D], count: usize) -> (&[D], &[D]) { digits.split_at(count) } fn split_least_significant_mut(digits: &mut [D], count: usize) -> (&mut [D], &mut [D]) { digits.split_at_mut(count) } fn split_most_significant_digit(digits: &[D]) -> (D, &[D]) { digits.split_last().map(|(&d, r)| (d, r)).unwrap_or((Zero::zero(), &[])) } fn strip_significant_zeros(digits: &mut Vec) { if let Some(idx) = digits.iter().rposition(|d| !d.is_zero()) { digits.truncate(idx + 1); } else { digits.clear(); } } fn split_significant_zeros(digits: &[D]) -> (&[D], &[D]) { if let Some(idx) = digits.iter().rposition(|d| !d.is_zero()) { let (digits, sig_zeros) = digits.split_at(idx); (digits, sig_zeros) } else { (&[], digits) } } fn remove_insignificant_digits(digits: &mut Vec, n: usize) { let last_nonzero_idx = digits.iter().rposition(|&d| !d.is_zero()); match (last_nonzero_idx, n > digits.len()) { (Some(idx), false) => { digits.copy_within(n..=idx, 0); digits.truncate(idx - n + 1); } _ => { digits.clear(); } } } fn reorder_be_vec(digits: &mut Vec) { match digits.iter().position(|&d| !d.is_zero()) { None => digits.clear(), Some(idx) => { digits.copy_within(idx.., 0); digits.truncate(digits.len() - idx); digits.reverse(); } } } #[allow(unused_variables)] fn reorder_le_digits(digits: &mut [D]) { //no-op } #[allow(unused_variables)] fn rotate_trailing_le_digits_at(digits: &mut [D], idx: usize) { //no-op } fn bigint_to_digits(n: &num_bigint::BigUint) -> Vec { n.to_radix_le(10) } fn biguint_from_digits(n: &[u8]) -> Option { num_bigint::BigUint::from_radix_le(n, 10) } fn fill_vec_with_u128(vec: &mut Vec, mut n: u128) { let base = R::RADIX.to_u128().unwrap(); vec.clear(); while !n.is_zero() { let (hi, lo) = num_integer::div_rem(n, base); let lo = R::Base::from_u128(lo).unwrap(); vec.push(lo); n = hi; } } } /// Abstraction over fixed-size little-endian bigdigit iterators /// /// Can be applied to slice, vecs, and num_bigint::{U32Digits, U64Digits} /// allowing "easy" access to the digits. pub(crate) trait LeBigDigitIterator<'a, D> : Iterator + ExactSizeIterator + DoubleEndedIterator { } /// Thin wrapper around boxed big-digit-iterator trait object /// /// Used to implement generic endian iterators for versions of Rust before /// Return Position Impl Trait In Trait (RPITIT) were implemented. /// #[cfg(not(rustc_1_75))] pub(crate) struct LittleEndianBigDigitIter<'a, D> { digits: Box + 'a>, } #[cfg(not(rustc_1_75))] impl Iterator for LittleEndianBigDigitIter<'_, D> { type Item = D; fn next(&mut self) -> Option { self.digits.next() } fn size_hint(&self) -> (usize, Option) { self.digits.size_hint() } } #[cfg(not(rustc_1_75))] impl DoubleEndedIterator for LittleEndianBigDigitIter<'_, D> { fn next_back(&mut self) -> Option { self.digits.next_back() } } #[cfg(not(rustc_1_75))] impl ExactSizeIterator for LittleEndianBigDigitIter<'_, D> { fn len(&self) -> usize { self.digits.len() } } impl<'a> LeBigDigitIterator<'a, u64> for num_bigint::U64Digits<'a> {} impl<'a> LeBigDigitIterator<'a, u32> for num_bigint::U32Digits<'a> {} impl<'a, D> LeBigDigitIterator<'a, &'a D> for stdlib::slice::Iter<'a, D> {} impl<'a, D> LeBigDigitIterator<'a, &'a D> for stdlib::iter::Rev> {} impl<'a, D> LeBigDigitIterator<'a, &'a mut D> for stdlib::slice::IterMut<'a, D> {} impl<'a, D> LeBigDigitIterator<'a, &'a mut D> for stdlib::iter::Rev> {} impl LeBigDigitIterator<'_, D> for stdlib::vec::IntoIter {} impl LeBigDigitIterator<'_, D> for stdlib::iter::Rev> {} bigdecimal-0.4.10/src/bigdigit/mod.rs000064400000000000000000000007301046102023000154640ustar 00000000000000//! BigDigit types and routines //! //! Constants and structures defining the "BigDigit" components of BigDecimal. //! //! BigDigit is generic over Radix types, allowing the properties of //! a bigdigit to be specified in the radix, and the the overall behavior //! of the bigdigit (i.e. add_with_carry) as methods on the BigDigit. //! //! NOTE: These are distinct from the BigDigits in num_bigint. //! pub mod alignment; pub mod digitvec; pub mod endian; pub mod radix; bigdecimal-0.4.10/src/bigdigit/radix.rs000064400000000000000000000277301046102023000160250ustar 00000000000000//! Radix definitions //! //! Empty structs used to make generic algorithms over kind of radix //! #![allow(dead_code)] #![allow(non_camel_case_types)] use crate::*; use crate::stdlib::fmt; use num_traits::{WrappingAdd, WrappingSub, AsPrimitive}; /// All the information needed to specify a bigdecimal's radix, and methods operating on integers pub trait RadixType: Copy + Clone + Default + fmt::Debug { /// the inner type of values type Base : 'static + Copy + fmt::Debug + num_integer::Integer + num_traits::PrimInt + num_traits::FromPrimitive + num_traits::AsPrimitive + num_traits::Zero + num_traits::One + num_traits::WrappingSub + num_traits::Pow + AddAssign + From + From; /// double wide unsigned type (capable of storing product of two BigDigits) type BaseDouble : 'static + Copy + num_integer::Integer + num_traits::PrimInt + num_traits::FromPrimitive + num_traits::AsPrimitive + num_traits::Zero + num_traits::One + num_traits::WrappingAdd + num_traits::WrappingSub + AddAssign + From + From; /// signed version of base (used for diffs) type SignedBase : 'static + Copy + num_integer::Integer + num_traits::PrimInt + num_traits::FromPrimitive + num_traits::Zero + num_traits::One + num_traits::Signed; /// Value of the RADIX const RADIX: Self::BaseDouble; /// Check contents of iterable contains values less than the radix fn validate_digits<'a, I: IntoIterator>(i: I) -> bool { i.into_iter().map(|&d| d.into()).all(|d| Self::BaseDouble::zero() <= d && d < Self::RADIX) } /// True if n is the maximum value for this radix (RADIX - 1) fn max() -> Self::Base { (Self::RADIX - One::one()).as_() } /// True if n is the maximum value for this radix (RADIX - 1) fn is_max(n: Self::Base) -> bool { n == Self::max() } /// Split single-width BigDigit base-type value into valid BigDigits for /// this Radix fn split_single(n: Self::Base) -> (Self::Base, Self::Base) { let (hi, lo) = num_integer::div_rem(n.as_(), Self::RADIX); return (hi.as_(), lo.as_()); } /// Split double-wide value into valid BigDigit and overflow for this Radix fn split_doublewide(n: Self::BaseDouble) -> (Self::BaseDouble, Self::Base) { let (hi, lo) = num_integer::div_rem(n, Self::RADIX); return (hi, lo.as_()); } /// Split double-wide bigdigit into high and low bigdigits. /// /// This assumes n will fit in two bigdigits, which is not guaranteed. /// Use split_doublewide. /// fn split_wide_digit(n: Self::BaseDouble) -> (Self::Base, Self::Base) { let (hi, lo) = num_integer::div_rem(n, Self::RADIX); debug_assert!(hi < Self::RADIX); return (hi.as_(), lo.as_()); } /// Perform n + carry, returning sum and storing overflow back in carry fn add_carry(n: Self::Base, carry: &mut Self::Base) -> Self::Base { let (hi, lo) = Self::expanding_add(n, *carry); *carry = hi; lo } /// Perform n += carry, returning overflow in carry fn addassign_carry(n: &mut Self::Base, carry: &mut Self::Base) { let (hi, lo) = Self::expanding_add(*n, *carry); *carry = hi; *n = lo; } /// Perform n += a + carry, returning overflow in carry fn addassign_with_carry(n: &mut Self::Base, a: Self::Base, carry: &mut Self::Base) { let sum = n.as_() + a.as_() + carry.as_(); let (hi, lo) = Self::split_wide_digit(sum); *carry = hi; *n = lo; } /// Perform a + b, returning tuple of (high, low) digits fn add_expand_doublewide(a: Self::Base, b: Self::BaseDouble) -> (Self::Base, Self::Base) { let a: Self::BaseDouble = a.into(); Self::split_wide_digit(a + b) } /// Perform a + b, returning tuple of (high, low) digits fn expanding_add(a: Self::Base, b: Self::Base) -> (Self::Base, Self::Base) { let a: Self::BaseDouble = a.into(); let b: Self::BaseDouble = b.into(); Self::split_wide_digit(a + b) } /// Perform a * b, returning tuple of (high, low) digits fn expanding_mul(a: Self::Base, b: Self::Base) -> (Self::Base, Self::Base) { let a: Self::BaseDouble = a.into(); let b: Self::BaseDouble = b.into(); Self::split_wide_digit(a * b) } /// Perform a * b + c, returning tuple of (high, low) digits fn fused_mul_add(a: Self::Base, b: Self::Base, c: Self::Base) -> (Self::Base, Self::Base) { let a: Self::BaseDouble = a.into(); let b: Self::BaseDouble = b.into(); let c: Self::BaseDouble = c.into(); Self::split_wide_digit(a * b + c) } /// Perform a * b + c + d, returning tuple of (high, low) digits fn carrying_mul_add( a: Self::Base, b: Self::Base, c: Self::Base, d: Self::Base, ) -> (Self::Base, Self::Base) { let a: Self::BaseDouble = a.into(); let b: Self::BaseDouble = b.into(); let c: Self::BaseDouble = c.into(); let d: Self::BaseDouble = d.into(); Self::split_wide_digit(a * b + c + d) } /// Perform c += a * b + carry, returning overflow in carry fn carrying_mul_add_inplace( a: Self::Base, b: Self::Base, c: &mut Self::Base, carry: &mut Self::Base, ) { let a: Self::BaseDouble = a.into(); let b: Self::BaseDouble = b.into(); let (hi, lo) = Self::split_wide_digit(a * b + (*c).into() + (*carry).into()); *c = lo; *carry = hi; } /// Add c into little-endian slice of digits, storing overflow in c /// /// Starts adding at index 0. /// fn add_carry_into_slice(dest: &mut [Self::Base], c: &mut Self::Base) { Self::add_carry_into(dest.iter_mut(), c) } /// Iterate over digits in 'dest', adding the carry value until it becomes zero. /// /// If iterator runs out of digits while carry has a value (i.e. the sum overflows), /// the carry value will not be zero. /// fn add_carry_into<'a, I: Iterator>(dest: I, c: &mut Self::Base) { for d in dest { if c.is_zero() { return; } let (overflow, sum) = Self::expanding_add(*c, *d); *d = sum; *c = overflow; } } /// a = a * b + c, storing fn mulassign_add_carry( a: &mut Self::Base, b: Self::Base, carry: &mut Self::Base, ) { let (hi, lo) = Self::expanding_mul(*a, b); *a = Self::add_carry(lo, carry); *carry += hi; } /// return value of (lhs - rhs + carry - borrow) fn sub_with_carry_borrow( lhs: Self::Base, rhs: Self::Base, carry: &mut Self::Base, borrow: &mut Self::Base, ) -> Self::Base { let mut result = Self::BaseDouble::from(lhs); result = result .wrapping_sub(&Self::BaseDouble::from(rhs)) .wrapping_add(&(*carry).as_()) .wrapping_sub(&(*borrow).as_()); *borrow = Self::Base::from(result >= (Self::RADIX << 1)); result = result.wrapping_add(&(borrow.as_() * Self::RADIX)); debug_assert!(result < (Self::RADIX << 1)); *carry = Self::Base::from(result >= Self::RADIX); result = result - carry.as_() * Self::RADIX; return result.as_(); } } /// Radix=*10* / storage=*u8* #[derive(Copy, Clone, Debug, Default)] pub struct RADIX_10_u8; /// Radix=*10,000* storage=*i16* #[derive(Copy, Clone, Debug, Default)] pub struct RADIX_10p4_i16; /// Radix=*1,000,000,000* storage=*u32* #[derive(Copy, Clone, Debug, Default)] pub struct RADIX_10p9_u32; /// Radix=*10,000,000,000,000,000,000* storage=*u64* #[derive(Copy, Clone, Debug, Default)] pub struct RADIX_10p19_u64; /// Radix = 2^32 #[derive(Copy, Clone, Debug, Default)] pub struct RADIX_u32; /// Radix = 2^64 #[derive(Copy, Clone, Debug, Default)] pub struct RADIX_u64; pub(crate) trait RadixPowerOfTen: RadixType { const DIGITS: usize; /// convert number of digits to number of big-digits fn divceil_digit_count(digit_count: usize) -> usize { use num_integer::Integer; Integer::div_ceil(&digit_count, &Self::DIGITS) } /// convert number of digits to number of big-digits fn divmod_digit_count(digit_count: usize) -> (usize, usize) { use num_integer::Integer; Integer::div_rem(&digit_count, &Self::DIGITS) } } impl RadixPowerOfTen for RADIX_10p19_u64 { const DIGITS: usize = 19; } impl RadixPowerOfTen for RADIX_10p9_u32 { const DIGITS: usize = 9; } impl RadixPowerOfTen for RADIX_10_u8 { const DIGITS: usize = 1; } impl RadixPowerOfTen for RADIX_10p4_i16 { const DIGITS: usize = 4; } impl RADIX_10p19_u64 { /// Divide double-wide u64 by radix, storing the quotient in the low u64, /// and returning the remainder pub(crate) fn rotating_div_u64_radix(hi: u64, lo: &mut u64) -> ::Base { use num_integer::div_rem; type BaseDouble = ::BaseDouble; let num = BaseDouble::from(*lo) + (BaseDouble::from(hi) << 64); let (q, r) = div_rem(num, Self::RADIX); *lo = q.as_(); r.as_() } } #[cfg(test)] mod test_validate { use super::*; macro_rules! impl_case { (valid $name:ident : $radix:ident ~ $values:expr) => { #[test] fn $name() { assert!($radix::validate_digits($values.iter())); } }; (invalid $name:ident : $radix:ident ~ $values:expr) => { #[test] fn $name() { assert!(!$radix::validate_digits($values.iter())); } }; } impl_case!(valid case_valid: RADIX_10p4_i16 ~ [1, 2, 3, 4, 5, 600]); impl_case!(invalid case_invalid_too_big: RADIX_10p4_i16 ~ [10000, 1, 2, 3, 4, 5, 600]); impl_case!(invalid case_invalid_negative: RADIX_10p4_i16 ~ [1, 2, -3, 4, 5, 600]); impl_case!(invalid case_invalid_leading_zeros: RADIX_10p4_i16 ~ [0, 1, 2, -3, 4, 5, 600]); impl_case!(invalid case_p9_toobig: RADIX_10p9_u32 ~ [3330199352]); } impl RadixType for RADIX_u32 { type Base = u32; type BaseDouble = u64; type SignedBase = i32; const RADIX: Self::BaseDouble = 1u64 << 32; // all u32 are valid in this radix fn validate_digits<'a, I: IntoIterator>(_: I) -> bool { true } fn expanding_add(a: u32, b: u32) -> (u32, u32) { let (sum, overflow) = a.overflowing_add(b); (u32::from(overflow), sum) } } impl RadixType for RADIX_u64 { type Base = u64; type BaseDouble = u128; type SignedBase = i64; const RADIX: Self::BaseDouble = 1u128 << 64; // all u64 are valid in this radix fn validate_digits<'a, I: IntoIterator>(_: I) -> bool { true } fn expanding_add(a: u64, b: u64) -> (u64, u64) { let (sum, overflow) = a.overflowing_add(b); (u64::from(overflow), sum) } } impl RadixType for RADIX_10p4_i16 { type Base = i16; type BaseDouble = i32; type SignedBase = i64; const RADIX: Self::BaseDouble = 10_000; } impl RadixType for RADIX_10p9_u32 { type Base = u32; type BaseDouble = u64; type SignedBase = i32; const RADIX: Self::BaseDouble = 1_000_000_000; } impl RadixType for RADIX_10p19_u64 { type Base = u64; type BaseDouble = u128; type SignedBase = i64; const RADIX: Self::BaseDouble = 10_000_000_000_000_000_000; } impl RadixType for RADIX_10_u8 { type Base = u8; type BaseDouble = u8; type SignedBase = i8; const RADIX: Self::BaseDouble = 10; } #[cfg(test)] mod tests { use super::*; include!("radix.tests.rs"); } bigdecimal-0.4.10/src/bigdigit/radix.tests.rs000064400000000000000000000042671046102023000171660ustar 00000000000000 mod radix_10p19_u64 { use super::*; use super::RADIX_10p19_u64 as Radix; #[test] fn split_wide_digit_10e19_0() { let (hi, lo) = Radix::split_wide_digit(0); assert_eq!(hi, 0); assert_eq!(lo, 0); } #[test] fn split_wide_digit_10e19_sqrd() { let (hi, lo) = Radix::split_wide_digit(99999999999999999980000000000000000001); assert_eq!(hi, 9999999999999999998); assert_eq!(lo, 1); } #[test] fn split_wide_digit_5060270152244608514849739578370464703() { let (hi, lo) = Radix::split_wide_digit(5060270152244608514849739578370464703); assert_eq!(hi, 506027015224460851); assert_eq!(lo, 4849739578370464703); } #[test] fn add_with_carry() { let mut carry = 20; let sum = Radix::add_carry(222292843123382, &mut carry); assert_eq!(sum, 222292843123402); assert_eq!(carry, 0); } #[test] fn add_with_carry_overflow_18446744073709551600_55() { let mut carry = 55; let sum = Radix::add_carry(18446744073709551600, &mut carry); assert_eq!(sum, 8446744073709551655); assert_eq!(carry, 1); } #[test] fn add_with_carry_overflow_2() { let result = &mut [0, 1, 2]; let mut carry = 40; Radix::add_carry_into_slice(result, &mut carry); assert_eq!(result, &[40, 1, 2]); assert_eq!(carry, 0); } } mod radix_u64 { use super::*; use super::RADIX_u64 as Radix; #[test] fn add_with_carry_overflow_1() { let mut carry = 55; let sum = Radix::add_carry(18446744073709551600, &mut carry); assert_eq!(sum, 39); assert_eq!(carry, 1); } #[test] fn add_with_carry_overflow_2() { let result = &mut 0; let mut carry = 40; Radix::addassign_carry(result, &mut carry); assert_eq!(*result, 40); assert_eq!(carry, 0); } #[test] fn add_with_carry_overflow_3() { let mut result = 3533561901698977160; let mut carry = 17004058994074047095; Radix::addassign_carry(&mut result, &mut carry); assert_eq!(result, 2090876822063472639); assert_eq!(carry, 1); } } bigdecimal-0.4.10/src/context.rs000064400000000000000000000230671046102023000146170ustar 00000000000000//! Define arithmetical context //! use crate::*; use stdlib::num::NonZeroU64; use arithmetic::store_carry; use rounding::NonDigitRoundingData; // const DEFAULT_PRECISION: u64 = ${RUST_BIGDECIMAL_DEFAULT_PRECISION} or 100; include!(concat!(env!("OUT_DIR"), "/default_precision.rs")); /// Mathematical Context /// /// Stores rules for numerical operations, such as how to round and /// number of digits to keep. /// /// Defaults are defined at compile time, determined by environment /// variables: /// /// | Variable | Description | default | /// |-----------------------------------------|-----------------|----------| /// | `RUST_BIGDECIMAL_DEFAULT_PRECISION` | digit precision | 100 | /// | `RUST_BIGDECIMAL_DEFAULT_ROUNDING_MODE` | rounding-mode | HalfEven | /// /// It is recommended that the user set explicit values of a Context and *not* /// rely on compile time constants, but the option is there if necessary. /// #[derive(Debug, Clone)] pub struct Context { /// total number of digits precision: NonZeroU64, /// how to round rounding: RoundingMode, } impl Context { /// Create context with precision and rounding mode pub fn new(precision: NonZeroU64, rounding: RoundingMode) -> Self { Context { precision: precision, rounding: rounding, } } /// Copy context with new precision value pub fn with_precision(&self, precision: NonZeroU64) -> Self { Self { precision: precision, ..*self } } /// Copy context with new precision value pub fn with_prec(&self, precision: T) -> Option { precision .to_u64() .and_then(NonZeroU64::new) .map(|prec| self.with_precision(prec)) } /// Copy context with new rounding mode pub fn with_rounding_mode(&self, mode: RoundingMode) -> Self { Self { rounding: mode, ..*self } } /// Rounding mode 'Down' for truncating results when /// proper rounding is not necessary pub(crate) fn new_truncating(prec: u64) -> Self { Self { rounding: RoundingMode::Down, precision: NonZeroU64::new(prec.max(1)).unwrap(), } } /// Return maximum precision pub fn precision(&self) -> NonZeroU64 { self.precision } /// Return rounding mode pub fn rounding_mode(&self) -> RoundingMode { self.rounding } /// Round decimal to precision in this context, using rounding-mode pub fn round_decimal(&self, n: BigDecimal) -> BigDecimal { n.with_precision_round(self.precision(), self.rounding_mode()) } /// Round decimal to precision in this context, using rounding-mode pub fn round_decimal_ref<'a, D: Into>>(&self, n: D) -> BigDecimal { let d = n.into().to_owned(); d.with_precision_round(self.precision(), self.rounding_mode()) } /// Round the bigint to the context's precision, returning it along with /// the scale indicating how man digits were removed #[allow(dead_code)] pub(crate) fn round_bigint( self, n: num_bigint::BigInt ) -> WithScale { self.rounding.round_bigint_to_prec(n, self.precision) } /// Round the biguint to the context's precision, returning it along with /// the scale indicating how man digits were removed #[allow(dead_code)] pub(crate) fn round_biguint( self, n: num_bigint::BigUint ) -> WithScale { let ndrd = NonDigitRoundingData { mode: self.rounding, sign: Sign::Plus }; ndrd.round_biguint_to_prec(n, self.precision) } /// Round digits x and y with the rounding mode #[allow(dead_code)] pub(crate) fn round_pair(&self, sign: Sign, x: u8, y: u8, trailing_zeros: bool) -> u8 { self.rounding.round_pair(sign, (x, y), trailing_zeros) } /// Round digits x and y with the rounding mode #[allow(dead_code)] pub(crate) fn round_pair_with_carry( &self, sign: Sign, x: u8, y: u8, trailing_zeros: bool, carry: &mut u8, ) -> u8 { self.rounding.round_pair_with_carry(sign, (x, y), trailing_zeros, carry) } /// Multiply two decimals, returning product rounded to this Context's precision /// /// ``` /// # use bigdecimal::{BigDecimal, Context}; /// let x: BigDecimal = "1.5".parse().unwrap(); /// let y: BigDecimal = "3.1415926".parse().unwrap(); /// /// let ctx = Context::default().with_prec(5).unwrap(); /// let product = ctx.multiply(&x, &y); /// /// // rounds to 5 digits of precision /// assert_eq!(product, "4.7124".parse::().unwrap()); /// // does not equal the 'full' precision /// assert_ne!(product, "4.71238890".parse::().unwrap()); /// ``` /// pub fn multiply<'a, L, R>(&self, lhs: L, rhs: R) -> BigDecimal where L: Into>, R: Into>, { use arithmetic::multiplication::multiply_decimals_with_context; let mut result = BigDecimal::zero(); multiply_decimals_with_context(&mut result, lhs, rhs, self); result } /// Calculate `1/n`, rounding at this Context's precision /// /// If n is zero, return zero. /// /// ``` /// # use bigdecimal::{BigDecimal, Context}; /// let x: BigDecimal = "3".parse().unwrap(); /// /// let ctx = Context::default().with_prec(5).unwrap(); /// let one_over_three = ctx.invert(&x); /// /// // rounds to 5 digits of precision /// assert_eq!(one_over_three, "0.33333".parse::().unwrap()); /// ``` /// pub fn invert<'a, T: Into>>(&self, n: T) -> BigDecimal { n.into().inverse_with_context(self) } } impl stdlib::default::Default for Context { fn default() -> Self { Self { precision: NonZeroU64::new(DEFAULT_PRECISION).unwrap(), rounding: RoundingMode::default(), } } } impl Context { /// Add two big digit references pub fn add_refs<'a, 'b, A, B>(&self, a: A, b: B) -> BigDecimal where A: Into>, B: Into>, { let mut sum = BigDecimal::zero(); self.add_refs_into(a, b, &mut sum); sum } /// Add two decimal refs, storing value in dest pub fn add_refs_into<'a, 'b, A, B>(&self, a: A, b: B, dest: &mut BigDecimal) where A: Into>, B: Into>, { let sum = a.into() + b.into(); *dest = sum.with_precision_round(self.precision, self.rounding) } } #[cfg(test)] mod test_context { use super::*; #[test] fn constructor_and_setters() { let ctx = Context::default(); let c = ctx.with_prec(44).unwrap(); assert_eq!(c.precision.get(), 44); assert_eq!(c.rounding, RoundingMode::HalfEven); let c = c.with_rounding_mode(RoundingMode::Down); assert_eq!(c.precision.get(), 44); assert_eq!(c.rounding, RoundingMode::Down); } #[test] fn sum_two_references() { use stdlib::ops::Neg; let ctx = Context::default(); let a: BigDecimal = "209682.134972197168613072130300".parse().unwrap(); let b: BigDecimal = "3.0782968222271332463325639E-12".parse().unwrap(); let sum = ctx.add_refs(&a, &b); let expected: BigDecimal = "209682.1349721971716913689525271332463325639".parse().unwrap(); assert_eq!(sum, expected); // make negative copy of b without cloning values let neg_b = b.to_ref().neg(); let sum = ctx.add_refs(&a, neg_b); let expected: BigDecimal = "209682.1349721971655347753080728667536674361".parse().unwrap(); assert_eq!(sum, expected); let sum = ctx.with_prec(27).unwrap().with_rounding_mode(RoundingMode::Up).add_refs(&a, neg_b); let expected: BigDecimal = "209682.134972197165534775309".parse().unwrap(); assert_eq!(sum, expected); } mod round_decimal_ref { use super::*; #[test] fn case_bigint_1234567_prec3() { let ctx = Context::default().with_prec(3).unwrap(); let i = BigInt::from(1234567); let d = ctx.round_decimal_ref(&i); assert_eq!(d.int_val, 123.into()); assert_eq!(d.scale, -4); } #[test] fn case_bigint_1234500_prec4_halfup() { let ctx = Context::default() .with_prec(4).unwrap() .with_rounding_mode(RoundingMode::HalfUp); let i = BigInt::from(1234500); let d = ctx.round_decimal_ref(&i); assert_eq!(d.int_val, 1235.into()); assert_eq!(d.scale, -3); } #[test] fn case_bigint_1234500_prec4_halfeven() { let ctx = Context::default() .with_prec(4).unwrap() .with_rounding_mode(RoundingMode::HalfEven); let i = BigInt::from(1234500); let d = ctx.round_decimal_ref(&i); assert_eq!(d.int_val, 1234.into()); assert_eq!(d.scale, -3); } #[test] fn case_bigint_1234567_prec10() { let ctx = Context::default().with_prec(10).unwrap(); let i = BigInt::from(1234567); let d = ctx.round_decimal_ref(&i); assert_eq!(d.int_val, 1234567000.into()); assert_eq!(d.scale, 3); } } } bigdecimal-0.4.10/src/impl_cmp.rs000064400000000000000000000415251046102023000147320ustar 00000000000000//! Implementation of comparison operations //! //! Comparisons between decimals and decimal refs //! are not directly supported as we lose some type //! inference features at the savings of a single //! '&' character. //! //! &BigDecimal and BigDecimalRef are comparable. //! use crate::*; use stdlib::cmp::Ordering; use stdlib::iter; impl PartialEq for BigDecimal { fn eq(&self, rhs: &BigDecimal) -> bool { self.to_ref() == rhs.to_ref() } } impl<'rhs, T> PartialEq for BigDecimalRef<'_> where T: Into> + Copy, { fn eq(&self, rhs: &T) -> bool { let rhs: BigDecimalRef<'rhs> = (*rhs).into(); check_equality_bigdecimal_ref(*self, rhs) } } fn check_equality_bigdecimal_ref(lhs: BigDecimalRef, rhs: BigDecimalRef) -> bool { match (lhs.sign(), rhs.sign()) { // both zero (Sign::NoSign, Sign::NoSign) => return true, // signs are different (a, b) if a != b => return false, // signs are same, do nothing _ => {} } let unscaled_int; let scaled_int; let trailing_zero_count; match arithmetic::checked_diff(lhs.scale, rhs.scale) { (Ordering::Equal, _) => { return lhs.digits == rhs.digits; } (Ordering::Greater, Some(scale_diff)) => { unscaled_int = lhs.digits; scaled_int = rhs.digits; trailing_zero_count = scale_diff; } (Ordering::Less, Some(scale_diff)) => { unscaled_int = rhs.digits; scaled_int = lhs.digits; trailing_zero_count = scale_diff; } _ => { // all other cases imply overflow in difference of scale, // numbers must not be equal return false; } } debug_assert_ne!(trailing_zero_count, 0); // test if unscaled_int is guaranteed to be less than // scaled_int*10^trailing_zero_count based on highest bit if highest_bit_lessthan_scaled(unscaled_int, scaled_int, trailing_zero_count) { return false; } // try compare without allocating if trailing_zero_count < 20 { let pow = ten_to_the_u64(trailing_zero_count as u8); let mut a_digits = unscaled_int.iter_u32_digits(); let mut b_digits = scaled_int.iter_u32_digits(); let mut carry = 0; loop { match (a_digits.next(), b_digits.next()) { (Some(next_a), Some(next_b)) => { let wide_b = match (next_b as u64).checked_mul(pow) { Some(tmp) => tmp + carry, None => break, }; let true_b = wide_b as u32; if next_a != true_b { return false; } carry = wide_b >> 32; } (None, Some(_)) => { return false; } (Some(a_digit), None) => { if a_digit != (carry as u32) { return false; } carry = 0; } (None, None) => { return carry == 0; } } } // we broke out of loop due to overflow - compare via allocation let scaled_int = scaled_int * pow; return &scaled_int == unscaled_int; } let trailing_zero_count = trailing_zero_count.to_usize().unwrap(); let unscaled_digits = unscaled_int.to_radix_le(10); if trailing_zero_count > unscaled_digits.len() { return false; } // split into digits below the other value, and digits overlapping let (low_digits, overlap_digits) = unscaled_digits.split_at(trailing_zero_count); // if any of the low digits are zero, they are not equal if low_digits.iter().any(|&d| d != 0) { return false; } let scaled_digits = scaled_int.to_radix_le(10); // different lengths with trailing zeros if overlap_digits.len() != scaled_digits.len() { return false; } // return true if all digits are the same overlap_digits.iter().zip(scaled_digits.iter()).all(|(digit_a, digit_b)| digit_a == digit_b) } impl PartialOrd for BigDecimal { #[inline] fn partial_cmp(&self, other: &BigDecimal) -> Option { Some(self.cmp(other)) } } impl PartialOrd for BigDecimalRef<'_> { fn partial_cmp(&self, other: &BigDecimalRef<'_>) -> Option { Some(self.cmp(other)) } } impl Ord for BigDecimal { #[inline] fn cmp(&self, other: &BigDecimal) -> Ordering { self.to_ref().cmp(&other.to_ref()) } } impl Ord for BigDecimalRef<'_> { /// 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: &BigDecimalRef) -> Ordering { use Ordering::*; let scmp = self.sign().cmp(&other.sign()); if scmp != Ordering::Equal { return scmp; } if self.sign() == Sign::NoSign { return Ordering::Equal; } let result = match arithmetic::checked_diff(self.scale, other.scale) { (Greater, Some(scale_diff)) | (Equal, Some(scale_diff)) => { compare_scaled_biguints(self.digits, other.digits, scale_diff) } (Less, Some(scale_diff)) => { compare_scaled_biguints(other.digits, self.digits, scale_diff).reverse() } (res, None) => { // The difference in scale does not fit in a u64, // we can safely assume the value of digits do not matter // (unless we have a 2^64 (i.e. ~16 exabyte) long number // larger scale means smaller number, reverse this ordering res.reverse() } }; if other.sign == Sign::Minus { result.reverse() } else { result } } } /// compare scaled uints: a <=> b * 10^{scale_diff} /// fn compare_scaled_biguints(a: &BigUint, b: &BigUint, scale_diff: u64) -> Ordering { use Ordering::*; if scale_diff == 0 { return a.cmp(b); } // check if highest bit of a is less than b * 10^scale_diff if highest_bit_lessthan_scaled(a, b, scale_diff) { return Ordering::Less; } // if biguints fit it u64 or u128, compare using those (avoiding allocations) if let Some(result) = compare_scalar_biguints(a, b, scale_diff) { return result; } let a_digit_count = count_decimal_digits_uint(a); let b_digit_count = count_decimal_digits_uint(b); let digit_count_cmp = a_digit_count.cmp(&(b_digit_count + scale_diff)); if digit_count_cmp != Equal { return digit_count_cmp; } let a_digits = a.to_radix_le(10); let b_digits = b.to_radix_le(10); debug_assert_eq!(a_digits.len(), a_digit_count as usize); debug_assert_eq!(b_digits.len(), b_digit_count as usize); let mut a_it = a_digits.iter().rev(); let mut b_it = b_digits.iter().rev(); loop { match (a_it.next(), b_it.next()) { (Some(ai), Some(bi)) => { match ai.cmp(bi) { Equal => continue, result => return result, } } (Some(&ai), None) => { if ai == 0 && a_it.all(Zero::is_zero) { return Equal; } else { return Greater; } } (None, Some(&bi)) => { if bi == 0 && b_it.all(Zero::is_zero) { return Equal; } else { return Less; } } (None, None) => { return Equal; } } } } /// Try fitting biguints into primitive integers, using those for ordering if possible fn compare_scalar_biguints(a: &BigUint, b: &BigUint, scale_diff: u64) -> Option { let scale_diff = scale_diff.to_usize()?; // try u64, then u128 compare_scaled_uints::(a, b, scale_diff) .or_else(|| compare_scaled_uints::(a, b, scale_diff)) } /// Implementation comparing biguints cast to generic type fn compare_scaled_uints<'a, T>( a: &'a BigUint, b: &'a BigUint, scale_diff: usize, ) -> Option where T: num_traits::PrimInt + TryFrom<&'a BigUint>, { let ten = T::from(10).unwrap(); let a = T::try_from(a).ok(); let b = T::try_from(b).ok().and_then( |b| num_traits::checked_pow(ten, scale_diff).and_then( |p| b.checked_mul(&p))); match (a, b) { (Some(a), Some(scaled_b)) => Some(a.cmp(&scaled_b)), // if scaled_b doesn't fit in size T, while 'a' does, then a is certainly less (Some(_), None) => Some(Ordering::Less), // if a doesn't fit in size T, while 'scaled_b' does, then a is certainly greater (None, Some(_)) => Some(Ordering::Greater), // neither fits, cannot determine relative size (None, None) => None, } } /// Return highest_bit(a) < highest_bit(b * 10^{scale}) /// /// Used for optimization when comparing scaled integers /// /// ```math /// a < b * 10^{scale} /// log(a) < log(b) + scale * log(10) /// ``` /// fn highest_bit_lessthan_scaled(a: &BigUint, b: &BigUint, scale: u64) -> bool { let a_bits = a.bits(); let b_bits = b.bits(); if a_bits < b_bits { return true; } let log_scale = LOG2_10 * scale as f64; match b_bits.checked_add(log_scale as u64) { Some(scaled_b_bit) => a_bits < scaled_b_bit, None => true, // overflowing u64 means we are definitely bigger } } macro_rules! impl_prim_cmp { ($t:ty) => { impl PartialOrd<$t> for BigDecimal { fn partial_cmp(&self, other: &$t) -> Option { self.to_ref().partial_cmp(other) } } impl PartialEq<$t> for BigDecimal { fn eq(&self, rhs: &$t) -> bool { self.to_ref().eq(rhs) } } impl PartialOrd<$t> for &BigDecimal { fn partial_cmp(&self, other: &$t) -> Option { self.to_ref().partial_cmp(other) } } impl PartialOrd<$t> for BigDecimalRef<'_> { fn partial_cmp(&self, other: &$t) -> Option { let rhs = BigDecimal::from(other); self.partial_cmp(&rhs.to_ref()) } } impl PartialEq<$t> for &BigDecimal { fn eq(&self, rhs: &$t) -> bool { self.to_ref().eq(rhs) } } impl PartialEq<$t> for BigDecimalRef<'_> { fn eq(&self, rhs: &$t) -> bool { let rhs = BigDecimal::from(rhs); check_equality_bigdecimal_ref(*self, rhs.to_ref()) } } }; } impl_prim_cmp!(u8); impl_prim_cmp!(u16); impl_prim_cmp!(u32); impl_prim_cmp!(u64); impl_prim_cmp!(u128); impl_prim_cmp!(i8); impl_prim_cmp!(i16); impl_prim_cmp!(i32); impl_prim_cmp!(i64); impl_prim_cmp!(i128); #[cfg(test)] mod test { use super::*; mod compare_scaled_biguints { use super::*; macro_rules! impl_test { ($name:ident: $a:literal > $b:literal e $e:literal) => { impl_test!($name: $a Greater $b e $e); }; ($name:ident: $a:literal < $b:literal e $e:literal) => { impl_test!($name: $a Less $b e $e); }; ($name:ident: $a:literal = $b:literal e $e:literal) => { impl_test!($name: $a Equal $b e $e); }; ($name:ident: $a:literal $op:ident $b:literal e $e:literal) => { #[test] fn $name() { let a: BigUint = $a.parse().unwrap(); let b: BigUint = $b.parse().unwrap(); let result = compare_scaled_biguints(&a, &b, $e); assert_eq!(result, Ordering::$op); } }; } impl_test!(case_500_51e1: "500" < "51" e 1); impl_test!(case_500_44e1: "500" > "44" e 1); impl_test!(case_5000_50e2: "5000" = "50" e 2); impl_test!(case_1234e9_12345e9: "1234000000000" < "12345" e 9); impl_test!(case_1116xx459_759xx717e2: "1116386634271380982470843247639640260491505327092723527088459" < "759522625769651746138617259189939751893902453291243506584717" e 2); } /// Test that large-magnitidue exponentials will not crash #[test] fn test_cmp_on_exp_boundaries() { let a = BigDecimal::new(1.into(), i64::MAX); let z = BigDecimal::new(1.into(), i64::MIN); assert_ne!(a, z); assert_ne!(z, a); assert!(a < z); assert_eq!(a, a); assert_eq!(z, z); } mod ord { use super::*; macro_rules! impl_test { ($name:ident: $a:literal < $b:literal) => { #[test] fn $name() { let a: BigDecimal = $a.parse().unwrap(); let b: BigDecimal = $b.parse().unwrap(); assert!(&a < &b); assert!(&b > &a); assert_ne!(a, b); } }; } impl_test!(case_diff_signs: "-1" < "1"); impl_test!(case_n1_0: "-1" < "0"); impl_test!(case_0_1: "0" < "1"); impl_test!(case_1d2345_1d2346: "1.2345" < "1.2346"); impl_test!(case_compare_extreme: "1e-9223372036854775807" < "1"); impl_test!(case_compare_extremes: "1e-9223372036854775807" < "1e9223372036854775807"); impl_test!(case_small_difference: "472697816888807260.1604" < "472697816888807260.16040000000000000000001"); impl_test!(case_very_small_diff: "-1.0000000000000000000000000000000000000000000000000001" < "-1"); impl_test!(case_1_2p128: "1" < "340282366920938463463374607431768211455"); impl_test!(case_1_1e39: "1000000000000000000000000000000000000000" < "1e41"); impl_test!(case_1d414xxx573: "1.414213562373095048801688724209698078569671875376948073176679730000000000000000000000000000000000000" < "1.41421356237309504880168872420969807856967187537694807317667974000000000"); impl_test!(case_11d414xxx573: "1.414213562373095048801688724209698078569671875376948073176679730000000000000000000000000000000000000" < "11.41421356237309504880168872420969807856967187537694807317667974000000000"); } mod eq { use super::*; macro_rules! impl_test { ($name:ident: $a:literal = $b:literal) => { #[test] fn $name() { let a: BigDecimal = $a.parse().unwrap(); let b: BigDecimal = $b.parse().unwrap(); assert_eq!(&a, &b); assert_eq!(a, b); } }; } impl_test!(case_zero: "0" = "0.00"); impl_test!(case_1_1d00: "1" = "1.00"); impl_test!(case_n1_n1000en3: "-1" = "-1000e-3"); impl_test!(case_0d000034500_345en7: "0.000034500" = "345e-7"); } #[test] fn test_borrow_neg_cmp() { let x: BigDecimal = "1514932018891593.916341142773".parse().unwrap(); let y: BigDecimal = "1514932018891593916341142773e-12".parse().unwrap(); assert_eq!(x, y); let x_ref = x.to_ref(); assert_eq!(x_ref, &y); assert_ne!(x_ref.neg(), x_ref); assert_eq!(x_ref.neg().neg(), x_ref); } mod cmp_prim { use super::*; #[test] fn cmp_zero_u8() { let n = BigDecimal::zero(); assert!(&n == 0u8); } } #[cfg(property_tests)] mod prop { use super::*; use proptest::prelude::*; proptest! { #![proptest_config(ProptestConfig { cases: 5000, ..Default::default() })] #[test] fn cmp_matches_f64( f in proptest::num::f64::NORMAL | proptest::num::f64::SUBNORMAL | proptest::num::f64::ZERO, g in proptest::num::f64::NORMAL | proptest::num::f64::SUBNORMAL | proptest::num::f64::ZERO ) { let a: BigDecimal = BigDecimal::from_f64(f).unwrap(); let b: BigDecimal = BigDecimal::from_f64(g).unwrap(); let expected = PartialOrd::partial_cmp(&f, &g).unwrap(); let value = a.cmp(&b); prop_assert_eq!(expected, value) } } } } bigdecimal-0.4.10/src/impl_convert.rs000064400000000000000000000034341046102023000156300ustar 00000000000000//! Code for implementing From/To BigDecimals use crate::BigDecimal; use crate::stdlib::convert::TryFrom; use num_bigint::BigInt; macro_rules! impl_from_int_primitive { ($t:ty) => { impl From<$t> for BigDecimal { fn from(n: $t) -> Self { BigDecimal { int_val: n.into(), scale: 0, } } } impl From<&$t> for BigDecimal { fn from(n: &$t) -> Self { BigDecimal { int_val: (*n).into(), scale: 0, } } } }; } impl_from_int_primitive!(u8); impl_from_int_primitive!(u16); impl_from_int_primitive!(u32); impl_from_int_primitive!(u64); impl_from_int_primitive!(u128); impl_from_int_primitive!(i8); impl_from_int_primitive!(i16); impl_from_int_primitive!(i32); impl_from_int_primitive!(i64); impl_from_int_primitive!(i128); impl TryFrom for BigDecimal { type Error = super::ParseBigDecimalError; #[inline] fn try_from(n: f32) -> Result { crate::parsing::try_parse_from_f32(n) } } impl TryFrom for BigDecimal { type Error = super::ParseBigDecimalError; #[inline] fn try_from(n: f64) -> Result { crate::parsing::try_parse_from_f64(n) } } impl From for BigDecimal { fn from(int_val: BigInt) -> Self { BigDecimal { int_val: int_val, scale: 0, } } } // Anything that may be a big-integer paired with a scale // parameter may be a bigdecimal impl> From<(T, i64)> for BigDecimal { fn from((int_val, scale): (T, i64)) -> Self { Self { int_val: int_val.into(), scale: scale, } } } bigdecimal-0.4.10/src/impl_fmt.rs000064400000000000000000001521271046102023000147420ustar 00000000000000//! Implementation of std::fmt traits & other stringification functions //! use crate::*; use rounding::{NonDigitRoundingData, InsigData}; use stdlib::fmt::Write; use stdlib::num::NonZeroUsize; // const EXPONENTIAL_FORMAT_LEADING_ZERO_THRESHOLD: usize = ${RUST_BIGDECIMAL_FMT_EXPONENTIAL_LOWER_THRESHOLD} or 5; // const EXPONENTIAL_FORMAT_TRAILING_ZERO_THRESHOLD: usize = ${RUST_BIGDECIMAL_FMT_EXPONENTIAL_UPPER_THRESHOLD} or 15; // const FMT_MAX_INTEGER_PADDING: usize = = ${RUST_BIGDECIMAL_FMT_MAX_INTEGER_PADDING} or 1000; include!(concat!(env!("OUT_DIR"), "/exponential_format_threshold.rs")); impl fmt::Display for BigDecimal { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { dynamically_format_decimal( self.to_ref(), f, EXPONENTIAL_FORMAT_LEADING_ZERO_THRESHOLD, EXPONENTIAL_FORMAT_TRAILING_ZERO_THRESHOLD, ) } } impl fmt::Display for BigDecimalRef<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { dynamically_format_decimal( *self, f, EXPONENTIAL_FORMAT_LEADING_ZERO_THRESHOLD, EXPONENTIAL_FORMAT_TRAILING_ZERO_THRESHOLD, ) } } impl fmt::LowerExp for BigDecimal { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::LowerExp::fmt(&self.to_ref(), f) } } impl fmt::LowerExp for BigDecimalRef<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (abs_int, scale) = get_abs_int_scale(*self); format_exponential(f, abs_int, self.sign, scale, "e") } } impl fmt::UpperExp for BigDecimal { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::UpperExp::fmt(&self.to_ref(), f) } } impl fmt::UpperExp for BigDecimalRef<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (abs_int, scale) = get_abs_int_scale(*self); format_exponential(f, abs_int, self.sign, scale, "E") } } impl fmt::Debug for BigDecimal { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if f.alternate() { write!(f, "BigDecimal(\"{}e{:}\")", self.int_val, -self.scale) } else { write!(f, "BigDecimal(sign={:?}, scale={}, digits={:?})", self.sign(), self.scale, self.int_val.magnitude().to_u64_digits() ) } } } fn get_abs_int_scale(this: BigDecimalRef) -> (String, i64) { // Acquire the absolute integer as a decimal string let abs_int = this.digits.to_str_radix(10); // Special-case 0: no zero-padding should be done. let scale = if this.is_zero() { 0 } else { this.scale }; (abs_int, scale) } fn dynamically_format_decimal( this: BigDecimalRef, f: &mut fmt::Formatter, leading_zero_threshold: usize, trailing_zero_threshold: usize, ) -> fmt::Result { let (abs_int, scale) = get_abs_int_scale(this); // number of zeros between most significant digit and decimal point let leading_zero_count = scale .to_u64() .and_then(|scale| scale.checked_sub(abs_int.len() as u64)) .unwrap_or(0); // number of zeros between least significant digit and decimal point let trailing_zero_count = scale .checked_neg() .and_then(|d| d.to_u64()); // this ignores scientific-formatting if precision is requested let trailing_zeros = f.precision().map(|_| 0) .or(trailing_zero_count) .unwrap_or(0); let leading_zero_threshold = leading_zero_threshold as u64; let trailing_zero_threshold = trailing_zero_threshold as u64; // use exponential form if decimal point is outside // the upper and lower thresholds of the decimal, // and precision was not requested if f.precision().is_none() && leading_zero_threshold < leading_zero_count { format_exponential(f, abs_int, this.sign, scale, "E") } else if trailing_zero_threshold < trailing_zeros { // non-scientific notation format_dotless_exponential(f, abs_int, this.sign, scale, "e") } else { format_full_scale(f, abs_int, this.sign, scale) } } pub(crate) struct FullScaleFormatter<'a>(pub BigDecimalRef<'a>); impl fmt::Display for FullScaleFormatter<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let n = self.0; let non_negative = matches!(n.sign, Sign::Plus | Sign::NoSign); let mut digits = n.digits.to_string(); if n.scale <= 0 { digits.extend(stdlib::iter::repeat('0').take(n.scale.neg() as usize)); } else if n.scale < digits.len() as i64 { digits.insert(digits.len() - n.scale as usize, '.'); } else { let mut digit_vec = digits.into_bytes(); let dest_str_size = n.scale as usize + 2; let digit_count = digit_vec.len(); let leading_char_idx = dest_str_size - digit_count; digit_vec.resize(dest_str_size, b'0'); digit_vec.copy_within(0..digit_count, leading_char_idx); fill_slice(&mut digit_vec[..digit_count.min(leading_char_idx)], b'0'); digit_vec[1] = b'.'; digits = String::from_utf8(digit_vec).unwrap(); } f.pad_integral(non_negative, "", &digits) } } fn format_full_scale( f: &mut fmt::Formatter, abs_int: String, sign: Sign, scale: i64, ) -> fmt::Result { use stdlib::cmp::Ordering::*; let mut digits = abs_int.into_bytes(); let mut exp = 0; let non_negative = matches!(sign, Sign::Plus | Sign::NoSign); debug_assert_ne!(digits.len(), 0); let rounder = NonDigitRoundingData::default_with_sign(sign); if scale <= 0 { exp = (scale as i128).neg(); // format an integer value by adding trailing zeros to the right zero_right_pad_integer_ascii_digits(&mut digits, &mut exp, f.precision()); } else { let scale = scale as u64; // std::fmt 'precision' has same meaning as bigdecimal 'scale' // // interpret 'no-precision' to mean the same as matching the scale // of the deicmal (i.e. no padding or rounding) let target_scale = f.precision().and_then(|prec| prec.to_u64()).unwrap_or(scale); if scale < digits.len() as u64 { // format both integer and fractional digits (always 'trim' to precision) format_ascii_digits_with_integer_and_fraction(&mut digits, scale, target_scale, rounder); } else { // format only fractional digits format_ascii_digits_no_integer(&mut digits, scale, target_scale, rounder); } } // move digits back into String form let mut buf = String::from_utf8(digits).unwrap(); // add exp part to buffer (if not zero) if exp != 0 { write!(buf, "e{:+}", exp)?; } // write buffer to formatter f.pad_integral(non_negative, "", &buf) } /// Fill appropriate number of zeros and decimal point into Vec of (ascii/utf-8) digits /// /// Exponent is set to zero if zeros were added /// fn zero_right_pad_integer_ascii_digits( digits: &mut Vec, exp: &mut i128, // number of zeros after the decimal point target_scale: Option, ) { debug_assert!(*exp >= 0); debug_assert_ne!(digits.len(), 0); let integer_zero_count = match exp.to_usize() { Some(n) => n, None => { return; } }; // did not explicitly request precision, so we'll only // implicitly right-pad if less than this threshold. if target_scale.is_none() && integer_zero_count > 20 { // no padding return; } let fraction_zero_char_count; let decimal_place_idx; if let Some(frac_zero_count) = target_scale.and_then(NonZeroUsize::new) { // add one char for '.' if target_scale is not zero fraction_zero_char_count = frac_zero_count.get() + 1; // indicate we'll need to add a decimal point decimal_place_idx = Some(digits.len() + integer_zero_count); } else { fraction_zero_char_count = 0; decimal_place_idx = None; } let total_additional_zeros = integer_zero_count.saturating_add(fraction_zero_char_count); // no padding if out of bounds if total_additional_zeros > FMT_MAX_INTEGER_PADDING { return; } digits.resize(digits.len() + total_additional_zeros, b'0'); if let Some(decimal_place_idx) = decimal_place_idx { digits[decimal_place_idx] = b'.'; } // set exp to zero so it won't be written in `format_full_scale` *exp = 0; } /// Insert decimal point into digits_ascii_be, rounding or padding with zeros when necessary /// /// (digits_ascii_be, scale) represents a decimal with both integer and fractional digits. /// fn format_ascii_digits_with_integer_and_fraction( digits_ascii_be: &mut Vec, scale: u64, target_scale: u64, rounder: NonDigitRoundingData, ) { debug_assert!(scale < digits_ascii_be.len() as u64, "No integer digits"); let mut digit_scale = scale; // decimal has more fractional digits than requested: round (trimming insignificant digits) if target_scale < scale { let digit_count_to_remove = (scale - target_scale) .to_usize() .expect("Precision exceeds maximum usize"); let rounding_idx = NonZeroUsize::new(digits_ascii_be.len() - digit_count_to_remove) .expect("decimal must have integer digits"); // round and trim the digits at the 'rounding index' let scale_diff = round_ascii_digits(digits_ascii_be, rounding_idx, rounder); match scale_diff.checked_sub(digit_scale as usize) { None | Some(0) => { digit_scale -= scale_diff as u64; } Some(zeros_to_add) => { digits_ascii_be.resize(digits_ascii_be.len() + zeros_to_add, b'0'); digit_scale = 0; } } } // ignore the decimal point if the target scale is zero if target_scale != 0 { // there are both integer and fractional digits let integer_digit_count = (digits_ascii_be.len() as u64 - digit_scale) .to_usize() .expect("Number of digits exceeds maximum usize"); digits_ascii_be.insert(integer_digit_count, b'.'); } if digit_scale < target_scale { let trailing_zero_count = (target_scale - digit_scale) .to_usize() .expect("Too Big"); // precision required beyond scale digits_ascii_be.resize(digits_ascii_be.len() + trailing_zero_count, b'0'); digit_scale += trailing_zero_count as u64; } debug_assert_eq!(digit_scale, target_scale); } /// Insert decimal point into digits_ascii_be, rounding or padding with zeros when necessary /// /// (digits_ascii_be, scale) represents a decimal with only fractional digits. /// fn format_ascii_digits_no_integer( digits_ascii_be: &mut Vec, scale: u64, target_scale: u64, rounder: NonDigitRoundingData, ) { use stdlib::cmp::Ordering::*; debug_assert!(scale >= digits_ascii_be.len() as u64); let leading_zeros = scale - digits_ascii_be.len() as u64; match arithmetic::diff(target_scale, leading_zeros) { // handle rounding point before the start of digits (Less, intermediate_zeros) | (Equal, intermediate_zeros) => { // get insignificant digit let (insig_digit, trailing_digits) = if intermediate_zeros > 0 { (0, digits_ascii_be.as_slice()) } else { (digits_ascii_be[0] - b'0', &digits_ascii_be[1..]) }; let insig_data = InsigData::from_digit_and_lazy_trailing_zeros( rounder, insig_digit, || trailing_digits.iter().all(|&d| d == b'0') ); let rounded_digit = insig_data.round_digit(0); debug_assert_ne!(rounded_digit, 10); digits_ascii_be.clear(); if target_scale > 0 { digits_ascii_be.resize(target_scale as usize + 1, b'0'); } digits_ascii_be.push(rounded_digit + b'0'); if target_scale > 0 { digits_ascii_be[1] = b'.'; } } (Greater, sig_digit_count) => { let significant_digit_count = sig_digit_count .to_usize() .and_then(NonZeroUsize::new) .expect("Request overflow in sig_digit_count"); let mut digit_scale = scale; // if 'digits_ascii_be' has more digits than requested, round if significant_digit_count.get() < digits_ascii_be.len() { let removed_digit_count = round_ascii_digits( digits_ascii_be, significant_digit_count, rounder ); digit_scale -= removed_digit_count as u64; } // number of zeros to keep after the significant digits let trailing_zeros = target_scale - digit_scale; // expected length is target scale (number of digits after decimal point) + "0." let dest_len = target_scale as usize + 2; // number of significant digits is whatever is left in the digit vector let sig_digit_count = digits_ascii_be.len(); // index where to store significant digits let sig_digit_idx = dest_len - trailing_zeros as usize - sig_digit_count; // fill output with zeros digits_ascii_be.resize(dest_len, b'0'); // very likely case where there are digits after the decimal point if digit_scale != 0 { // copy significant digits to their index location digits_ascii_be.copy_within(..sig_digit_count, sig_digit_idx); // clear copied values fill_slice(&mut digits_ascii_be[..sig_digit_count.min(sig_digit_idx)], b'0'); } else { debug_assert_eq!(sig_digit_count, 1); } // add decimal point digits_ascii_be[1] = b'.'; } } } #[cfg(rust_1_50)] fn fill_slice(v: &mut [T], value: T) { v.fill(value); } #[cfg(not(rust_1_50))] fn fill_slice(v: &mut [T], value: T) { for i in v.iter_mut() { *i = value.clone(); } } /// Format integer as {int}e+{exp} /// /// Slightly different than scientific notation, /// fn format_dotless_exponential( f: &mut fmt::Formatter, mut abs_int: String, sign: Sign, scale: i64, e_symbol: &str, ) -> fmt::Result { debug_assert!(scale <= 0); write!(abs_int, "{}{:+}", e_symbol, -scale).unwrap(); let non_negative = matches!(sign, Sign::Plus | Sign::NoSign); f.pad_integral(non_negative, "", &abs_int) } fn format_exponential( f: &mut fmt::Formatter, abs_int: String, sign: Sign, scale: i64, e_symbol: &str, ) -> fmt::Result { // Steps: // 1. Truncate integer based on precision // 2. calculate exponent from the scale and the length of the internal integer // 3. Place decimal point after a single digit of the number, or omit if there is only a single digit // 4. Append `E{exponent}` and format the resulting string based on some `Formatter` flags let exp = (scale as i128).neg(); let digits = abs_int.into_bytes(); format_exponential_bigendian_ascii_digits( digits, sign, exp, f, e_symbol ) } fn format_exponential_bigendian_ascii_digits( mut digits: Vec, sign: Sign, mut exp: i128, f: &mut fmt::Formatter, e_symbol: &str, ) -> fmt::Result { // how many zeros to pad at the end of the decimal let mut extra_trailing_zero_count = 0; if let Some(prec) = f.precision() { // 'prec' is number of digits after the decimal point let total_prec = prec + 1; if total_prec < digits.len() { // round to smaller precision let rounder = NonDigitRoundingData::default_with_sign(sign); let target_scale = NonZeroUsize::new(total_prec).unwrap(); let delta_exp = round_ascii_digits(&mut digits, target_scale, rounder); exp += delta_exp as i128; } extra_trailing_zero_count = total_prec - digits.len(); } let needs_decimal_point = digits.len() > 1 || extra_trailing_zero_count > 0; let mut abs_int = String::from_utf8(digits).unwrap(); // Determine the exponent value based on the scale // // # First case: the integer representation falls completely behind the // decimal point. // // Example of this.scale > abs_int.len(): // 0.000001234509876 // abs_int.len() = 10 // scale = 15 // target is 1.234509876 // exponent = -6 // // Example of this.scale == abs_int.len(): // 0.333333333333333314829616256247390992939472198486328125 // abs_int.len() = 54 // scale = 54 // target is 3.33333333333333314829616256247390992939472198486328125 // exponent = -1 // // # Second case: the integer representation falls around, or before the // decimal point // // ## Case 2.1, entirely before the decimal point. // Example of (abs_int.len() - this.scale) > abs_int.len(): // 123450987600000 // abs_int.len() = 10 // scale = -5 // location = 15 // target is 1.234509876 // exponent = 14 // // ## Case 2.2, somewhere around the decimal point. // Example of (abs_int.len() - this.scale) < abs_int.len(): // 12.339999999999999857891452847979962825775146484375 // abs_int.len() = 50 // scale = 48 // target is 1.2339999999999999857891452847979962825775146484375 // exponent = 1 // // For the (abs_int.len() - this.scale) == abs_int.len() I couldn't // come up with an example let exponent = abs_int.len() as i128 + exp - 1; if needs_decimal_point { // only add decimal point if there is more than 1 decimal digit abs_int.insert(1, '.'); } if extra_trailing_zero_count > 0 { abs_int.extend(stdlib::iter::repeat('0').take(extra_trailing_zero_count)); } // always print exponent in exponential mode write!(abs_int, "{}{:+}", e_symbol, exponent)?; let non_negative = matches!(sign, Sign::Plus | Sign::NoSign); //pad_integral does the right thing although we have a decimal f.pad_integral(non_negative, "", &abs_int) } /// Round big-endian ascii digits to given significant digit count, /// updating the scale appropriately /// /// Returns the number of digits removed; this should be treated as the /// change in the decimal's scale, and should be subtracted from the scale /// when appropriate. /// fn round_ascii_digits( // bigendian ascii digits digits_ascii_be: &mut Vec, // number of significant digits to keep significant_digit_count: NonZeroUsize, // how to round rounder: NonDigitRoundingData, ) -> usize { debug_assert!(significant_digit_count.get() < digits_ascii_be.len()); let (sig_digits, insig_digits) = digits_ascii_be.split_at(significant_digit_count.get()); let (&insig_digit, trailing_digits) = insig_digits.split_first().unwrap_or((&b'0', &[])); let insig_data = InsigData::from_digit_and_lazy_trailing_zeros( rounder, insig_digit - b'0', || trailing_digits.iter().all(|&d| d == b'0') ); let rounding_digit_pos = significant_digit_count.get() - 1; let sig_digit = sig_digits[rounding_digit_pos] - b'0'; let rounded_digit = insig_data.round_digit(sig_digit); // record how many digits to remove (changes the 'scale') let mut removed_digit_count = insig_digits.len(); // discard insignificant digits (and rounding digit) digits_ascii_be.truncate(rounding_digit_pos); if rounded_digit < 10 { // simple case: no carrying/overflow, push rounded digit digits_ascii_be.push(rounded_digit + b'0'); return removed_digit_count; } // handle carrying the 1 debug_assert!(rounded_digit == 10); // carry the one past trailing 9's: replace them with zeros let next_non_nine_rev_pos = digits_ascii_be.iter().rev().position(|&d| d != b'9'); match next_non_nine_rev_pos { // number of nines to remove Some(backwards_nine_count) => { let digits_to_trim = backwards_nine_count + 1; let idx = digits_ascii_be.len() - digits_to_trim; // increment least significant non-nine zero digits_ascii_be[idx] += 1; // remove trailing nines digits_ascii_be.truncate(idx + 1); // count truncation removed_digit_count += digits_to_trim; } // all nines! overflow to 1.000 None => { digits_ascii_be.clear(); digits_ascii_be.push(b'1'); // all 'significant' digits were removed removed_digit_count += significant_digit_count.get(); } } // return the number of removed digits return removed_digit_count; } #[inline(never)] pub(crate) fn write_scientific_notation(n: &BigDecimal, w: &mut W) -> fmt::Result { if n.is_zero() { return w.write_str("0e0"); } if n.int_val.sign() == Sign::Minus { w.write_str("-")?; } let digits = n.int_val.magnitude(); let dec_str = digits.to_str_radix(10); let (first_digit, remaining_digits) = dec_str.as_str().split_at(1); w.write_str(first_digit)?; if !remaining_digits.is_empty() { w.write_str(".")?; w.write_str(remaining_digits)?; } write!(w, "e{}", remaining_digits.len() as i128 - n.scale as i128) } #[inline(never)] pub(crate) fn write_engineering_notation(n: &BigDecimal, out: &mut W) -> fmt::Result { if n.is_zero() { return out.write_str("0e0"); } if n.int_val.sign() == Sign::Minus { out.write_char('-')?; } let digits = n.int_val.magnitude(); let dec_str = digits.to_str_radix(10); let digit_count = dec_str.len(); let top_digit_exponent = digit_count as i128 - n.scale as i128; let shift_amount = match top_digit_exponent.rem_euclid(3) { 0 => 3, i => i as usize, }; let exp = top_digit_exponent - shift_amount as i128; // handle adding zero padding if let Some(padding_zero_count) = shift_amount.checked_sub(dec_str.len()) { let zeros = &"000"[..padding_zero_count]; out.write_str(&dec_str)?; out.write_str(zeros)?; return write!(out, "e{}", exp); } let (head, rest) = dec_str.split_at(shift_amount); debug_assert_eq!(exp % 3, 0); out.write_str(head)?; if !rest.is_empty() { out.write_char('.')?; out.write_str(rest)?; } return write!(out, "e{}", exp); } #[cfg(test)] #[allow(non_snake_case)] mod test { use super::*; use paste::*; /// test case builder for mapping decimal-string to formatted-string /// define test_fmt_function! macro to test your function #[cfg(test)] macro_rules! impl_case { ($name:ident : $in:literal => $ex:literal) => { #[test] fn $name() { let n: BigDecimal = $in.parse().unwrap(); let s = test_fmt_function!(n); assert_eq!(&s, $ex); } }; } /// "Mock" Formatter /// /// Given callable, forwards formatter to callable. /// Required work-around due to lack of constructor in fmt::Formatter /// struct Fmt(F) where F: Fn(&mut fmt::Formatter) -> fmt::Result; impl fmt::Display for Fmt where F: Fn(&mut fmt::Formatter) -> fmt::Result, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // call closure with given formatter (self.0)(f) } } impl fmt::Debug for Fmt where F: Fn(&mut fmt::Formatter) -> fmt::Result, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (self.0)(f) } } mod dynamic_fmt { use super::*; macro_rules! test_fmt_function { ($n:ident) => {{ format!("{}", Fmt(|f| dynamically_format_decimal($n.to_ref(), f, 2, 9))) }}; } impl_case!(case_0d123: "0.123" => "0.123"); impl_case!(case_0d0123: "0.0123" => "0.0123"); impl_case!(case_0d00123: "0.00123" => "0.00123"); impl_case!(case_0d000123: "0.000123" => "1.23E-4"); impl_case!(case_123d: "123." => "123"); impl_case!(case_123de1: "123.e1" => "1230"); } mod fmt_options { use super::*; macro_rules! impl_case { ($name:ident: $fmt:literal => $expected:literal) => { #[test] fn $name() { let x = test_input(); let y = format!($fmt, x); assert_eq!(y, $expected); } }; } mod dec_1 { use super::*; fn test_input() -> BigDecimal { "1".parse().unwrap() } impl_case!(fmt_default: "{}" => "1"); impl_case!(fmt_d1: "{:.1}" => "1.0"); impl_case!(fmt_d4: "{:.4}" => "1.0000"); impl_case!(fmt_4d1: "{:4.1}" => " 1.0"); impl_case!(fmt_r4d1: "{:>4.1}" => " 1.0"); impl_case!(fmt_l4d1: "{:<4.1}" => "1.0 "); impl_case!(fmt_p05d1: "{:+05.1}" => "+01.0"); impl_case!(fmt_e: "{:e}" => "1e+0"); impl_case!(fmt_E: "{:E}" => "1E+0"); } mod dec_1e1 { use super::*; fn test_input() -> BigDecimal { BigDecimal::new(1.into(), -1) } impl_case!(fmt_default: "{}" => "10"); impl_case!(fmt_debug: "{:?}" => "BigDecimal(sign=Plus, scale=-1, digits=[1])"); impl_case!(fmt_debug_alt: "{:#?}" => "BigDecimal(\"1e1\")"); impl_case!(fmt_d0: "{:.0}" => "10"); impl_case!(fmt_d1: "{:.1}" => "10.0"); impl_case!(fmt_d2: "{:.2}" => "10.00"); } mod dec_1en1 { use super::*; fn test_input() -> BigDecimal { BigDecimal::new(1.into(), 1) } impl_case!(fmt_default: "{}" => "0.1"); impl_case!(fmt_d0: "{:.0}" => "0"); impl_case!(fmt_d1: "{:.1}" => "0.1"); impl_case!(fmt_d2: "{:.2}" => "0.10"); } mod dec_9en1 { use super::*; fn test_input() -> BigDecimal { BigDecimal::new(9.into(), 1) } impl_case!(fmt_default: "{}" => "0.9"); impl_case!(fmt_d0: "{:.0}" => "1"); impl_case!(fmt_d1: "{:.1}" => "0.9"); impl_case!(fmt_d4: "{:.4}" => "0.9000"); } mod dec_800en3 { use super::*; fn test_input() -> BigDecimal { BigDecimal::new(800.into(), 3) } impl_case!(fmt_default: "{}" => "0.800"); impl_case!(fmt_d0: "{:.0}" => "1"); impl_case!(fmt_d1: "{:.1}" => "0.8"); impl_case!(fmt_d3: "{:.3}" => "0.800"); impl_case!(fmt_d9: "{:.9}" => "0.800000000"); } mod dec_123456 { use super::*; fn test_input() -> BigDecimal { "123456".parse().unwrap() } impl_case!(fmt_default: "{}" => "123456"); impl_case!(fmt_d1: "{:.1}" => "123456.0"); impl_case!(fmt_d4: "{:.4}" => "123456.0000"); impl_case!(fmt_4d1: "{:4.1}" => "123456.0"); impl_case!(fmt_15d2: "{:15.2}" => " 123456.00"); impl_case!(fmt_r15d2: "{:>15.2}" => " 123456.00"); impl_case!(fmt_l15d2: "{:<15.2}" => "123456.00 "); impl_case!(fmt_p05d1: "{:+05.7}" => "+123456.0000000"); } mod dec_d099995 { use super::*; fn test_input() -> BigDecimal { ".099995".parse().unwrap() } impl_case!(fmt_default: "{}" => "0.099995"); impl_case!(fmt_d0: "{:.0}" => "0"); impl_case!(fmt_d1: "{:.1}" => "0.1"); impl_case!(fmt_d3: "{:.3}" => "0.100"); } mod dec_d9999999 { use super::*; fn test_input() -> BigDecimal { ".9999999".parse().unwrap() } impl_case!(fmt_default: "{}" => "0.9999999"); impl_case!(fmt_d0: "{:.0}" => "1"); impl_case!(fmt_d1: "{:.1}" => "1.0"); impl_case!(fmt_d3: "{:.3}" => "1.000"); } mod dec_9999999 { use super::*; fn test_input() -> BigDecimal { "9999999".parse().unwrap() } impl_case!(fmt_default: "{}" => "9999999"); impl_case!(fmt_d1: "{:.1}" => "9999999.0"); impl_case!(fmt_d8: "{:.8}" => "9999999.00000000"); impl_case!(fmt_e: "{:e}" => "9.999999e+6"); impl_case!(fmt_E: "{:E}" => "9.999999E+6"); impl_case!(fmt_d0e: "{:.0e}" => "1e+7"); impl_case!(fmt_d1e: "{:.1e}" => "1.0e+7"); impl_case!(fmt_d2e: "{:.2e}" => "1.00e+7"); impl_case!(fmt_d4e: "{:.4e}" => "1.0000e+7"); impl_case!(fmt_d6e: "{:.6e}" => "9.999999e+6"); impl_case!(fmt_d7e: "{:.7e}" => "9.9999990e+6"); impl_case!(fmt_d10e: "{:.10e}" => "9.9999990000e+6"); } mod dec_19073d97235939614856 { use super::*; fn test_input() -> BigDecimal { "19073.97235939614856".parse().unwrap() } impl_case!(fmt_default: "{}" => "19073.97235939614856"); impl_case!(fmt_pd7: "{:+.7}" => "+19073.9723594"); impl_case!(fmt_d0: "{:.0}" => "19074"); impl_case!(fmt_d1: "{:.1}" => "19074.0"); impl_case!(fmt_d3: "{:.3}" => "19073.972"); impl_case!(fmt_d4: "{:.4}" => "19073.9724"); impl_case!(fmt_8d3: "{:8.3}" => "19073.972"); impl_case!(fmt_10d3: "{:10.3}" => " 19073.972"); impl_case!(fmt_010d3: "{:010.3}" => "019073.972"); } mod dec_10950633712399d557 { use super::*; fn test_input() -> BigDecimal { "10950633712399.557".parse().unwrap() } impl_case!(fmt_default: "{}" => "10950633712399.557"); impl_case!(fmt_d0: "{:.0}" => "10950633712400"); impl_case!(fmt_d1: "{:.1}" => "10950633712399.6"); impl_case!(fmt_d2: "{:.2}" => "10950633712399.56"); impl_case!(fmt_d3: "{:.3}" => "10950633712399.557"); impl_case!(fmt_d4: "{:.4}" => "10950633712399.5570"); } mod dec_n90037659d6902 { use super::*; fn test_input() -> BigDecimal { "-90037659.6905".parse().unwrap() } impl_case!(fmt_default: "{}" => "-90037659.6905"); impl_case!(fmt_debug: "{:?}" => "BigDecimal(sign=Minus, scale=4, digits=[900376596905])"); impl_case!(fmt_debug_alt: "{:#?}" => "BigDecimal(\"-900376596905e-4\")"); impl_case!(fmt_pd7: "{:+.7}" => "-90037659.6905000"); impl_case!(fmt_d0: "{:.0}" => "-90037660"); impl_case!(fmt_d3: "{:.3}" => "-90037659.690"); impl_case!(fmt_d4: "{:.4}" => "-90037659.6905"); impl_case!(fmt_14d4: "{:14.4}" => "-90037659.6905"); impl_case!(fmt_15d4: "{:15.4}" => " -90037659.6905"); impl_case!(fmt_l17d5: "{:<17.5}" => "-90037659.69050 "); } mod dec_0d0002394899999500 { use super::*; fn test_input() -> BigDecimal { "0.0002394899999500".parse().unwrap() } impl_case!(fmt_default: "{}" => "0.0002394899999500"); impl_case!(fmt_d0: "{:.0}" => "0"); impl_case!(fmt_d1: "{:.1}" => "0.0"); impl_case!(fmt_d3: "{:.3}" => "0.000"); impl_case!(fmt_d4: "{:.4}" => "0.0002"); impl_case!(fmt_d5: "{:.5}" => "0.00024"); impl_case!(fmt_d10: "{:.10}" => "0.0002394900"); impl_case!(fmt_d13: "{:.13}" => "0.0002394900000"); impl_case!(fmt_d14: "{:.14}" => "0.00023948999995"); impl_case!(fmt_d20: "{:.20}" => "0.00023948999995000000"); } mod dec_1764031078en13 { use super::*; fn test_input() -> BigDecimal { BigDecimal::new(1764031078.into(), 13) } impl_case!(fmt_default: "{}" => "0.0001764031078"); impl_case!(fmt_d1: "{:.1}" => "0.0"); impl_case!(fmt_d3: "{:.3}" => "0.000"); impl_case!(fmt_d4: "{:.4}" => "0.0002"); impl_case!(fmt_d5: "{:.5}" => "0.00018"); impl_case!(fmt_d13: "{:.13}" => "0.0001764031078"); impl_case!(fmt_d20: "{:.20}" => "0.00017640310780000000"); } mod dec_1e15 { use super::*; fn test_input() -> BigDecimal { "1e15".parse().unwrap() } impl_case!(fmt_default: "{}" => "1000000000000000"); impl_case!(fmt_d0: "{:.0}" => "1000000000000000"); impl_case!(fmt_d1: "{:.1}" => "1000000000000000.0"); } mod dec_1e16 { use super::*; fn test_input() -> BigDecimal { "1e16".parse().unwrap() } impl_case!(fmt_default: "{}" => "1e+16"); impl_case!(fmt_d0: "{:.0}" => "10000000000000000"); impl_case!(fmt_d2: "{:.2}" => "10000000000000000.00"); } mod dec_491326en12 { use super::*; fn test_input() -> BigDecimal { "491326e-12".parse().unwrap() } impl_case!(fmt_default: "{}" => "4.91326E-7"); impl_case!(fmt_d0: "{:.0}" => "0"); impl_case!(fmt_d1: "{:.1}" => "0.0"); impl_case!(fmt_d3: "{:.3}" => "0.000"); impl_case!(fmt_d5: "{:.5}" => "0.00000"); impl_case!(fmt_d6: "{:.7}" => "0.0000005"); impl_case!(fmt_d9: "{:.9}" => "0.000000491"); impl_case!(fmt_d20: "{:.20}" => "0.00000049132600000000"); impl_case!(fmt_d0e: "{:.0E}" => "5E-7"); impl_case!(fmt_d1e: "{:.1E}" => "4.9E-7"); impl_case!(fmt_d3e: "{:.3E}" => "4.913E-7"); impl_case!(fmt_d5e: "{:.5E}" => "4.91326E-7"); impl_case!(fmt_d6e: "{:.6E}" => "4.913260E-7"); } mod dec_0d00003102564500 { use super::*; fn test_input() -> BigDecimal { "0.00003102564500".parse().unwrap() } impl_case!(fmt_default: "{}" => "0.00003102564500"); impl_case!(fmt_d0: "{:.0}" => "0"); impl_case!(fmt_d1: "{:.1}" => "0.0"); impl_case!(fmt_d2: "{:.2}" => "0.00"); impl_case!(fmt_d4: "{:.4}" => "0.0000"); impl_case!(fmt_d5: "{:.5}" => "0.00003"); impl_case!(fmt_d10: "{:.10}" => "0.0000310256"); impl_case!(fmt_d14: "{:.14}" => "0.00003102564500"); impl_case!(fmt_d17: "{:.17}" => "0.00003102564500000"); impl_case!(fmt_e: "{:e}" => "3.102564500e-5"); impl_case!(fmt_de: "{:.e}" => "3.102564500e-5"); impl_case!(fmt_d0e: "{:.0e}" => "3e-5"); impl_case!(fmt_d1e: "{:.1e}" => "3.1e-5"); impl_case!(fmt_d4e: "{:.4e}" => "3.1026e-5"); } mod dec_1en100000 { use super::*; fn test_input() -> BigDecimal { "1E-10000".parse().unwrap() } impl_case!(fmt_default: "{}" => "1E-10000"); impl_case!(fmt_d: "{:.0}" => "0"); impl_case!(fmt_d1: "{:.1}" => "0.0"); impl_case!(fmt_d4: "{:.4}" => "0.0000"); impl_case!(fmt_d1E: "{:.1E}" => "1.0E-10000"); impl_case!(fmt_d4E: "{:.4E}" => "1.0000E-10000"); } mod dec_1e100000 { use super::*; fn test_input() -> BigDecimal { "1e100000".parse().unwrap() } impl_case!(fmt_default: "{}" => "1e+100000"); impl_case!(fmt_d1: "{:.1}" => "1e+100000"); impl_case!(fmt_d4: "{:.4}" => "1e+100000"); } mod dec_1234506789E5 { use super::*; fn test_input() -> BigDecimal { BigDecimal::new(1234506789.into(), -5) } impl_case!(fmt_default: "{}" => "123450678900000"); impl_case!(fmt_d1: "{:.1}" => "123450678900000.0"); impl_case!(fmt_d3: "{:.3}" => "123450678900000.000"); impl_case!(fmt_d4: "{:.4}" => "123450678900000.0000"); impl_case!(fmt_l13d4: "{:<23.4}" => "123450678900000.0000 "); impl_case!(fmt_r13d4: "{:>23.4}" => " 123450678900000.0000"); } mod dec_1234506789E15 { use super::*; fn test_input() -> BigDecimal { BigDecimal::new(1234506789.into(), -15) } impl_case!(fmt_default: "{}" => "1234506789000000000000000"); impl_case!(fmt_d1: "{:.1}" => "1234506789000000000000000.0"); impl_case!(fmt_d3: "{:.3}" => "1234506789000000000000000.000"); impl_case!(fmt_l13d4: "{:<+32.2}" => "+1234506789000000000000000.00 "); impl_case!(fmt_r13d4: "{:>+32.2}" => " +1234506789000000000000000.00"); } mod dec_13400476439814628800E2502 { use super::*; fn test_input() -> BigDecimal { BigDecimal::new(13400476439814628800u64.into(), -2502) } impl_case!(fmt_default: "{}" => "13400476439814628800e+2502"); impl_case!(fmt_d1: "{:.1}" => "13400476439814628800e+2502"); } mod dec_d9999 { use super::*; fn test_input() -> BigDecimal { "0.9999".parse().unwrap() } impl_case!(fmt_default: "{}" => "0.9999"); impl_case!(fmt_d0: "{:.0}" => "1"); impl_case!(fmt_d1: "{:.1}" => "1.0"); impl_case!(fmt_d2: "{:.2}" => "1.00"); impl_case!(fmt_d3: "{:.3}" => "1.000"); impl_case!(fmt_d4: "{:.4}" => "0.9999"); impl_case!(fmt_d6: "{:.6}" => "0.999900"); } mod dec_9d99 { use super::*; fn test_input() -> BigDecimal { "9.99".parse().unwrap() } impl_case!(fmt_default: "{}" => "9.99"); impl_case!(fmt_d0: "{:.0}" => "10"); impl_case!(fmt_d1: "{:.1}" => "10.0"); impl_case!(fmt_d2: "{:.2}" => "9.99"); impl_case!(fmt_d3: "{:.3}" => "9.990"); impl_case!(fmt_10d3: "{:10.3}" => " 9.990"); } mod dec_0 { use super::*; fn test_input() -> BigDecimal { "0".parse().unwrap() } impl_case!(fmt_default: "{}" => "0"); impl_case!(fmt_d0: "{:.0}" => "0"); impl_case!(fmt_d1: "{:.1}" => "0.0"); impl_case!(fmt_e: "{:e}" => "0e+0"); impl_case!(fmt_E: "{:E}" => "0E+0"); } mod dec_0e15 { use super::*; fn test_input() -> BigDecimal { "0e15".parse().unwrap() } impl_case!(fmt_default: "{}" => "0"); impl_case!(fmt_d0: "{:.0}" => "0"); impl_case!(fmt_d1: "{:.1}" => "0.0"); impl_case!(fmt_5d1: "{:5.1}" => " 0.0"); impl_case!(fmt_010d1: "{:010.1}" => "00000000.0"); impl_case!(fmt_e: "{:e}" => "0e+0"); impl_case!(fmt_E: "{:E}" => "0E+0"); impl_case!(fmt_d2e: "{:.2e}" => "0.00e+0"); impl_case!(fmt_8d2e: "{:8.2e}" => " 0.00e+0"); } mod dec_0en15 { use super::*; fn test_input() -> BigDecimal { "0e-15".parse().unwrap() } impl_case!(fmt_default: "{}" => "0"); impl_case!(fmt_d0: "{:.0}" => "0"); impl_case!(fmt_d1: "{:.1}" => "0.0"); impl_case!(fmt_6d2: "{:6.2}" => " 0.00"); impl_case!(fmt_010d1: "{:010.1}" => "00000000.0"); impl_case!(fmt_e: "{:e}" => "0e+0"); impl_case!(fmt_E: "{:E}" => "0E+0"); } mod dec_n0e6 { use super::*; fn test_input() -> BigDecimal { "-0e6".parse().unwrap() } impl_case!(fmt_default: "{}" => "0"); impl_case!(fmt_d1: "{:.1}" => "0.0"); impl_case!(fmt_e: "{:e}" => "0e+0"); impl_case!(fmt_E: "{:E}" => "0E+0"); } } mod fmt_boundaries { use super::*; macro_rules! impl_case { ( $name:ident: $src:expr => $expected:literal ) => { #[test] fn $name() { let src = $src; let bd: BigDecimal = src.parse().unwrap(); let result = bd.to_string(); assert_eq!(result, $expected); let round_trip = BigDecimal::from_str(&result).unwrap(); assert_eq!(round_trip, bd); let sci = bd.to_scientific_notation(); let sci_round_trip = BigDecimal::from_str(&sci).unwrap(); assert_eq!(sci_round_trip, bd); let eng = bd.to_engineering_notation(); let eng_round_trip = BigDecimal::from_str(&eng).unwrap(); assert_eq!(eng_round_trip, bd); } }; ( (eng-check-invalid) $name:ident: $src:expr => $expected:literal ) => { #[test] fn $name() { let src = $src; let bd: BigDecimal = src.parse().unwrap(); let result = bd.to_string(); assert_eq!(result, $expected); let round_trip = BigDecimal::from_str(&result).unwrap(); assert_eq!(round_trip, bd); let sci = bd.to_scientific_notation(); let sci_round_trip = BigDecimal::from_str(&sci).unwrap(); assert_eq!(sci_round_trip, bd); let eng = bd.to_engineering_notation(); let eng_round_trip = BigDecimal::from_str(&eng); assert!(eng_round_trip.is_err()); } }; ( (panics) $name:ident: $src:expr ) => { #[test] #[should_panic] fn $name() { let src = $src; let _bd: BigDecimal = src.parse().unwrap(); } }; } impl_case!(test_max: format!("1E{}", i64::MAX) => "1e+9223372036854775807"); impl_case!(test_max_multiple_digits: format!("314156E{}", i64::MAX) => "314156e+9223372036854775807"); impl_case!(test_min_scale: "1E9223372036854775807" => "1e+9223372036854775807"); impl_case!((eng-check-invalid) test_max_scale: "1E-9223372036854775807" => "1E-9223372036854775807"); impl_case!(test_min_multiple_digits: format!("271828182E-{}", i64::MAX) => "2.71828182E-9223372036854775799"); impl_case!((panics) test_max_exp_overflow: "1E9223372036854775809"); impl_case!((panics) test_min_exp_overflow: "1E-9223372036854775808"); } #[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); } } mod fmt_debug { use super::*; macro_rules! impl_case { ($name:ident: $input:literal => $expected:literal => $expected_alt:literal) => { paste! { #[test] fn $name() { let x: BigDecimal = $input.parse().unwrap(); let y = format!("{:?}", x); assert_eq!(y, $expected); } #[test] fn [< $name _alt >]() { let x: BigDecimal = $input.parse().unwrap(); let y = format!("{:#?}", x); assert_eq!(y, $expected_alt); } } }; } impl_case!(case_0: "0" => r#"BigDecimal(sign=NoSign, scale=0, digits=[])"# => r#"BigDecimal("0e0")"#); impl_case!(case_n0: "-0" => r#"BigDecimal(sign=NoSign, scale=0, digits=[])"# => r#"BigDecimal("0e0")"#); impl_case!(case_1: "1" => r#"BigDecimal(sign=Plus, scale=0, digits=[1])"# => r#"BigDecimal("1e0")"#); impl_case!(case_123_400: "123.400" => r#"BigDecimal(sign=Plus, scale=3, digits=[123400])"# => r#"BigDecimal("123400e-3")"#); impl_case!(case_123_4en2: "123.4e-2" => r#"BigDecimal(sign=Plus, scale=3, digits=[1234])"# => r#"BigDecimal("1234e-3")"#); impl_case!(case_123_456: "123.456" => r#"BigDecimal(sign=Plus, scale=3, digits=[123456])"# => r#"BigDecimal("123456e-3")"#); impl_case!(case_01_20: "01.20" => r#"BigDecimal(sign=Plus, scale=2, digits=[120])"# => r#"BigDecimal("120e-2")"#); impl_case!(case_1_20: "1.20" => r#"BigDecimal(sign=Plus, scale=2, digits=[120])"# => r#"BigDecimal("120e-2")"#); impl_case!(case_01_2e3: "01.2E3" => r#"BigDecimal(sign=Plus, scale=-2, digits=[12])"# => r#"BigDecimal("12e2")"#); impl_case!(case_avagadro: "6.02214076e1023" => r#"BigDecimal(sign=Plus, scale=-1015, digits=[602214076])"# => r#"BigDecimal("602214076e1015")"#); impl_case!(case_1e99999999999999 : "1e99999999999999" => r#"BigDecimal(sign=Plus, scale=-99999999999999, digits=[1])"# => r#"BigDecimal("1e99999999999999")"#); impl_case!(case_n144d3308279 : "-144.3308279" => r#"BigDecimal(sign=Minus, scale=7, digits=[1443308279])"# => r#"BigDecimal("-1443308279e-7")"#); impl_case!(case_n349983058835858339619e2 : "-349983058835858339619e2" => r#"BigDecimal(sign=Minus, scale=-2, digits=[17941665509086410531, 18])"# => r#"BigDecimal("-349983058835858339619e2")"#); } mod write_scientific_notation { use super::*; macro_rules! test_fmt_function { ($n:expr) => { $n.to_scientific_notation() }; } impl_case!(case_4_1592480782835e9 : "4159248078.2835" => "4.1592480782835e9"); impl_case!(case_1_234e_5 : "0.00001234" => "1.234e-5"); impl_case!(case_0 : "0" => "0e0"); impl_case!(case_1 : "1" => "1e0"); impl_case!(case_2_00e0 : "2.00" => "2.00e0"); impl_case!(case_neg_5_70e1 : "-57.0" => "-5.70e1"); } mod write_engineering_notation { use super::*; macro_rules! test_fmt_function { ($n:expr) => { $n.to_engineering_notation() }; } impl_case!(case_4_1592480782835e9 : "4159248078.2835" => "4.1592480782835e9"); impl_case!(case_12_34e_6 : "0.00001234" => "12.34e-6"); impl_case!(case_0 : "0" => "0e0"); impl_case!(case_1 : "1" => "1e0"); impl_case!(case_2_00e0 : "2.00" => "2.00e0"); impl_case!(case_neg_5_70e1 : "-57.0" => "-57.0e0"); impl_case!(case_5_31e4 : "5.31e4" => "53.1e3"); impl_case!(case_5_31e5 : "5.31e5" => "531e3"); impl_case!(case_5_31e6 : "5.31e6" => "5.31e6"); impl_case!(case_5_31e7 : "5.31e7" => "53.1e6"); impl_case!(case_1e2 : "1e2" => "100e0"); impl_case!(case_1e119 : "1e19" => "10e18"); impl_case!(case_1e3000 : "1e3000" => "1e3000"); impl_case!(case_4_2e7 : "4.2e7" => "42e6"); impl_case!(case_4_2e8 : "4.2e8" => "420e6"); impl_case!(case_4e99999999999999 : "4e99999999999999" => "4e99999999999999"); impl_case!(case_4e99999999999998 : "4e99999999999998" => "400e99999999999996"); impl_case!(case_44e99999999999998 : "44e99999999999998" => "4.4e99999999999999"); impl_case!(case_4e99999999999997 : "4e99999999999997" => "40e99999999999996"); impl_case!(case_41e99999999999997 : "41e99999999999997" => "410e99999999999996"); impl_case!(case_413e99999999999997 : "413e99999999999997" => "4.13e99999999999999"); // impl_case!(case_413e99999999999997 : "413e99999999999997" => "4.13e99999999999999"); } } #[cfg(all(test, property_tests))] mod proptests { use super::*; use paste::paste; use proptest::prelude::*; use proptest::num::f64::NORMAL as NormalF64; macro_rules! impl_parsing_test { ($t:ty) => { paste! { proptest! { #[test] fn [< roudtrip_to_str_and_back_ $t >](n: $t) { let original = BigDecimal::from(n); let display = format!("{}", original); let parsed = display.parse::().unwrap(); prop_assert_eq!(&original, &parsed); } } } }; (from-float $t:ty) => { paste! { proptest! { #[test] fn [< roudtrip_to_str_and_back_ $t >](n: $t) { let original = BigDecimal::try_from(n).unwrap(); let display = format!("{}", original); let parsed = display.parse::().unwrap(); prop_assert_eq!(&original, &parsed); } } } }; } impl_parsing_test!(u8); impl_parsing_test!(u16); impl_parsing_test!(u32); impl_parsing_test!(u64); impl_parsing_test!(u128); impl_parsing_test!(i8); impl_parsing_test!(i16); impl_parsing_test!(i32); impl_parsing_test!(i64); impl_parsing_test!(i128); impl_parsing_test!(from-float f32); impl_parsing_test!(from-float f64); proptest! { #![proptest_config(ProptestConfig::with_cases(32_000))] #[test] fn float_formatting(f in NormalF64, prec in 0..21usize) { let d = BigDecimal::from_f64(f).unwrap(); let f_fmt = format!("{f:.prec$}"); let d_fmt = format!("{d:.prec$}").replace("+", ""); prop_assert_eq!(f_fmt, d_fmt); } } proptest! { #![proptest_config(ProptestConfig::with_cases(1000))] #[test] fn scientific_notation_roundtrip(f: f64) { prop_assume!(!f.is_nan() && !f.is_infinite()); let n = BigDecimal::from_f64(f).unwrap(); let s = n.to_scientific_notation(); let m: BigDecimal = s.parse().unwrap(); prop_assert_eq!(n, m); } #[test] fn engineering_notation_roundtrip(f: f64) { prop_assume!(!f.is_nan() && !f.is_infinite()); let n = BigDecimal::from_f64(f).unwrap(); let s = n.to_engineering_notation(); let m: BigDecimal = s.parse().unwrap(); prop_assert_eq!(n, m); } } } bigdecimal-0.4.10/src/impl_num.rs000064400000000000000000000304531046102023000147500ustar 00000000000000//! Code for num_traits use num_traits::{Zero, Num, Signed, FromPrimitive, ToPrimitive, AsPrimitive}; use num_bigint::{BigInt, Sign, ToBigInt}; #[cfg(not(feature = "std"))] use num_traits::float::FloatCore; use crate::stdlib; use stdlib::str::FromStr; use stdlib::string::{String, ToString}; use stdlib::convert::TryFrom; use stdlib::ops::Neg; use stdlib::cmp::Ordering; use crate::BigDecimal; use crate::BigDecimalRef; use crate::ParseBigDecimalError; #[cfg(not(feature = "std"))] // f64::powi is only available in std, no_std must use libm fn powi(x: f64, n: i32) -> f64 { libm::pow(x, n as f64) } #[cfg(feature = "std")] fn powi(x: f64, n: i32) -> f64 { x.powi(n) } 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, e_exp) = s.split_at(loc); (base, i128::from_str(&e_exp[1..])?) } }; // TEMPORARY: Test for emptiness - remove once BigInt supports similar error if base_part.is_empty() { return Err(ParseBigDecimalError::Empty); } let mut digit_buffer = String::new(); let last_digit_loc = base_part.len() - 1; // split decimal into a digit string and decimal-point offset let (digits, decimal_offset) = match base_part.find('.') { // No dot! pass directly to BigInt None => (base_part, 0), // dot at last digit, pass all preceding digits to BigInt Some(loc) if loc == last_digit_loc => { (&base_part[..last_digit_loc], 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..]); digit_buffer.reserve(lead.len() + trail.len()); // copy all leading characters into 'digits' string digit_buffer.push_str(lead); // copy all trailing characters after '.' into the digits string digit_buffer.push_str(trail); // count number of trailing digits let trail_digits = trail.chars().filter(|c| *c != '_').count(); (digit_buffer.as_str(), trail_digits as i128) } }; // Calculate scale by subtracing the parsed exponential // value from the number of decimal digits. // Return error if anything overflows outside i64 boundary. let scale = decimal_offset .checked_sub(exponent_value) .and_then(|scale| scale.to_i64()) .ok_or_else(|| ParseBigDecimalError::Other( format!("Exponent overflow when parsing '{}'", s)) )?; let big_int = BigInt::from_str_radix(digits, radix)?; Ok(BigDecimal::new(big_int, scale)) } } impl ToPrimitive for BigDecimal { fn to_i64(&self) -> Option { self.to_ref().to_i64() } fn to_i128(&self) -> Option { self.to_ref().to_i128() } fn to_u64(&self) -> Option { self.to_ref().to_u64() } fn to_u128(&self) -> Option { self.to_ref().to_u128() } fn to_f64(&self) -> Option { self.to_ref().to_f64() } } impl ToPrimitive for BigDecimalRef<'_> { fn to_i64(&self) -> Option { match self.sign() { Sign::Plus if self.scale == 0 => self.digits.to_i64(), Sign::Minus if self.scale == 0 => { self.digits.to_u64().and_then( |d| match d.cmp(&(i64::MAX as u64 + 1)) { Ordering::Less => Some((d as i64).neg()), Ordering::Equal => Some(i64::MIN), Ordering::Greater => None, } ) } Sign::Plus | Sign::Minus => self.to_owned_with_scale(0).int_val.to_i64(), Sign::NoSign => Some(0), } } fn to_i128(&self) -> Option { match self.sign() { Sign::Plus if self.scale == 0 => self.digits.to_i128(), Sign::Minus if self.scale == 0 => { self.digits.to_u128().and_then( |d| match d.cmp(&(i128::MAX as u128 + 1)) { Ordering::Less => Some((d as i128).neg()), Ordering::Equal => Some(i128::MIN), Ordering::Greater => None, } ) } Sign::Plus | Sign::Minus => self.to_owned_with_scale(0).int_val.to_i128(), Sign::NoSign => Some(0), } } fn to_u64(&self) -> Option { match self.sign() { Sign::Plus if self.scale == 0 => self.digits.to_u64(), Sign::Plus => self.to_owned_with_scale(0).int_val.to_u64(), Sign::NoSign => Some(0), Sign::Minus => None, } } fn to_u128(&self) -> Option { match self.sign() { Sign::Plus if self.scale == 0 => self.digits.to_u128(), Sign::Plus => self.to_owned_with_scale(0).int_val.to_u128(), Sign::NoSign => Some(0), Sign::Minus => None, } } fn to_f64(&self) -> Option { let copy_sign_to_float = |f: f64| if self.sign == Sign::Minus { f.neg() } else { f }; if self.digits.is_zero() { return Some(0.0); } if self.scale == 0 { return self.digits.to_f64().map(copy_sign_to_float); } // borrow bugint value let (mut int_cow, mut scale) = self.to_cow_biguint_and_scale(); // approximate number of base-10 digits let digit_count = ((int_cow.bits() + 1) as f64 * stdlib::f64::consts::LOG10_2).floor() as u64; // trim trailing digits, 19 at a time, leaving about 25 // which should be more than accurate enough for direct // conversion to f64 const N: u64 = 25; let digits_to_remove = digit_count.saturating_sub(N); let ten_to_19 = 10u64.pow(19); let iter_count = digits_to_remove / 19; for _ in 0..iter_count { *int_cow.to_mut() /= ten_to_19; scale -= 19; } match scale.to_i32().and_then(|x| x.checked_neg()) { Some(pow) if 0 <= pow => { // 'simple' integer case let f = int_cow.to_f64().map(copy_sign_to_float)?; (f * powi(10.0, pow)).into() } Some(exp) => { // format decimal as floating point and let the default parser generate the f64 #[cfg(not(feature = "std"))] { let s = format!("{}e{}", int_cow, exp); s.parse().map(copy_sign_to_float).ok() } #[cfg(feature = "std")] { use std::io::Write; // save allocation of a String by using local buffer of bytes // since we know the size will be small // // ~ 1 '-' + (N+19) digits + 1 'e' + 11 i32 digits = 32 + N // (plus a little extra for safety) let mut buf = [0u8; 50 + N as usize]; write!(&mut buf[..], "{}e{}", int_cow, exp).ok()?; let i = buf.iter().position(|&c| c == 0)?; let s = stdlib::str::from_utf8(&buf[..i]).ok()?; s.parse().map(copy_sign_to_float).ok() } } None => { // exponenent too big for i32: return appropriate infinity let result = if self.sign != Sign::Minus { f64::INFINITY } else { f64::NEG_INFINITY }; result.into() } } } } 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_i128(n: i128) -> Option { Some(BigDecimal::from(n)) } #[inline] fn from_u128(n: u128) -> Option { Some(BigDecimal::from(n)) } #[inline] fn from_f32(n: f32) -> Option { BigDecimal::try_from(n).ok() } #[inline] fn from_f64(n: f64) -> Option { BigDecimal::try_from(n).ok() } } impl ToBigInt for BigDecimal { fn to_bigint(&self) -> Option { Some(self.with_scale(0).int_val) } } #[cfg(test)] mod test { use super::*; mod from_str_radix { use super::*; #[test] fn out_of_bounds() { let d = BigDecimal::from_str_radix("1e-9223372036854775808", 10); assert_eq!(d.unwrap_err(), ParseBigDecimalError::Other("Exponent overflow when parsing '1e-9223372036854775808'".to_string())); } } mod to_f64 { use super::*; use paste::paste; use crate::stdlib; macro_rules! impl_case { ($name:ident: $f:expr) => { #[test] fn $name() { let f: f64 = $f; let s = format!("{}", f); let n: BigDecimal = s.parse().unwrap(); let result = n.to_f64().unwrap(); assert_eq!(result, f, "src='{}'", s); } }; ($name:ident: $src:literal => $expected:expr) => { #[test] fn $name() { let n: BigDecimal = $src.parse().unwrap(); assert_eq!(n.to_f64().unwrap(), $expected); } }; } impl_case!(case_zero: 0.0); impl_case!(case_neg_zero: -0.0); impl_case!(case_875en6: 0.000875); impl_case!(case_f64_min: f64::MIN); impl_case!(case_f64_max: f64::MAX); impl_case!(case_f64_min_pos: f64::MIN_POSITIVE); impl_case!(case_pi: stdlib::f64::consts::PI); impl_case!(case_neg_e: -stdlib::f64::consts::E); impl_case!(case_1en500: 1e-500); impl_case!(case_3en310: 3e-310); impl_case!(case_0d001: 0.001); impl_case!(case_pos2_224en320: 2.224e-320); impl_case!(case_neg2_224en320: -2.224e-320); impl_case!(case_12d34: "12.34" => 12.34); impl_case!(case_0d14: "0.14" => 0.14); impl_case!(case_3d14: "3.14" => 3.14); impl_case!(case_54e23: "54e23" => 54e23); impl_case!(case_n54e23: "-54e23" => -54e23); impl_case!(case_12en78: "12e-78" => 12e-78); impl_case!(case_n12en78: "-12e-78" => -1.2e-77); impl_case!(case_n1en320: "-1e-320" => -1e-320); impl_case!(case_1d0001en920: "1.0001e-920" => 0.0); impl_case!(case_50000d0000: "50000.0000" => 50000.0); impl_case!(case_13100e4: "13100e4" => 131000000.0); impl_case!(case_44223e9999: "44223e9999" => f64::INFINITY); impl_case!(case_neg44223e9999: "-44223e9999" => f64::NEG_INFINITY); } } #[cfg(all(test, property_tests))] mod proptests { use super::*; use paste::paste; use proptest::prelude::*; use proptest::num::f64::{NORMAL as NormalF64, SUBNORMAL as SubnormalF64}; proptest! { #![proptest_config(ProptestConfig::with_cases(20_000))] #[test] fn to_f64_roundtrip(f in NormalF64 | SubnormalF64) { let d = BigDecimal::from_f64(f).unwrap(); let v = d.to_f64(); prop_assert!(v.is_some()); prop_assert_eq!(f, v.unwrap()); } } } bigdecimal-0.4.10/src/impl_ops.rs000064400000000000000000000273621046102023000147570ustar 00000000000000//! Implement math operations: Add,Sub, etc use crate::*; macro_rules! impl_add_for_primitive { ($t:ty) => { impl_add_for_primitive!(IMPL:ADD $t); impl_add_for_primitive!(IMPL:ADD-ASSIGN $t); impl_add_for_primitive!(IMPL:ADD &$t); impl_add_for_primitive!(IMPL:ADD-ASSIGN &$t); }; (IMPL:ADD $t:ty) => { impl Add<$t> for BigDecimal { type Output = BigDecimal; fn add(mut self, rhs: $t) -> BigDecimal { self += rhs; self } } impl Add<$t> for &BigDecimal { type Output = BigDecimal; fn add(self, rhs: $t) -> BigDecimal { self.to_ref() + rhs } } impl Add<$t> for BigDecimalRef<'_> { type Output = BigDecimal; fn add(self, rhs: $t) -> BigDecimal { BigDecimal::from(rhs) + self } } impl Add for $t { type Output = BigDecimal; fn add(self, rhs: BigDecimal) -> BigDecimal { rhs + self } } impl Add<&BigDecimal> for $t { type Output = BigDecimal; fn add(self, rhs: &BigDecimal) -> BigDecimal { rhs + self } } }; (IMPL:ADD-ASSIGN &$t:ty) => { // special case for the ref types impl AddAssign<&$t> for BigDecimal { fn add_assign(&mut self, rhs: &$t) { *self += *rhs; } } }; (IMPL:ADD-ASSIGN $t:ty) => { impl AddAssign<$t> for BigDecimal { fn add_assign(&mut self, rhs: $t) { if rhs == 0 { // no-op } else if self.scale == 0 { self.int_val += rhs; } else { *self += BigDecimal::from(rhs); } } } }; } impl_add_for_primitive!(u8); impl_add_for_primitive!(u16); impl_add_for_primitive!(u32); impl_add_for_primitive!(u64); impl_add_for_primitive!(u128); impl_add_for_primitive!(i8); impl_add_for_primitive!(i16); impl_add_for_primitive!(i32); impl_add_for_primitive!(i64); impl_add_for_primitive!(i128); macro_rules! impl_sub_for_primitive { ($t:ty) => { impl_sub_for_primitive!(IMPL:SUB $t); impl_sub_for_primitive!(IMPL:SUB-ASSIGN $t); impl_sub_for_primitive!(IMPL:SUB &$t); impl_sub_for_primitive!(IMPL:SUB-ASSIGN &$t); }; (IMPL:SUB $t:ty) => { impl Sub<$t> for BigDecimal { type Output = BigDecimal; fn sub(mut self, rhs: $t) -> BigDecimal { self -= rhs; self } } impl Sub<$t> for &BigDecimal { type Output = BigDecimal; fn sub(self, rhs: $t) -> BigDecimal { let res = BigDecimal::from(rhs).neg(); res + self } } impl Sub for $t { type Output = BigDecimal; fn sub(self, rhs: BigDecimal) -> BigDecimal { rhs.neg() + self } } impl Sub<&BigDecimal> for $t { type Output = BigDecimal; fn sub(self, rhs: &BigDecimal) -> BigDecimal { rhs.neg() + self } } }; (IMPL:SUB-ASSIGN &$t:ty) => { impl SubAssign<&$t> for BigDecimal { fn sub_assign(&mut self, rhs: &$t) { *self -= *rhs; } } }; (IMPL:SUB-ASSIGN $t:ty) => { impl SubAssign<$t> for BigDecimal { fn sub_assign(&mut self, rhs: $t) { if self.scale == 0 { self.int_val -= rhs; } else { *self -= BigDecimal::from(rhs); } } } }; } impl_sub_for_primitive!(u8); impl_sub_for_primitive!(u16); impl_sub_for_primitive!(u32); impl_sub_for_primitive!(u64); impl_sub_for_primitive!(u128); impl_sub_for_primitive!(i8); impl_sub_for_primitive!(i16); impl_sub_for_primitive!(i32); impl_sub_for_primitive!(i64); impl_sub_for_primitive!(i128); macro_rules! impl_mul_for_primitive { ($t:ty) => { impl_mul_for_primitive!(IMPL:MUL $t); impl_mul_for_primitive!(IMPL:MUL-ASSIGN $t); impl_mul_for_primitive!(IMPL:MUL &$t); impl_mul_for_primitive!(IMPL:MUL-ASSIGN &$t); }; (IMPL:MUL $t:ty) => { impl Mul<$t> for BigDecimal { type Output = BigDecimal; fn mul(mut self, rhs: $t) -> BigDecimal { self *= rhs; self } } impl Mul<$t> for &BigDecimal { type Output = BigDecimal; fn mul(self, rhs: $t) -> BigDecimal { let res = BigDecimal::from(rhs); res * self } } impl Mul for $t { type Output = BigDecimal; fn mul(self, rhs: BigDecimal) -> BigDecimal { rhs * self } } impl Mul<&BigDecimal> for $t { type Output = BigDecimal; fn mul(self, rhs: &BigDecimal) -> BigDecimal { rhs * self } } }; (IMPL:MUL-ASSIGN $t:ty) => { impl MulAssign<$t> for BigDecimal { fn mul_assign(&mut self, rhs: $t) { if rhs.is_zero() { *self = BigDecimal::zero() } else if rhs.is_one() { // no-op } else { *self *= BigDecimal::from(rhs); } } } }; } impl_mul_for_primitive!(u8); impl_mul_for_primitive!(u16); impl_mul_for_primitive!(u32); impl_mul_for_primitive!(u64); impl_mul_for_primitive!(u128); impl_mul_for_primitive!(i8); impl_mul_for_primitive!(i16); impl_mul_for_primitive!(i32); impl_mul_for_primitive!(i64); impl_mul_for_primitive!(i128); macro_rules! impl_div_for_primitive { (f32) => { impl_div_for_primitive!(IMPL:DIV:FLOAT f32); impl_div_for_primitive!(IMPL:DIV:REF &f32); }; (f64) => { impl_div_for_primitive!(IMPL:DIV:FLOAT f64); impl_div_for_primitive!(IMPL:DIV:REF &f64); }; ($t:ty) => { impl_div_for_primitive!(IMPL:DIV $t); impl_div_for_primitive!(IMPL:DIV:REF &$t); impl_div_for_primitive!(IMPL:DIV-ASSIGN $t); }; (IMPL:DIV $t:ty) => { impl Div<$t> for BigDecimal { type Output = BigDecimal; fn div(self, denom: $t) -> BigDecimal { if denom.is_one() { self } else if denom.checked_neg() == Some(1) { self.neg() } else if denom.clone() == 2 { self.half() } else if denom.checked_neg() == Some(2) { self.half().neg() } else { self / BigDecimal::from(denom) } } } impl Div<$t> for &BigDecimal { type Output = BigDecimal; fn div(self, denom: $t) -> BigDecimal { self.clone() / denom } } impl Div for $t { type Output = BigDecimal; fn div(self, denom: BigDecimal) -> BigDecimal { if self.is_one() { denom.inverse() } else { BigDecimal::from(self) / denom } } } impl Div<&BigDecimal> for $t { type Output = BigDecimal; fn div(self, denom: &BigDecimal) -> BigDecimal { self / denom.clone() } } }; (IMPL:DIV-ASSIGN $t:ty) => { impl DivAssign<$t> for BigDecimal { fn div_assign(&mut self, rhs: $t) { if rhs.is_zero() { *self = BigDecimal::zero() } else if rhs.is_one() { // no-op } else { *self = self.clone() / BigDecimal::from(rhs); } } } }; (IMPL:DIV:REF $t:ty) => { impl Div<$t> for BigDecimal { type Output = BigDecimal; fn div(self, denom: $t) -> BigDecimal { self / *denom } } impl Div for $t { type Output = BigDecimal; fn div(self, denom: BigDecimal) -> Self::Output { *self / denom } } impl Div<&BigDecimal> for $t { type Output = BigDecimal; fn div(self, denom: &BigDecimal) -> Self::Output { *self / denom } } impl DivAssign<$t> for BigDecimal { fn div_assign(&mut self, denom: $t) { self.div_assign(*denom) } } }; (IMPL:DIV:FLOAT $t:ty) => { impl Div<$t> for BigDecimal { type Output = BigDecimal; #[allow(clippy::float_cmp)] fn div(self, denom: $t) -> BigDecimal { if !denom.is_normal() { BigDecimal::zero() } else if denom == (1.0 as $t) { self } else if denom == (-1.0 as $t) { self.neg() } else if denom == (2.0 as $t) { self.half() } else if denom == (-2.0 as $t) { self.half().neg() } else { self / BigDecimal::try_from(denom).unwrap() } } } impl Div<$t> for &BigDecimal { type Output = BigDecimal; fn div(self, denom: $t) -> BigDecimal { self.clone() / denom } } impl Div for $t { type Output = BigDecimal; fn div(self, denom: BigDecimal) -> Self::Output { if !self.is_normal() { BigDecimal::zero() } else if self.is_one() { denom.inverse() } else { BigDecimal::try_from(self).unwrap() / denom } } } impl Div<&BigDecimal> for $t { type Output = BigDecimal; fn div(self, denom: &BigDecimal) -> Self::Output { if !self.is_normal() { BigDecimal::zero() } else if self.is_one() { denom.inverse() } else { BigDecimal::try_from(self).unwrap() / denom } } } impl DivAssign<$t> for BigDecimal { fn div_assign(&mut self, denom: $t) { if !denom.is_normal() { *self = BigDecimal::zero() } else { *self = self.clone() / BigDecimal::try_from(denom).unwrap() }; } } }; } impl_div_for_primitive!(u8); impl_div_for_primitive!(u16); impl_div_for_primitive!(u32); impl_div_for_primitive!(u64); impl_div_for_primitive!(u128); impl_div_for_primitive!(i8); impl_div_for_primitive!(i16); impl_div_for_primitive!(i32); impl_div_for_primitive!(i64); impl_div_for_primitive!(i128); impl_div_for_primitive!(f32); impl_div_for_primitive!(f64); impl Neg for BigDecimal { type Output = BigDecimal; #[inline] fn neg(mut self) -> BigDecimal { self.int_val = -self.int_val; self } } impl Neg for &BigDecimal { type Output = BigDecimal; #[inline] fn neg(self) -> BigDecimal { -self.clone() } } impl Neg for BigDecimalRef<'_> { type Output = Self; fn neg(self) -> Self::Output { Self { sign: self.sign.neg(), digits: self.digits, scale: self.scale, } } } bigdecimal-0.4.10/src/impl_ops_add.rs000064400000000000000000000217721046102023000155660ustar 00000000000000//! Addition operator trait implementation //! use super::*; use stdlib::borrow::ToOwned; impl Add for BigDecimal { type Output = BigDecimal; #[inline] fn add(self, rhs: BigDecimal) -> BigDecimal { arithmetic::addition::add_bigdecimals(self, rhs) } } impl<'a, T: Into>> Add for BigDecimal { type Output = BigDecimal; fn add(mut self, rhs: T) -> BigDecimal { self.add_assign(rhs); self } } impl Add for BigDecimal { type Output = BigDecimal; #[inline] fn add(self, rhs: BigInt) -> BigDecimal { self + BigDecimal::from(rhs) } } impl Add for &'_ BigDecimal { type Output = BigDecimal; #[inline] fn add(self, rhs: BigDecimal) -> BigDecimal { rhs + self } } impl<'a, T: Into>> Add for &'_ BigDecimal { type Output = BigDecimal; fn add(self, rhs: T) -> BigDecimal { arithmetic::addition::add_bigdecimal_refs(self, rhs, None) } } impl Add for &'_ BigDecimal { type Output = BigDecimal; #[inline] fn add(self, rhs: BigInt) -> BigDecimal { self.to_ref() + rhs } } impl Add for BigDecimalRef<'_> { type Output = BigDecimal; #[inline] fn add(self, rhs: BigDecimal) -> BigDecimal { rhs + self } } impl<'a, T: Into>> Add for BigDecimalRef<'_> { type Output = BigDecimal; fn add(self, rhs: T) -> BigDecimal { arithmetic::addition::add_bigdecimal_refs(self, rhs, None) } } impl Add for BigDecimalRef<'_> { type Output = BigDecimal; #[inline] fn add(self, rhs: BigInt) -> BigDecimal { self + BigDecimal::from(rhs) } } impl Add for BigInt { type Output = BigDecimal; #[inline] fn add(self, rhs: BigDecimal) -> BigDecimal { BigDecimal::from(self) + rhs } } impl Add<&BigDecimal> for BigInt { type Output = BigDecimal; fn add(self, rhs: &BigDecimal) -> BigDecimal { BigDecimal::from(self) + rhs } } impl Add> for BigInt { type Output = BigDecimal; fn add(self, rhs: BigDecimalRef<'_>) -> BigDecimal { BigDecimal::from(self) + rhs } } impl Add for &BigInt { type Output = BigDecimal; #[inline] fn add(self, rhs: BigDecimal) -> BigDecimal { rhs + self } } impl Add<&BigDecimal> for &BigInt { type Output = BigDecimal; #[inline] fn add(self, rhs: &BigDecimal) -> BigDecimal { rhs + self } } impl Add> for &BigInt { type Output = BigDecimal; #[inline] fn add(self, rhs: BigDecimalRef<'_>) -> BigDecimal { rhs + self } } impl AddAssign for BigDecimal { fn add_assign(&mut self, rhs: BigDecimal) { arithmetic::addition::addassign_bigdecimals(self, rhs) } } impl<'a, N: Into>> AddAssign for BigDecimal { #[inline] fn add_assign(&mut self, rhs: N) { arithmetic::addition::addassign_bigdecimal_ref(self, rhs) } } impl AddAssign for BigDecimal { #[inline] fn add_assign(&mut self, rhs: BigInt) { self.add_assign(BigDecimal::from(rhs)); } } #[cfg(test)] mod test { use super::*; use paste::paste; macro_rules! impl_case { ( $name:ident: $a:literal + $b:literal => $c:literal ) => { #[test] fn $name() { let a: BigDecimal = $a.parse().unwrap(); let b: BigDecimal = $b.parse().unwrap(); let c: BigDecimal = $c.parse().unwrap(); assert_eq!(c, a.clone() + b.clone()); assert_eq!(c, a.clone() + b.to_ref()); assert_eq!(c, a.clone() + &b); assert_eq!(c, &a + b.clone()); assert_eq!(c, &a + b.to_ref()); assert_eq!(c, &a + &b); assert_eq!(c, a.to_ref() + b.clone()); assert_eq!(c, a.to_ref() + b.to_ref()); assert_eq!(c, a.to_ref() + &b); // Reversed assert_eq!(c, b.clone() + a.clone()); assert_eq!(c, b.clone() + a.to_ref()); assert_eq!(c, b.clone() + &a); assert_eq!(c, &b + a.clone()); assert_eq!(c, &b + a.to_ref()); assert_eq!(c, &b + &a); assert_eq!(c, b.to_ref() + a.clone()); assert_eq!(c, b.to_ref() + a.to_ref()); assert_eq!(c, b.to_ref() + &a); let mut n = a.clone(); n += b.clone(); assert_eq!(c, n); let mut n = a.clone(); n += &b; assert_eq!(c, n); let mut n = a.clone(); n += b.to_ref(); assert_eq!(c, n); let mut n = b.clone(); n += a.clone(); assert_eq!(c, n); let mut n = b.clone(); n += &a; assert_eq!(c, n); let mut n = b.clone(); n += a.to_ref(); assert_eq!(c, n); } }; ( $name:ident: $a:literal + (int) $b:literal => $c:literal ) => { #[test] fn $name() { let a: BigDecimal = $a.parse().unwrap(); let b: BigInt = $b.parse().unwrap(); let c: BigDecimal = $c.parse().unwrap(); assert_eq!(c, a.clone() + b.clone()); assert_eq!(c, a.clone() + &b); assert_eq!(c, &a + &b); assert_eq!(c, &a + b.clone()); assert_eq!(c, a.to_ref() + &b); assert_eq!(c, b.clone() + a.clone()); assert_eq!(c, b.clone() + a.to_ref()); assert_eq!(c, b.clone() + &a); assert_eq!(c, &b + a.clone()); assert_eq!(c, &b + a.to_ref()); assert_eq!(c, &b + &a); let mut n = a.clone(); n += b.clone(); assert_eq!(c, n); let mut n = a.clone(); n += &b; assert_eq!(c, n); } }; } impl_case!(case_1234en2_1234en3: "12.34" + "1.234" => "13.574"); impl_case!(case_1234en2_n1234en3: "12.34" + "-1.234" => "11.106"); impl_case!(case_1234en2_n1234en2: "12.34" + "-12.34" => "0"); impl_case!(case_1234e6_1234en6: "1234e6" + "1234e-6" => "1234000000.001234"); impl_case!(case_1234en6_1234e6: "1234e6" + "1234e-6" => "1234000000.001234"); impl_case!(case_18446744073709551616_1: "18446744073709551616.0" + "1" => "18446744073709551617"); impl_case!(case_184467440737e3380_0: "184467440737e3380" + "0" => "184467440737e3380"); impl_case!(case_0_776en1: "0" + "77.6" => "77.6"); impl_case!(case_80802295e5_int0: "80802295e5" + (int)"0" => "80802295e5"); impl_case!(case_239200en4_intneg101: "23.9200" + (int)"-101" => "-77.0800"); impl_case!(case_46636423395767125en15_int0: "46.636423395767125" + (int)"123" => "169.636423395767125"); #[cfg(property_tests)] mod prop { use super::*; use proptest::*; use num_traits::FromPrimitive; proptest! { #[test] fn add_refs_and_owners(f: f32, g: f32) { // ignore non-normal numbers prop_assume!(f.is_normal()); prop_assume!(g.is_normal()); let a = BigDecimal::from_f32(f).unwrap(); let b = BigDecimal::from_f32(g).unwrap(); let own_plus_ref = a.clone() + &b; let ref_plus_own = &a + b.clone(); let mut c = a.clone(); c += &b; let mut d = a.clone(); d += b; prop_assert_eq!(&own_plus_ref, &ref_plus_own); prop_assert_eq!(&c, &ref_plus_own); prop_assert_eq!(&d, &ref_plus_own); } #[test] fn addition_is_communative(f: f32, g: f32) { // ignore non-normal numbers prop_assume!(f.is_normal()); prop_assume!(g.is_normal()); let a = BigDecimal::from_f32(f).unwrap(); let b = BigDecimal::from_f32(g).unwrap(); let a_plus_b = &a + &b; let b_plus_a = &b + &a; prop_assert_eq!(a_plus_b, b_plus_a) } #[test] fn addition_is_associative(f: f32, g: f32, h: f32) { // ignore non-normal numbers prop_assume!(f.is_normal()); prop_assume!(g.is_normal()); prop_assume!(h.is_normal()); let a = BigDecimal::from_f32(f).unwrap(); let b = BigDecimal::from_f32(g).unwrap(); let c = BigDecimal::from_f32(h).unwrap(); let ab = &a + &b; let ab_c = ab + &c; let bc = &b + &c; let a_bc = a + bc; prop_assert_eq!(ab_c, a_bc) } } } } bigdecimal-0.4.10/src/impl_ops_div.rs000064400000000000000000000043271046102023000156150ustar 00000000000000//! Implement division use super::*; 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_quickcheck() == Some(true) { 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 = DEFAULT_PRECISION; 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_quickcheck() == Some(true) { 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 = DEFAULT_PRECISION; return impl_division(self.int_val, &other.int_val, scale, max_precision); } } forward_ref_val_binop!(impl Div for BigDecimal, div); impl Div<&BigDecimal> for &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_quickcheck() == Some(true) { 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 = DEFAULT_PRECISION; return impl_division(num_int.clone(), den_int, scale, max_precision); } } // tests in lib.tests.ops.div.rs bigdecimal-0.4.10/src/impl_ops_mul.rs000064400000000000000000000246501046102023000156310ustar 00000000000000//! Multiplication operator trait implementation //! use super::*; use crate::stdlib::mem::swap; impl Mul for BigDecimal { type Output = BigDecimal; #[inline] fn mul(mut self, rhs: BigDecimal) -> BigDecimal { if self.is_one_quickcheck() == Some(true) { return rhs; } if rhs.is_one_quickcheck() != Some(true) { self.scale += rhs.scale; self.int_val *= rhs.int_val; } self } } impl Mul<&BigDecimal> for BigDecimal { type Output = BigDecimal; #[inline] fn mul(mut self, rhs: &BigDecimal) -> BigDecimal { if self.is_one_quickcheck() == Some(true) { self.scale = rhs.scale; self.int_val.set_zero(); self.int_val += &rhs.int_val; } else if rhs.is_zero() { self.scale = 0; self.int_val.set_zero(); } else if !self.is_zero() && rhs.is_one_quickcheck() != Some(true) { self.scale += rhs.scale; self.int_val *= &rhs.int_val; } self } } impl Mul for &BigDecimal { type Output = BigDecimal; #[inline] fn mul(self, rhs: BigDecimal) -> BigDecimal { rhs * self } } impl Mul<&BigDecimal> for &BigDecimal { type Output = BigDecimal; #[inline] fn mul(self, rhs: &BigDecimal) -> BigDecimal { if self.is_one_quickcheck() == Some(true) { rhs.normalized() } else if rhs.is_one_quickcheck() == Some(true) { self.normalized() } else { 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 Mul<&BigInt> for BigDecimal { type Output = BigDecimal; #[inline] fn mul(mut self, rhs: &BigInt) -> BigDecimal { self.int_val *= rhs; self } } impl Mul for &BigDecimal { type Output = BigDecimal; #[inline] fn mul(self, mut rhs: BigInt) -> BigDecimal { rhs *= &self.int_val; BigDecimal::new(rhs, self.scale) } } impl Mul<&BigInt> for &BigDecimal { type Output = BigDecimal; #[inline] fn mul(self, rhs: &BigInt) -> BigDecimal { if rhs.is_one() { self.normalized() } else if self.is_one_quickcheck() == Some(true) { BigDecimal::new(rhs.clone(), 0) } else { let value = &self.int_val * rhs; BigDecimal::new(value, self.scale) } } } // swap (lhs * rhs) to (rhs * lhs) for (BigInt * BigDecimal) forward_communative_binop!(impl Mul::mul for BigInt); forward_communative_binop!(impl Mul<&BigDecimal>::mul for BigInt); forward_communative_binop!(impl Mul::mul for &BigInt); forward_communative_binop!(impl Mul<&BigDecimal>::mul for &BigInt); impl Mul for BigDecimal { type Output = BigDecimal; #[inline] fn mul(mut self, rhs: BigUint) -> BigDecimal { self *= rhs; self } } impl Mul<&BigUint> for BigDecimal { type Output = BigDecimal; #[inline] fn mul(mut self, rhs: &BigUint) -> BigDecimal { self *= rhs; self } } impl Mul for &BigDecimal { type Output = BigDecimal; #[inline] fn mul(self, rhs: BigUint) -> BigDecimal { self * BigInt::from_biguint(Sign::Plus, rhs) } } impl Mul<&BigUint> for &BigDecimal { type Output = BigDecimal; #[inline] fn mul(self, rhs: &BigUint) -> BigDecimal { if rhs.is_one() { self.normalized() } else if self.is_one_quickcheck() == Some(true) { let value = BigInt::from_biguint(Sign::Plus, rhs.clone()); BigDecimal::new(value, 0) } else { let biguint = self.int_val.magnitude() * rhs; let value = BigInt::from_biguint(self.sign(), biguint); BigDecimal::new(value, self.scale) } } } // swap (lhs * rhs) to (rhs * lhs) for (BigUint * BigDecimal) forward_communative_binop!(impl Mul::mul for BigUint); forward_communative_binop!(impl Mul<&BigDecimal>::mul for BigUint); forward_communative_binop!(impl Mul::mul for &BigUint); forward_communative_binop!(impl Mul<&BigDecimal>::mul for &BigUint); impl MulAssign for BigDecimal { #[inline] fn mul_assign(&mut self, rhs: BigDecimal) { if self.is_one_quickcheck() == Some(true) { self.int_val = rhs.int_val; self.scale = rhs.scale; } else if rhs.is_one_quickcheck() != Some(true) { self.scale += rhs.scale; self.int_val *= rhs.int_val; } } } impl MulAssign<&BigDecimal> for BigDecimal { #[inline] fn mul_assign(&mut self, rhs: &BigDecimal) { if rhs.is_one_quickcheck() == Some(true) { return; } self.scale += rhs.scale; self.int_val *= &rhs.int_val; } } impl MulAssign<&BigInt> for BigDecimal { #[inline] fn mul_assign(&mut self, rhs: &BigInt) { if rhs.is_one() { return; } self.int_val *= rhs; } } impl MulAssign for BigDecimal { #[inline] fn mul_assign(&mut self, rhs: BigInt) { *self *= &rhs } } impl MulAssign for BigDecimal { #[inline] fn mul_assign(&mut self, rhs: BigUint) { if rhs.is_one() { return; } *self *= BigInt::from_biguint(Sign::Plus, rhs); // *self *= &rhs } } impl MulAssign<&BigUint> for BigDecimal { #[inline] fn mul_assign(&mut self, rhs: &BigUint) { if rhs.is_one() { return; } // No way to multiply bigint and biguint, we have to clone *self *= BigInt::from_biguint(Sign::Plus, rhs.clone()); } } #[cfg(test)] #[allow(non_snake_case)] mod bigdecimal_tests { use super::*; use num_traits::{ToPrimitive, FromPrimitive, Signed, Zero, One}; use num_bigint; use paste::paste; macro_rules! impl_test { ($name:ident; $a:literal * $b:literal => $expected:literal) => { #[test] fn $name() { let mut a: BigDecimal = $a.parse().unwrap(); let b: BigDecimal = $b.parse().unwrap(); let expected: BigDecimal = $expected.parse().unwrap(); let prod = a.clone() * b.clone(); assert_eq!(prod, expected); assert_eq!(prod.scale, expected.scale); let prod = a.clone() * &b; assert_eq!(prod, expected); // assert_eq!(prod.scale, expected.scale); let prod = &a * b.clone(); assert_eq!(prod, expected); // assert_eq!(prod.scale, expected.scale); let prod = &a * &b; assert_eq!(prod, expected); assert_eq!(prod.scale, expected.scale); a *= b; assert_eq!(a, expected); assert_eq!(a.scale, expected.scale); } }; ($name:ident; $bigt:ty; $a:literal * $b:literal => $expected:literal) => { #[test] fn $name() { let a: BigDecimal = $a.parse().unwrap(); let b: $bigt = $b.parse().unwrap(); let c: BigDecimal = $expected.parse().unwrap(); let prod = a.clone() * b.clone(); assert_eq!(prod, c); assert_eq!(prod.scale, c.scale); let prod = b.clone() * a.clone(); assert_eq!(prod, c); assert_eq!(prod.scale, c.scale); let prod = a.clone() * &b; assert_eq!(prod, c); assert_eq!(prod.scale, c.scale); let prod = b.clone() * &a; assert_eq!(prod, c); // assert_eq!(prod.scale, c.scale); let prod = &a * b.clone(); assert_eq!(prod, c); assert_eq!(prod.scale, c.scale); let prod = &b * a.clone(); assert_eq!(prod, c); // assert_eq!(prod.scale, c.scale); let prod = &a * &b; assert_eq!(prod, c); // assert_eq!(prod.scale, c.scale); let prod = &b * &a; assert_eq!(prod, c); // assert_eq!(prod.scale, c.scale); } }; } impl_test!(case_2_1; "2" * "1" => "2"); impl_test!(case_12d34_1d234; "12.34" * "1.234" => "15.22756"); impl_test!(case_2e1_1; "2e1" * "1" => "2e1"); impl_test!(case_3_d333333; "3" * ".333333" => "0.999999"); impl_test!(case_2389472934723_209481029831; "2389472934723" * "209481029831" => "500549251119075878721813"); impl_test!(case_1ed450_1e500; "1e-450" * "1e500" => "0.1e51"); impl_test!(case_n995052931ddd_4d523087321; "-995052931372975485719.533153137" * "4.523087321" => "-4500711297616988541501.836966993116075977"); impl_test!(case_995052931ddd_n4d523087321; "995052931372975485719.533153137" * "-4.523087321" => "-4500711297616988541501.836966993116075977"); impl_test!(case_n8d37664968_n4d523087321; "-8.37664968" * "-1.9086963714056968482094712882596748" => "15.988480848752691653730876239769592670324064"); impl_test!(case_n8d37664968_0; "-8.37664968" * "0" => "0.00000000"); impl_test!(case_8d561_10; BigInt; "8.561" * "10" => "85.610"); // Test multiplication between big decimal and big integer impl_test!(case_10000_638655273892892437; BigInt; "10000" * "638655273892892437" => "6386552738928924370000"); impl_test!(case_1en10_n9056180052657301; BigInt; "1e-10" * "-9056180052657301" => "-905618.0052657301"); impl_test!(case_n9en1_n368408638655273892892437473; BigInt; "-9e-1" * "-368408638655273892892437473" => "331567774789746503603193725.7"); impl_test!(case_n1d175470587012343730098_577575785; BigInt; "-1.175470587012343730098" * "577575785" => "-678923347.038065234601180476930"); impl_test!(case_1d000000_7848321491728058276; BigInt; "1.000000" * "7848321491728058276" => "7848321491728058276.000000"); impl_test!(case_16535178640845d04844_1; BigInt; "16535178640845.04844" * "1" => "16535178640845.04844"); impl_test!(case_1d000000_u7848321491728058276; BigUint; "1.000000" * "7848321491728058276" => "7848321491728058276.000000"); impl_test!(case_16535178640845d04844_u1; BigUint; "16535178640845.04844" * "1" => "16535178640845.04844"); } bigdecimal-0.4.10/src/impl_ops_rem.rs000064400000000000000000000107561046102023000156210ustar 00000000000000//! Remainder implementations use super::*; impl Rem for BigDecimal { type Output = BigDecimal; #[inline] fn rem(self, other: BigDecimal) -> BigDecimal { let scale = 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 Rem<&BigDecimal> for BigDecimal { type Output = BigDecimal; #[inline] fn rem(self, other: &BigDecimal) -> BigDecimal { let scale = 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 Rem for &BigDecimal { type Output = BigDecimal; #[inline] fn rem(self, other: BigDecimal) -> BigDecimal { let scale = 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 Rem<&BigDecimal> for &BigDecimal { type Output = BigDecimal; #[inline] fn rem(self, other: &BigDecimal) -> BigDecimal { let scale = 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 RemAssign<&BigDecimal> for BigDecimal { fn rem_assign(&mut self, other: &BigDecimal) { let rem = (&*self).rem(other); *self = rem; } } #[cfg(test)] mod test { use super::*; use paste::paste; macro_rules! impl_case { ($a:literal % $b:literal => $c:literal ) => { paste! { impl_case!([< case_ $a _ $b >]: $a % $b => $c); } }; ($name:ident: $a:literal % $b:literal => $c:literal ) => { #[test] fn $name() { let mut a: BigDecimal = $a.parse().unwrap(); let b: BigDecimal = $b.parse().unwrap(); let c: BigDecimal = $c.parse().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); } }; } impl_case!("100" % "5" => "0"); impl_case!("2e1" % "1" => "0"); impl_case!("2" % "1" => "0"); impl_case!("1" % "3" => "1"); impl_case!("1" % "5e-1" => "0"); impl_case!("15e-1" % "1" => "0.5"); impl_case!("1" % "3e-2" => "1e-2"); impl_case!("10" % "3e-3" => "0.001"); impl_case!("3" % "2" => "1"); impl_case!("1234e-2" % "1233e-3" => "0.01"); impl_case!(case_neg3_2: "-3" % "2" => "-1"); impl_case!(case_3_neg2: "3" % "-2" => "1"); impl_case!(case_neg3_neg2: "3" % "-2" => "1"); impl_case!(case_neg95eneg1_515eneg2: "-9.5" % "5.15" => "-4.35"); #[cfg(property_tests)] mod prop { use super::*; use proptest::*; use num_traits::FromPrimitive; proptest! { #[test] fn quotient_and_remainder(f: f32, g: f32) { // ignore non-normal numbers prop_assume!(f.is_normal()); prop_assume!(g.is_normal()); prop_assume!(!g.is_zero()); let (f, g) = if f.abs() > g.abs() { (f, g) } else { (g, f) }; let a = BigDecimal::from_f32(f).unwrap(); let b = BigDecimal::from_f32(g).unwrap(); let r = &a % &b; let q = (&a / &b).with_scale(0); assert_eq!(a, q * b + r); } } } } bigdecimal-0.4.10/src/impl_ops_sub.rs000064400000000000000000000225201046102023000156170ustar 00000000000000//! //! Subtraction operator trait implementation //! use crate::*; impl Sub for BigDecimal { type Output = BigDecimal; #[inline] fn sub(self, rhs: BigDecimal) -> BigDecimal { if rhs.is_zero() { return self; } if self.is_zero() { return rhs.neg(); } 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 => { let rhs = rhs.take_and_scale(lhs.scale); lhs - rhs }, } } } impl Sub for &'_ BigDecimal { type Output = BigDecimal; #[inline] fn sub(self, rhs: BigDecimal) -> BigDecimal { self.to_ref() - rhs } } impl Sub for BigDecimalRef<'_> { type Output = BigDecimal; #[inline] fn sub(self, rhs: BigDecimal) -> BigDecimal { (rhs - self).neg() } } impl<'a, T: Into>> Sub for BigDecimal { type Output = BigDecimal; fn sub(mut self, rhs: T) -> BigDecimal { self.sub_assign(rhs); self } } impl<'a, T: Into>> Sub for &'_ BigDecimal { type Output = BigDecimal; fn sub(self, rhs: T) -> BigDecimal { let rhs = rhs.into(); match self.scale.cmp(&rhs.scale) { Ordering::Equal => { self.clone() - rhs } Ordering::Less => { self.with_scale(rhs.scale) - rhs } Ordering::Greater => { self - rhs.to_owned_with_scale(self.scale) } } } } impl<'a, T: Into>> Sub for BigDecimalRef<'_> { type Output = BigDecimal; fn sub(self, rhs: T) -> BigDecimal { let rhs = rhs.into(); match self.scale.cmp(&rhs.scale) { Ordering::Equal => self.to_owned() - rhs, Ordering::Less => self.to_owned_with_scale(rhs.scale) - rhs, Ordering::Greater => self - rhs.to_owned_with_scale(self.scale), } } } impl Sub for BigDecimal { type Output = BigDecimal; fn sub(mut self, rhs: BigInt) -> BigDecimal { self.sub_assign(rhs); self } } impl Sub for &'_ BigDecimal { type Output = BigDecimal; #[inline] fn sub(self, rhs: BigInt) -> BigDecimal { self.to_ref() - rhs } } impl Sub for BigDecimalRef<'_> { type Output = BigDecimal; #[inline] fn sub(self, rhs: BigInt) -> BigDecimal { self - BigDecimal::from(rhs) } } impl Sub for BigInt { type Output = BigDecimal; #[inline] fn sub(self, rhs: BigDecimal) -> BigDecimal { (rhs - self).neg() } } impl Sub for &BigInt { type Output = BigDecimal; #[inline] fn sub(self, rhs: BigDecimal) -> BigDecimal { (rhs - self).neg() } } impl<'a> Sub> for BigInt { type Output = BigDecimal; #[inline] fn sub(self, rhs: BigDecimalRef<'a>) -> BigDecimal { (rhs - &self).neg() } } impl<'a> Sub> for &BigInt { type Output = BigDecimal; #[inline] fn sub(self, rhs: BigDecimalRef<'a>) -> BigDecimal { (rhs - self).neg() } } impl SubAssign for BigDecimal { #[inline] fn sub_assign(&mut self, rhs: BigDecimal) { if rhs.is_zero() { return; } if self.is_zero() { *self = rhs.neg(); return; } match self.scale.cmp(&rhs.scale) { Ordering::Equal => { self.int_val -= rhs.int_val; } Ordering::Less => { self.int_val *= ten_to_the((rhs.scale - self.scale) as u64); self.int_val -= rhs.int_val; self.scale = rhs.scale; } Ordering::Greater => { let mut rhs_int_val = rhs.int_val; rhs_int_val *= ten_to_the((self.scale - rhs.scale) as u64); self.int_val -= rhs_int_val; } } } } impl<'rhs, T: Into>> SubAssign for BigDecimal { #[inline] fn sub_assign(&mut self, rhs: T) { let rhs = rhs.into(); if rhs.is_zero() { return; } if self.is_zero() { *self = rhs.neg().to_owned(); return; } match self.scale.cmp(&rhs.scale) { Ordering::Equal => { self.int_val -= rhs.to_owned().int_val; } Ordering::Less => { self.int_val *= ten_to_the((rhs.scale - self.scale) as u64); self.int_val -= rhs.to_owned().int_val; self.scale = rhs.scale; } Ordering::Greater => { *self -= rhs.to_owned_with_scale(self.scale); } } } } impl SubAssign for BigDecimal { #[inline(always)] fn sub_assign(&mut self, rhs: BigInt) { *self -= BigDecimal::new(rhs, 0) } } #[cfg(test)] mod test { use super::*; use paste::paste; macro_rules! impl_case { ($name:ident: $a:literal - $b:literal => $c:literal ) => { #[test] fn $name() { let a: BigDecimal = $a.parse().unwrap(); let b: BigDecimal = $b.parse().unwrap(); let c: BigDecimal = $c.parse().unwrap(); assert_eq!(c, a.clone() - b.clone()); assert_eq!(c, a.clone() - &b); assert_eq!(c, &a - b.clone()); assert_eq!(c, &a - &b); assert_eq!(c, a.to_ref() - &b); assert_eq!(c, &a - b.to_ref()); assert_eq!(c, a.to_ref() - b.to_ref()); let mut n = a.clone(); n -= b.to_ref(); assert_eq!(n, c); let mut n = a.clone(); n -= &b; assert_eq!(n, c); let mut n = a.clone(); n -= b.clone(); assert_eq!(n, c); let mut n = a.clone(); (&mut n).sub_assign(b.clone()); assert_eq!(n, c); } }; ($name:ident: $a:literal - (int) $b:literal => $c:literal ) => { #[test] fn $name() { let a: BigDecimal = $a.parse().unwrap(); let b: BigInt = $b.parse().unwrap(); let expected: BigDecimal = $c.parse().unwrap(); assert_eq!(expected, a.clone() - b.clone()); assert_eq!(expected, a.clone() - &b); assert_eq!(expected, &a - &b); assert_eq!(expected, &a - b.clone()); assert_eq!(expected, a.to_ref() - &b); let expected_neg = expected.clone().neg(); assert_eq!(expected_neg, b.clone() - a.clone()); assert_eq!(expected_neg, &b - a.to_ref()); assert_eq!(expected_neg, &b - a.clone()); } }; } impl_case!(case_1234en2_1234en3: "12.34" - "1.234" => "11.106"); impl_case!(case_1234en2_n1234en3: "12.34" - "-1.234" => "13.574"); impl_case!(case_1234e6_1234en6: "1234e6" - "1234e-6" => "1233999999.998766"); impl_case!(case_1234en6_1234e6: "1234e-6" - "1234e6" => "-1233999999.998766"); impl_case!(case_712911676en6_4856259269250829: "712911676e-6" - "4856259269250829" => "-4856259269250116.088324"); impl_case!(case_85616001e4_0: "85616001e4" - "0" => "85616001e4"); impl_case!(case_0_520707672en5: "0" - "5207.07672" => "-520707672e-5"); impl_case!(case_99291289e5_int0: "99291289e5" - (int)"0" => "99291289e5"); impl_case!(case_7051277471570131en16_int1: "0.7051277471570131" - (int)"1" => "-0.2948722528429869"); impl_case!(case_4068603022763836en8_intneg10: "40686030.22763836" - (int)"-10" => "40686040.22763836"); #[cfg(property_tests)] mod prop { use super::*; use proptest::*; use num_traits::FromPrimitive; proptest! { #[test] fn sub_refs_and_owners(f: f32, g: f32) { // ignore non-normal numbers prop_assume!(f.is_normal()); prop_assume!(g.is_normal()); let a = BigDecimal::from_f32(f).unwrap(); let b = BigDecimal::from_f32(g).unwrap(); let own_minus_ref = a.clone() - &b; let ref_minus_own = &a - b.clone(); let mut c = a.clone(); c -= &b; let mut d = a.clone(); d -= b; prop_assert_eq!(&own_minus_ref, &ref_minus_own); prop_assert_eq!(&c, &ref_minus_own); prop_assert_eq!(&d, &ref_minus_own); } #[test] fn subtraction_is_anticommunative(f: f32, g: f32) { // ignore non-normal numbers prop_assume!(f.is_normal()); prop_assume!(g.is_normal()); let a = BigDecimal::from_f32(f).unwrap(); let b = BigDecimal::from_f32(g).unwrap(); let a_minus_b = &a - &b; let b_minus_a = &b - &a; prop_assert_eq!(a_minus_b, -b_minus_a) } } } } bigdecimal-0.4.10/src/impl_serde.rs000064400000000000000000000352341046102023000152550ustar 00000000000000//! //! Support for serde implementations //! use crate::*; use serde_crate::{self as serde, de, ser, Serialize, Deserialize}; // const SERDE_SCALE_LIMIT: usize = = ${RUST_BIGDECIMAL_SERDE_SCALE_LIMIT} or 150_000; #[cfg(feature = "serde_json")] include!(concat!(env!("OUT_DIR"), "/serde_scale_limit.rs")); impl ser::Serialize for BigDecimal { fn serialize(&self, serializer: S) -> Result where S: ser::Serializer, { serializer.collect_str(&self) } } /// Used by SerDe to construct a BigDecimal 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, { 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_u128(self, value: u128) -> Result where E: de::Error, { Ok(BigDecimal::from(value)) } fn visit_i128(self, value: i128) -> Result where E: de::Error, { Ok(BigDecimal::from(value)) } fn visit_f32(self, value: f32) -> Result where E: de::Error, { BigDecimal::try_from(value).map_err(|err| E::custom(format!("{}", err))) } fn visit_f64(self, value: f64) -> Result where E: de::Error, { BigDecimal::try_from(value).map_err(|err| E::custom(format!("{}", err))) } fn visit_map(self, mut map: A) -> Result where A: de::MapAccess<'de>, { match map.next_key::<&str>() { Ok(Some("$serde_json::private::Number")) => { map.next_value::() } _ => { Err(de::Error::invalid_type(de::Unexpected::Map, &self)) } } } } #[cfg(not(feature = "string-only"))] impl<'de> de::Deserialize<'de> for BigDecimal { fn deserialize(d: D) -> Result where D: de::Deserializer<'de>, { d.deserialize_any(BigDecimalVisitor) } } #[cfg(feature = "string-only")] impl<'de> de::Deserialize<'de> for BigDecimal { fn deserialize(d: D) -> Result where D: de::Deserializer<'de>, { d.deserialize_str(BigDecimalVisitor) } } #[cfg(test)] mod test { use super::*; use paste::paste; use serde_test::{ Token, assert_tokens, assert_de_tokens, assert_de_tokens_error }; mod serde_serialize_deserialize_str { use super::*; macro_rules! impl_case { ($name:ident : $input:literal => $output:literal) => { #[test] fn $name() { let expected = Token::Str($output); let decimal: BigDecimal = $input.parse().unwrap(); assert_tokens(&decimal, &[expected]); } }; } impl_case!(case_1d0: "1.0" => "1.0"); impl_case!(case_0d5: "0.5" => "0.5"); impl_case!(case_50: "50" => "50"); impl_case!(case_50000: "50000" => "50000"); impl_case!(case_1en3: "1e-3" => "0.001"); impl_case!(case_10e11: "10e11" => "1000000000000"); impl_case!(case_d25: ".25" => "0.25"); impl_case!(case_12d34e1: "12.34e1" => "123.4"); impl_case!(case_40d0010: "40.0010" => "40.0010"); } #[cfg(not(feature = "string-only"))] mod serde_deserialize_int { use super::*; macro_rules! impl_case { ( $( $ttype:ident ),+ : -$input:literal ) => { $( paste! { impl_case!([< case_n $input _ $ttype:lower >] : $ttype : -$input); } )* }; ( $( $ttype:ident ),+ : $input:literal ) => { $( paste! { impl_case!([< case_ $input _ $ttype:lower >] : $ttype : $input); } )* }; ($name:ident : $type:ident : $input:literal) => { #[test] fn $name() { let expected = BigDecimal::from($input); let token = Token::$type($input); assert_de_tokens(&expected, &[token]); } }; } impl_case!(I8, I16, I32, I64, U8, U16, U32, U64 : 0); impl_case!(I8, I16, I32, I64, U8, U16, U32, U64 : 1); impl_case!(I8, I16, I32, I64 : -1); impl_case!(I64: -99999999999i64); impl_case!(I64: -9_223_372_036_854_775_808i64); } #[cfg(not(feature = "string-only"))] mod serde_deserialize_float { use super::*; macro_rules! impl_case { ( $name:ident : $input:literal => $ttype:ident : $expected:literal ) => { paste! { #[test] fn [< $name _ $ttype:lower >]() { let expected: BigDecimal = $expected.parse().unwrap(); let token = Token::$ttype($input); assert_de_tokens(&expected, &[token]); } } }; ( $name:ident : $input:literal => $( $ttype:ident : $expected:literal )+ ) => { $( impl_case!($name : $input => $ttype : $expected); )* }; ( $name:ident : $input:literal => $( $ttype:ident ),+ : $expected:literal ) => { $( impl_case!($name : $input => $ttype : $expected); )* }; } impl_case!(case_1d0 : 1.0 => F32, F64 : "1"); impl_case!(case_1d1 : 1.1 => F32 : "1.10000002384185791015625" F64 : "1.100000000000000088817841970012523233890533447265625"); impl_case!(case_0d001834988943300: 0.001834988943300 => F32 : "0.001834988943301141262054443359375" F64 : "0.00183498894330000003084768511740776375518180429935455322265625"); impl_case!(case_n869651d9131236838: -869651.9131236838 => F32 : "-869651.9375" F64 : "-869651.91312368377111852169036865234375"); impl_case!(case_n1en20: -1e-20 => F32 : "-9.999999682655225388967887463487205224055287544615566730499267578125E-21" F64 : "-999999999999999945153271454209571651729503702787392447107715776066783064379706047475337982177734375e-119"); } #[cfg(not(feature = "string-only"))] mod serde_deserialize_nan { use super::*; #[test] fn case_f32() { let tokens = [ Token::F32(f32::NAN) ]; assert_de_tokens_error::(&tokens, "NAN"); } #[test] fn case_f64() { let tokens = [ Token::F64(f64::NAN) ]; assert_de_tokens_error::(&tokens, "NAN"); } } #[cfg(feature = "serde_json")] mod json_support { use super::*; use impl_serde::{Serialize, Deserialize}; use serde_json; #[derive(Serialize, Deserialize)] struct TestStruct { name: String, value: BigDecimal, #[serde(with = "crate::serde::json_num")] number: BigDecimal, } #[test] fn test_struct_parsing() { let json_src = r#" { "name": "foo", "value": 0.0008741329382918, "number": "12.34" } "#; let my_struct: TestStruct = serde_json::from_str(&json_src).unwrap(); assert_eq!(&my_struct.name, "foo"); assert_eq!(&my_struct.value, &"0.0008741329382918".parse::().unwrap()); assert_eq!(&my_struct.number, &"12.34".parse::().unwrap()); let s = serde_json::to_string(&my_struct).unwrap(); assert_eq!(s, r#"{"name":"foo","value":"0.0008741329382918","number":12.34}"#); } } } /// Serialize/deserialize [`BigDecimal`] as arbitrary precision numbers in JSON using the `arbitrary_precision` feature within `serde_json`. /// // The following example is ignored as it requires derives which we don't import and aren't compatible // with our locked versions of rust due to proc_macro2. /// ```ignore /// # extern crate serde; /// # use serde::{Serialize, Deserialize}; /// # use bigdecimal::BigDecimal; /// # use std::str::FromStr; /// /// #[derive(Serialize, Deserialize)] /// pub struct ArbitraryExample { /// #[serde(with = "bigdecimal::serde::json_num")] /// value: BigDecimal, /// } /// /// let value = ArbitraryExample { value: BigDecimal::from_str("123.400").unwrap() }; /// assert_eq!( /// &serde_json::to_string(&value).unwrap(), /// r#"{"value":123.400}"# /// ); /// ``` #[cfg(feature = "serde_json")] pub mod arbitrary_precision { use super::*; pub fn deserialize<'de, D>(deserializer: D) -> Result where D: serde::de::Deserializer<'de>, { let n = BigDecimal::deserialize(deserializer)?; if n.scale.abs() > SERDE_SCALE_LIMIT && SERDE_SCALE_LIMIT > 0 { let msg = format!("Calculated exponent '{}' out of bounds", -n.scale); Err(serde::de::Error::custom(msg)) } else { Ok(n) } } pub fn serialize(value: &BigDecimal, serializer: S) -> Result where S: serde::Serializer, { serde_json::Number::from_str(&value.to_string()) .map_err(ser::Error::custom)? .serialize(serializer) } } /// Serialize/deserialize [`Option`] as arbitrary precision numbers in JSON using the `arbitrary_precision` feature within `serde_json`. /// // The following example is ignored as it requires derives which we don't import and aren't compatible // with our locked versions of rust due to proc_macro2. /// ```ignore /// # extern crate serde; /// # use serde::{Serialize, Deserialize}; /// # use bigdecimal::BigDecimal; /// # use std::str::FromStr; /// /// #[derive(Serialize, Deserialize)] /// pub struct ArbitraryExample { /// #[serde(with = "bigdecimal::impl_serde::arbitrary_precision_option")] /// value: Option, /// } /// /// let value = ArbitraryExample { value: Some(BigDecimal::from_str("123.400").unwrap()) }; /// assert_eq!( /// &serde_json::to_string(&value).unwrap(), /// r#"{"value":123.400}"# /// ); /// /// let value = ArbitraryExample { value: None }; /// assert_eq!( /// &serde_json::to_string(&value).unwrap(), /// r#"{"value":null}"# /// ); /// ``` #[cfg(feature = "serde_json")] pub mod arbitrary_precision_option { use super::*; pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::de::Deserializer<'de>, { Option::::deserialize(deserializer)? .map(|num| num.as_str().parse().map_err(serde::de::Error::custom)) .transpose() } pub fn serialize(value: &Option, serializer: S) -> Result where S: serde::Serializer, { match *value { Some(ref decimal) => { serde_json::Number::from_str(&decimal.to_string()) .map_err(serde::ser::Error::custom)? .serialize(serializer) } None => serializer.serialize_none(), } } } #[cfg(all(test, feature = "serde_json"))] mod test_jsonification { use super::*; extern crate serde_json; mod deserialize_f64 { use super::*; macro_rules! impl_case { ($name:ident : $input:expr) => { impl_case!($name: $input => $input); }; ($name:ident : $input:expr => $expected:literal) => { #[test] fn $name() { let mut json_deserialize = serde_json::Deserializer::from_str($input); let value = arbitrary_precision::deserialize(&mut json_deserialize) .expect("should parse JSON"); let expected: BigDecimal = $expected.parse().unwrap(); assert_eq!(expected, value); } }; } impl_case!(case_1d0: "1.0" => "1.0"); impl_case!(case_0d001: "0.001" => "0.001"); impl_case!(case_41009d2207etc: "41009.22075436852032769878903135430037010"); } mod serde_struct_decimals { use super::*; use crate as bigdecimal; #[derive(Serialize, Deserialize)] pub struct TestExample { #[serde(with = "bigdecimal::serde::json_num")] value: BigDecimal, } macro_rules! impl_case { ($name:ident : $input:expr => (error)) => { #[test] fn $name() { let res = serde_json::from_str::($input); assert!(res.is_err()); } }; ($name:ident : $input:expr => $expected:expr) => { #[test] fn $name() { let obj: TestExample = serde_json::from_str($input).unwrap(); let expected: BigDecimal = $expected.parse().unwrap(); assert_eq!(expected, obj.value); // expect output to be input with all spaces removed let s = serde_json::to_string(&obj).unwrap(); let input_stripped = $input.replace(" ", ""); assert_eq!(&s, &input_stripped); } }; } impl_case!(case_1d0: r#"{ "value": 1.0 }"# => "1.0" ); impl_case!(case_2d01: r#"{ "value": 2.01 }"# => "2.01" ); impl_case!(case_50: r#"{ "value": 50 }"# => "50" ); impl_case!(case_high_prec: r#"{ "value": 64771126779.35857825871133263810255301911 }"# => "64771126779.35857825871133263810255301911" ); impl_case!(case_nan: r#"{ "value": nan }"# => (error) ); #[test] fn scale_out_of_bounds() { use serde_crate::de::Error; let src = r#"{ "value": 1e92233720392233 }"#; let parse_err = serde_json::from_str::(&src).err().unwrap(); let err_str = parse_err.to_string(); assert!(err_str.starts_with("Calculated exponent '92233720392233' out of bounds"), "{}", err_str); } } } bigdecimal-0.4.10/src/impl_trait_from_str.rs000064400000000000000000000055061046102023000172100ustar 00000000000000use crate::*; use stdlib::str::FromStr; impl FromStr for BigDecimal { type Err = ParseBigDecimalError; #[inline] fn from_str(s: &str) -> Result { // implemented in impl_num.rs BigDecimal::from_str_radix(s, 10) } } #[cfg(test)] mod tests { use super::*; macro_rules! impl_case { ($name:ident: $input:literal => $int:literal E $exp:literal) => { #[test] fn $name() { let dec = BigDecimal::from_str($input).unwrap(); assert_eq!(dec.int_val, $int.into()); assert_eq!(dec.scale, -($exp)); } }; } impl_case!(case_1331d107: "1331.107" => 1331107 E -3 ); impl_case!(case_1d0: "1.0" => 10 E -1 ); impl_case!(case_2e1: "2e1" => 2 E 1 ); impl_case!(case_0d00123: "0.00123" => 123 E -5); impl_case!(case_n123: "-123" => -123 E -0); impl_case!(case_n1230: "-1230" => -1230 E -0); impl_case!(case_12d3: "12.3" => 123 E -1); impl_case!(case_123en1: "123e-1" => 123 E -1); impl_case!(case_1d23ep1: "1.23e+1" => 123 E -1); impl_case!(case_1d23ep3: "1.23E+3" => 123 E 1); impl_case!(case_1d23en8: "1.23E-8" => 123 E -10); impl_case!(case_n1d23en10: "-1.23E-10" => -123 E -12); impl_case!(case_123_: "123_" => 123 E -0); impl_case!(case_31_862_140d830_686_979: "31_862_140.830_686_979" => 31862140830686979i128 E -9); impl_case!(case_n1_1d2_2: "-1_1.2_2" => -1122 E -2); impl_case!(case_999d521_939: "999.521_939" => 999521939 E -6); impl_case!(case_679d35_84_03en2: "679.35_84_03E-2" => 679358403 E -8); impl_case!(case_271576662d_e4: "271576662.__E4" => 271576662 E 4); impl_case!(case_1_d_2: "1_._2" => 12 E -1); } #[cfg(test)] mod test_invalid { use super::*; macro_rules! impl_case { ($name:ident: $input:literal => $exp:literal) => { #[test] #[should_panic(expected = $exp)] fn $name() { BigDecimal::from_str($input).unwrap(); } }; } impl_case!(case_bad_string_empty : "" => "Empty"); impl_case!(case_bad_string_empty_exponent : "123.123E" => "Empty"); impl_case!(case_bad_string_only_decimal_point : "." => "Empty"); impl_case!(test_bad_string_only_decimal_and_exponent : ".e4" => "Empty"); impl_case!(test_bad_string_only_decimal_and_underscore : "_._" => "InvalidDigit"); impl_case!(case_bad_string_hello : "hello" => "InvalidDigit"); impl_case!(case_bad_string_nan : "nan" => "InvalidDigit"); impl_case!(case_bad_string_invalid_char : "12z3.12" => "InvalidDigit"); impl_case!(case_bad_string_nan_exponent : "123.123eg" => "InvalidDigit"); impl_case!(case_bad_string_multiple_decimal_points : "123.12.45" => "InvalidDigit"); impl_case!(case_bad_string_hex : "0xCafeBeef" => "InvalidDigit"); } bigdecimal-0.4.10/src/lib.rs000064400000000000000000002256101046102023000136770ustar 00000000000000// Copyright 2016 Adam Sunderland // 2016-2023 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); //! ``` #![cfg_attr(not(feature = "std"), no_std)] #![allow(clippy::style)] #![allow(clippy::excessive_precision)] #![allow(clippy::unreadable_literal)] #![allow(clippy::unusual_byte_groupings)] #![allow(clippy::needless_late_init)] #![allow(clippy::needless_return)] #![allow(clippy::suspicious_arithmetic_impl)] #![allow(clippy::suspicious_op_assign_impl)] #![allow(clippy::redundant_field_names)] #![allow(clippy::approx_constant)] #![allow(clippy::wrong_self_convention)] #![allow(clippy::doc_overindented_list_items)] #![cfg_attr(test, allow(clippy::useless_vec))] #![allow(non_shorthand_field_patterns)] #![allow(unused_imports)] pub extern crate num_bigint; pub extern crate num_traits; extern crate num_integer; #[cfg(test)] extern crate paste; #[cfg(feature = "serde")] extern crate serde as serde_crate; #[cfg(all(test, any(feature = "serde", feature = "serde_json")))] extern crate serde_test; #[cfg(all(test, feature = "serde_json"))] extern crate serde_json; #[cfg(feature = "std")] include!("./with_std.rs"); #[cfg(not(feature = "std"))] include!("./without_std.rs"); // make available some standard items use self::stdlib::cmp::{self, Ordering}; use self::stdlib::convert::TryFrom; use self::stdlib::default::Default; use self::stdlib::hash::{Hash, Hasher}; use self::stdlib::num::{ParseFloatError, ParseIntError}; use self::stdlib::ops::{ Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign, Rem, RemAssign, }; use self::stdlib::iter::Sum; use self::stdlib::str::FromStr; use self::stdlib::string::{String, ToString}; use self::stdlib::fmt; use self::stdlib::Vec; use self::stdlib::borrow::Cow; use num_bigint::{BigInt, BigUint, ParseBigIntError, Sign}; use num_integer::Integer as IntegerTrait; pub use num_traits::{FromPrimitive, Num, One, Pow, Signed, ToPrimitive, Zero}; use stdlib::f64::consts::LOG2_10; use stdlib::f64::consts::LOG10_2; // const DEFAULT_PRECISION: u64 = ${RUST_BIGDECIMAL_DEFAULT_PRECISION} or 100; include!(concat!(env!("OUT_DIR"), "/default_precision.rs")); #[macro_use] mod macros; // "low level" functions mod arithmetic; // digit & radix routines mod bigdigit; // From, To, TryFrom impls mod impl_convert; mod impl_trait_from_str; // Add, Sub, etc... mod impl_ops; mod impl_ops_add; mod impl_ops_sub; mod impl_ops_mul; mod impl_ops_div; mod impl_ops_rem; // PartialEq mod impl_cmp; // Implementations of num_traits mod impl_num; // Implementations of std::fmt traits and stringificaiton routines mod impl_fmt; // Implementations for deserializations and serializations #[cfg(any(feature = "serde", feature = "serde_json"))] pub mod impl_serde; /// re-export serde-json derive modules #[cfg(feature = "serde_json")] pub mod serde { /// Parse JSON number directly to BigDecimal pub use impl_serde::arbitrary_precision as json_num; /// Parse JSON (number | null) directly to Option pub use impl_serde::arbitrary_precision_option as json_num_option; } // construct BigDecimals from strings and floats mod parsing; // Routines for rounding pub mod rounding; pub use rounding::RoundingMode; // Mathematical context mod context; pub use context::Context; use arithmetic::{ ten_to_the, ten_to_the_uint, ten_to_the_u64, diff, diff_usize, count_decimal_digits, count_decimal_digits_uint, }; /// Internal function used for rounding /// /// returns 1 if most significant digit is >= 5, otherwise 0 /// /// 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 / LOG2_10) 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`. /// /// The more explicit method `from_bigint` should be preferred, as new /// may change in the future. /// #[inline] pub fn new(digits: BigInt, scale: i64) -> BigDecimal { BigDecimal::from_bigint(digits, scale) } /// Construct BigDecimal from BigInt and a scale pub fn from_bigint(digits: BigInt, scale: i64) -> BigDecimal { BigDecimal { int_val: digits, scale: scale, } } /// Construct positive BigDecimal from BigUint and a scale pub fn from_biguint(digits: BigUint, scale: i64) -> BigDecimal { let n = BigInt::from_biguint(Sign::Plus, digits); BigDecimal::from_bigint(n, scale) } /// Make a BigDecimalRef of this value pub fn to_ref(&self) -> BigDecimalRef<'_> { // search for "From<&'a BigDecimal> for BigDecimalRef<'a>" self.into() } /// Count of decimal digits /// /// Zero is considered to be one digit. /// pub fn decimal_digit_count(&self) -> u64 { if self.is_zero() { return 1; } count_decimal_digits_uint(self.int_val.magnitude()) } /// Position of most significant digit of this decimal /// /// Equivalent to the exponent when written in scientific notation, /// or `⌊log10(n)⌋`. /// /// The order of magnitude of 0 is 0. /// pub fn order_of_magnitude(&self) -> i64 { self.to_ref().order_of_magnitude() } /// Returns the scale of the BigDecimal, the total number of /// digits to the right of the decimal point (including insignificant /// leading zeros) /// /// # Examples /// /// ``` /// use bigdecimal::BigDecimal; /// use std::str::FromStr; /// /// let a = BigDecimal::from(12345); // No fractional part /// let b = BigDecimal::from_str("123.45").unwrap(); // Fractional part /// let c = BigDecimal::from_str("0.0000012345").unwrap(); // Completely fractional part /// let d = BigDecimal::from_str("5e9").unwrap(); // Negative-fractional part /// /// assert_eq!(a.fractional_digit_count(), 0); /// assert_eq!(b.fractional_digit_count(), 2); /// assert_eq!(c.fractional_digit_count(), 10); /// assert_eq!(d.fractional_digit_count(), -9); /// ``` #[inline] pub fn fractional_digit_count(&self) -> i64 { self.scale } /// Creates and initializes a `BigDecimal`. /// /// Decodes using `str::from_utf8` and forwards to `BigDecimal::from_str_radix`. /// Only base-10 is supported. /// /// # Examples /// /// ``` /// use bigdecimal::{BigDecimal, Zero}; /// /// assert_eq!(BigDecimal::parse_bytes(b"0", 10).unwrap(), BigDecimal::zero()); /// assert_eq!(BigDecimal::parse_bytes(b"13", 10).unwrap(), BigDecimal::from(13)); /// ``` #[inline] pub fn parse_bytes(buf: &[u8], radix: u32) -> Option { stdlib::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); } match new_scale.cmp(&self.scale) { Ordering::Greater => { 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) } Ordering::Less => { 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) } Ordering::Equal => self.clone(), } } /// Return a new BigDecimal after shortening the digits and rounding /// /// ``` /// # use bigdecimal::*; /// /// let n: BigDecimal = "129.41675".parse().unwrap(); /// /// assert_eq!(n.with_scale_round(2, RoundingMode::Up), "129.42".parse::().unwrap()); /// assert_eq!(n.with_scale_round(-1, RoundingMode::Down), "120".parse::().unwrap()); /// assert_eq!(n.with_scale_round(4, RoundingMode::HalfEven), "129.4168".parse::().unwrap()); /// ``` pub fn with_scale_round(&self, new_scale: i64, mode: RoundingMode) -> BigDecimal { use stdlib::cmp::Ordering::*; if self.int_val.is_zero() { return BigDecimal::new(BigInt::zero(), new_scale); } match new_scale.cmp(&self.scale) { Ordering::Equal => { self.clone() } Ordering::Greater => { // increase number of zeros 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) } Ordering::Less => { let (sign, mut digits) = self.int_val.to_radix_le(10); let digit_count = digits.len(); let int_digit_count = digit_count as i64 - self.scale; let rounded_int = match int_digit_count.cmp(&-new_scale) { Equal => { let (&last_digit, remaining) = digits.split_last().unwrap(); let trailing_zeros = remaining.iter().all(Zero::is_zero); let rounded_digit = mode.round_pair(sign, (0, last_digit), trailing_zeros); BigInt::new(sign, vec![rounded_digit as u32]) } Less => { debug_assert!(!digits.iter().all(Zero::is_zero)); let rounded_digit = mode.round_pair(sign, (0, 0), false); BigInt::new(sign, vec![rounded_digit as u32]) } Greater => { // location of new rounding point let scale_diff = (self.scale - new_scale) as usize; let low_digit = digits[scale_diff - 1]; let high_digit = digits[scale_diff]; let trailing_zeros = digits[0..scale_diff-1].iter().all(Zero::is_zero); let rounded_digit = mode.round_pair(sign, (high_digit, low_digit), trailing_zeros); debug_assert!(rounded_digit <= 10); if rounded_digit < 10 { digits[scale_diff] = rounded_digit; } else { digits[scale_diff] = 0; let mut i = scale_diff + 1; loop { if i == digit_count { digits.push(1); break; } if digits[i] < 9 { digits[i] += 1; break; } digits[i] = 0; i += 1; } } BigInt::from_radix_le(sign, &digits[scale_diff..], 10).unwrap() } }; BigDecimal::new(rounded_int, new_scale) } } } /// Return a new BigDecimal object with same value and given scale, /// padding with zeros or truncating digits as needed /// /// Useful for aligning decimals before adding/subtracting. /// fn take_and_scale(mut self, new_scale: i64) -> BigDecimal { self.set_scale(new_scale); self } /// Change to requested scale by multiplying or truncating fn set_scale(&mut self, new_scale: i64) { if self.int_val.is_zero() { self.scale = new_scale; return; } match diff(new_scale, self.scale) { (Ordering::Greater, scale_diff) => { self.scale = new_scale; if scale_diff < 20 { self.int_val *= ten_to_the_u64(scale_diff as u8); } else { self.int_val *= ten_to_the(scale_diff); } } (Ordering::Less, scale_diff) => { self.scale = new_scale; if scale_diff < 20 { self.int_val /= ten_to_the_u64(scale_diff as u8); } else { self.int_val /= ten_to_the(scale_diff); } } (Ordering::Equal, _) => {} } } /// set scale only if new_scale is greater than current pub(crate) fn extend_scale_to(&mut self, new_scale: i64) { if new_scale > self.scale { self.set_scale(new_scale) } } /// Take and return bigdecimal with the given sign /// /// The Sign value `NoSign` is ignored: only use Plus & Minus /// pub(crate) fn take_with_sign(self, sign: Sign) -> BigDecimal { let BigDecimal { scale, mut int_val } = self; if int_val.sign() != sign && sign != Sign::NoSign { int_val = int_val.neg(); } BigDecimal { int_val: int_val, scale: scale, } } /// Return a new BigDecimal object with precision set to new value /// /// ``` /// # use bigdecimal::*; /// /// let n: BigDecimal = "129.41675".parse().unwrap(); /// /// assert_eq!(n.with_prec(2), "130".parse::().unwrap()); /// /// let n_p12 = n.with_prec(12); /// let (i, scale) = n_p12.as_bigint_and_exponent(); /// assert_eq!(n_p12, "129.416750000".parse::().unwrap()); /// assert_eq!(i, 129416750000_u64.into()); /// assert_eq!(scale, 9); /// ``` pub fn with_prec(&self, prec: u64) -> BigDecimal { let digits = self.digits(); match digits.cmp(&prec) { Ordering::Greater => { 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, } } Ordering::Less => { let diff = prec - digits; BigDecimal { int_val: &self.int_val * ten_to_the(diff), scale: self.scale + diff as i64, } } Ordering::Equal => self.clone(), } } /// Return this BigDecimal with the given precision, rounding if needed #[cfg(rustc_1_46)] // Option::zip #[allow(clippy::incompatible_msrv)] pub fn with_precision_round( &self, prec: stdlib::num::NonZeroU64, round: RoundingMode, ) -> BigDecimal { let digit_count = self.digits(); let new_prec = prec.get().to_i64(); let new_scale = new_prec .zip(digit_count.to_i64()) .and_then(|(new_prec, old_prec)| new_prec.checked_sub(old_prec)) .and_then(|prec_diff| self.scale.checked_add(prec_diff)) .expect("precision overflow"); self.with_scale_round(new_scale, round) } #[cfg(not(rustc_1_46))] pub fn with_precision_round( &self, prec: stdlib::num::NonZeroU64, round: RoundingMode, ) -> BigDecimal { let new_scale = self.digits().to_i64().and_then( |old_prec| { prec.get().to_i64().and_then( |new_prec| { new_prec.checked_sub(old_prec) })}) .and_then(|prec_diff| self.scale.checked_add(prec_diff)) .expect("precision overflow"); self.with_scale_round(new_scale, round) } /// Return the sign of the `BigDecimal` as `num::bigint::Sign`. /// /// ``` /// # use bigdecimal::{BigDecimal, num_bigint::Sign}; /// /// fn sign_of(src: &str) -> Sign { /// let n: BigDecimal = src.parse().unwrap(); /// n.sign() /// } /// /// assert_eq!(sign_of("-1"), Sign::Minus); /// assert_eq!(sign_of("0"), Sign::NoSign); /// assert_eq!(sign_of("1"), 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 /// /// ``` /// use bigdecimal::{BigDecimal, num_bigint::BigInt}; /// /// let n: BigDecimal = "1.23456".parse().unwrap(); /// let expected = ("123456".parse::().unwrap(), 5); /// assert_eq!(n.as_bigint_and_exponent(), expected); /// ``` #[inline] pub fn as_bigint_and_exponent(&self) -> (BigInt, i64) { (self.int_val.clone(), self.scale) } /// Take BigDecimal and split into `num::BigInt` of digits, and the scale /// /// Scale is number of digits after the decimal point, can be negative. /// pub fn into_bigint_and_scale(self) -> (BigInt, i64) { (self.int_val, self.scale) } /// Return digits as borrowed Cow of integer digits, and its scale /// /// Scale is number of digits after the decimal point, can be negative. /// pub fn as_bigint_and_scale(&self) -> (Cow<'_, BigInt>, i64) { let cow_int = Cow::Borrowed(&self.int_val); (cow_int, self.scale) } /// Convert into the internal big integer value and an exponent. Note that a positive /// exponent indicates a negative power of 10. /// /// # Examples /// /// ``` /// use bigdecimal::{BigDecimal, num_bigint::BigInt}; /// /// let n: BigDecimal = "1.23456".parse().unwrap(); /// let expected = ("123456".parse::().unwrap(), 5); /// assert_eq!(n.into_bigint_and_exponent(), expected); /// ``` #[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 /// /// ``` /// # use bigdecimal::BigDecimal; /// let n: BigDecimal = "123.45".parse().unwrap(); /// assert_eq!(n.abs(), "123.45".parse::().unwrap()); /// /// let n: BigDecimal = "-123.45".parse().unwrap(); /// assert_eq!(n.abs(), "123.45".parse::().unwrap()); /// ``` #[inline] pub fn abs(&self) -> BigDecimal { BigDecimal { int_val: self.int_val.abs(), scale: self.scale, } } /// Multiply decimal by 2 (efficiently) /// /// ``` /// # use bigdecimal::BigDecimal; /// let n: BigDecimal = "123.45".parse().unwrap(); /// assert_eq!(n.double(), "246.90".parse::().unwrap()); /// ``` pub fn double(&self) -> BigDecimal { if self.is_zero() { self.clone() } else { BigDecimal { int_val: self.int_val.clone() * 2, scale: self.scale, } } } /// Divide decimal by 2 (efficiently) /// /// *Note*: If the last digit in the decimal is odd, the precision /// will increase by 1 /// /// ``` /// # use bigdecimal::BigDecimal; /// let n: BigDecimal = "123.45".parse().unwrap(); /// assert_eq!(n.half(), "61.725".parse::().unwrap()); /// ``` #[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, } } } /// Square a decimal: *x²* /// /// No rounding or truncating of digits; this is the full result /// of the squaring operation. /// /// *Note*: doubles the scale of bigdecimal, which might lead to /// accidental exponential-complexity if used in a loop. /// /// ``` /// # use bigdecimal::BigDecimal; /// let n: BigDecimal = "1.1156024145937225657484".parse().unwrap(); /// assert_eq!(n.square(), "1.24456874744734405154288399835406316085210256".parse::().unwrap()); /// /// let n: BigDecimal = "-9.238597585E+84".parse::().unwrap(); /// assert_eq!(n.square(), "8.5351685337567832225E+169".parse::().unwrap()); /// ``` pub fn square(&self) -> BigDecimal { if self.is_zero() || self.is_one_quickcheck() == Some(true) { self.clone() } else { BigDecimal { int_val: self.int_val.clone() * &self.int_val, scale: self.scale * 2, } } } /// Cube a decimal: *x³* /// /// No rounding or truncating of digits; this is the full result /// of the cubing operation. /// /// *Note*: triples the scale of bigdecimal, which might lead to /// accidental exponential-complexity if used in a loop. /// /// ``` /// # use bigdecimal::BigDecimal; /// let n: BigDecimal = "1.1156024145937225657484".parse().unwrap(); /// assert_eq!(n.cube(), "1.388443899780141911774491376394890472130000455312878627147979955904".parse::().unwrap()); /// /// let n: BigDecimal = "-9.238597585E+84".parse().unwrap(); /// assert_eq!(n.cube(), "-7.88529874035334084567570176625E+254".parse::().unwrap()); /// ``` pub fn cube(&self) -> BigDecimal { if self.is_zero() || self.is_one_quickcheck() == Some(true) { self.clone() } else { BigDecimal { int_val: self.int_val.clone() * &self.int_val * &self.int_val, scale: self.scale * 3, } } } /// Raises the number to an integer power /// /// Uses default-precision, set from build time environment variable //// `RUST_BIGDECIMAL_DEFAULT_PRECISION` (defaults to 100) /// /// ``` /// # use bigdecimal::BigDecimal; /// let n: BigDecimal = 2.into(); /// assert_eq!(n.powi(3000000000), "9.816204233623505350831385407878283564899139328691307267002649220552261820356883420275966921502700387e903089986".parse::().unwrap()); /// ``` #[inline] pub fn powi(&self, exp: i64) -> BigDecimal { self.powi_with_context(exp, &Context::default()) } /// Raises the number to an integer power, using context for precision and rounding /// #[inline] pub fn powi_with_context(&self, exp: i64, ctx: &Context) -> BigDecimal { if self.is_zero() || self.is_one() { return self.clone(); } arithmetic::pow::impl_powi_with_context(self.to_ref(), exp, ctx) } /// Take the square root of the number /// /// Uses default-precision, set from build time environment variable //// `RUST_BIGDECIMAL_DEFAULT_PRECISION` (defaults to 100) /// /// If the value is < 0, None is returned /// /// ``` /// # use bigdecimal::BigDecimal; /// let n: BigDecimal = "1.1156024145937225657484".parse().unwrap(); /// assert_eq!(n.sqrt().unwrap(), "1.056220817156016181190291268045893004363809142172289919023269377496528394924695970851558013658193913".parse::().unwrap()); /// /// let n: BigDecimal = "-9.238597585E+84".parse().unwrap(); /// assert_eq!(n.sqrt(), None); /// ``` #[inline] pub fn sqrt(&self) -> Option { self.sqrt_with_context(&Context::default()) } /// Take the square root of the number, using context for precision and rounding /// pub fn sqrt_with_context(&self, ctx: &Context) -> Option { if self.is_zero() || self.is_one_quickcheck() == Some(true) { return Some(self.clone()); } if self.is_negative() { return None; } let uint = self.int_val.magnitude(); let result = arithmetic::sqrt::impl_sqrt(uint, self.scale, ctx); Some(result) } /// Take the cube root of the number, using default context /// #[inline] pub fn cbrt(&self) -> BigDecimal { self.cbrt_with_context(&Context::default()) } /// Take cube root of self, using properties of context pub fn cbrt_with_context(&self, ctx: &Context) -> BigDecimal { if self.is_zero() || self.is_one_quickcheck() == Some(true) { return self.clone(); } arithmetic::cbrt::impl_cbrt_int_scale(&self.int_val, self.scale, ctx) } /// Compute the reciprical of the number: x-1 #[inline] pub fn inverse(&self) -> BigDecimal { self.inverse_with_context(&Context::default()) } /// Return inverse of self, rounding with ctx pub fn inverse_with_context(&self, ctx: &Context) -> BigDecimal { self.to_ref().inverse_with_context(ctx) } /// Multiply by rhs, limiting precision using context pub fn mul_with_context<'a, T: Into>>(&'a self, rhs: T, ctx: &Context) -> BigDecimal { ctx.multiply(self, rhs) } /// Return given number rounded to 'round_digits' precision after the /// decimal point, using default rounding mode /// /// Default rounding mode is `HalfEven`, but can be configured at compile-time /// by the environment variable: `RUST_BIGDECIMAL_DEFAULT_ROUNDING_MODE` /// (or by patching _build.rs_ ) /// pub fn round(&self, round_digits: i64) -> BigDecimal { self.with_scale_round(round_digits, Context::default().rounding_mode()) } /// 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() } } /// Try to determine if decimal is 1.0, without allocating pub fn is_one_quickcheck(&self) -> Option { self.to_ref().is_one_quickcheck() } /// Evaluate the natural-exponential function ex /// #[inline] pub fn exp(&self) -> BigDecimal { if self.is_zero() { return BigDecimal::one(); } let target_precision = DEFAULT_PRECISION; 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(target_precision + 5); if prev_result == trimmed_result { return trimmed_result.with_prec(target_precision); } prev_result = trimmed_result; } unreachable!("Loop did not converge") } #[must_use] pub fn normalized(&self) -> BigDecimal { if self == &BigDecimal::zero() { return BigDecimal::zero(); } let (sign, mut digits) = self.int_val.to_radix_be(10); let trailing_count = digits.iter().rev().take_while(|i| **i == 0).count(); let trunc_to = digits.len() - trailing_count; digits.truncate(trunc_to); let int_val = BigInt::from_radix_be(sign, &digits, 10).unwrap(); let scale = self.scale - trailing_count as i64; BigDecimal::new(int_val, scale) } ////////////////////////// // Formatting methods /// Create string of decimal in standard decimal notation. /// /// Unlike standard formatter, this never prints the number in /// scientific notation. /// /// # Panics /// If the magnitude of the exponent is _very_ large, this may /// cause out-of-memory errors, or overflowing panics. /// /// # Examples /// ``` /// # use bigdecimal::BigDecimal; /// let n: BigDecimal = "123.45678".parse().unwrap(); /// assert_eq!(&n.to_plain_string(), "123.45678"); /// /// let n: BigDecimal = "1e-10".parse().unwrap(); /// assert_eq!(&n.to_plain_string(), "0.0000000001"); /// ``` pub fn to_plain_string(&self) -> String { let mut output = String::new(); self.write_plain_string(&mut output).expect("Could not write to string"); output } /// Write decimal value in decimal notation to the writer object. /// /// # Panics /// If the exponent is very large or very small, the number of /// this will print that many trailing or leading zeros. /// If exabytes, this will likely panic. /// pub fn write_plain_string(&self, wtr: &mut W) -> fmt::Result { write!(wtr, "{}", impl_fmt::FullScaleFormatter(self.to_ref())) } /// Create string of this bigdecimal in scientific notation /// /// ``` /// # use bigdecimal::BigDecimal; /// let n = BigDecimal::from(12345678); /// assert_eq!(&n.to_scientific_notation(), "1.2345678e7"); /// ``` pub fn to_scientific_notation(&self) -> String { let mut output = String::new(); self.write_scientific_notation(&mut output).expect("Could not write to string"); output } /// Write bigdecimal in scientific notation to writer `w` pub fn write_scientific_notation(&self, w: &mut W) -> fmt::Result { impl_fmt::write_scientific_notation(self, w) } /// Create string of this bigdecimal in engineering notation /// /// Engineering notation is scientific notation with the exponent /// coerced to a multiple of three /// /// ``` /// # use bigdecimal::BigDecimal; /// let n = BigDecimal::from(12345678); /// assert_eq!(&n.to_engineering_notation(), "12.345678e6"); /// ``` /// pub fn to_engineering_notation(&self) -> String { let mut output = String::new(); self.write_engineering_notation(&mut output).expect("Could not write to string"); output } /// Write bigdecimal in engineering notation to writer `w` pub fn write_engineering_notation(&self, w: &mut W) -> fmt::Result { impl_fmt::write_engineering_notation(self, w) } } #[derive(Debug, PartialEq, Clone)] 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), } } } #[cfg(feature = "std")] impl std::error::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) } } #[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); 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 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 { fn one() -> BigDecimal { BigDecimal::new(BigInt::one(), 0) } fn is_one(&self) -> bool { self.to_ref().is_one() } } 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)); } return BigDecimal::new(quotient, scale); } 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) } } /// Immutable big-decimal, referencing a borrowed buffer of digits /// /// The non-digit information like `scale` and `sign` may be changed /// on these objects, which otherwise would require cloning the full /// digit buffer in the BigDecimal. /// /// Built from full `BigDecimal` object using the `to_ref()` method. /// `BigDecimal` not implement `AsRef`, so we will reserve the method /// `as_ref()` for a later time. /// /// May be transformed into full BigDecimal object using the `to_owned()` /// method. /// This clones the bigdecimal digits. /// /// BigDecimalRef (or `Into`) should be preferred over /// using `&BigDecimal` for library functions that need an immutable /// reference to a bigdecimal, as it may be much more efficient. /// /// NOTE: Using `&BigDecimalRef` is redundant, and not recommended. /// /// ## Examples /// /// ``` /// # use bigdecimal::*; use std::ops::Neg; /// fn add_one<'a, N: Into>>(n: N) -> BigDecimal { /// n.into() + 1 /// } /// /// let n: BigDecimal = "123.456".parse().unwrap(); /// /// // call via "standard" reference (implements Into) /// let m = add_one(&n); /// assert_eq!(m, "124.456".parse::().unwrap()); /// /// // call by negating the reference (fast: no-digit cloning involved) /// let m = add_one(n.to_ref().neg()); /// assert_eq!(m, "-122.456".parse::().unwrap()); /// ``` /// #[derive(Clone, Copy, Debug, Eq)] pub struct BigDecimalRef<'a> { sign: Sign, digits: &'a BigUint, scale: i64, } impl<'a> BigDecimalRef<'a> { /// Clone digits to make this reference a full BigDecimal object pub fn to_owned(&self) -> BigDecimal { BigDecimal { scale: self.scale, int_val: BigInt::from_biguint(self.sign, self.digits.clone()), } } /// Clone digits, returning BigDecimal with given scale /// /// ``` /// # use bigdecimal::*; /// /// let n: BigDecimal = "123.45678".parse().unwrap(); /// let r = n.to_ref(); /// assert_eq!(r.to_owned_with_scale(5), n.clone()); /// assert_eq!(r.to_owned_with_scale(0), "123".parse::().unwrap()); /// assert_eq!(r.to_owned_with_scale(-1), "12e1".parse::().unwrap()); /// /// let x = r.to_owned_with_scale(8); /// assert_eq!(&x, &n); /// assert_eq!(x.fractional_digit_count(), 8); /// ``` pub fn to_owned_with_scale(&self, scale: i64) -> BigDecimal { use stdlib::cmp::Ordering::*; let digits = match arithmetic::diff(self.scale, scale) { (Equal, _) => self.digits.clone(), (Less, scale_diff) => { if scale_diff < 20 { self.digits * ten_to_the_u64(scale_diff as u8) } else { self.digits * ten_to_the_uint(scale_diff) } } (Greater, scale_diff) => { if scale_diff < 20 { self.digits / ten_to_the_u64(scale_diff as u8) } else { self.digits / ten_to_the_uint(scale_diff) } } }; BigDecimal { scale: scale, int_val: BigInt::from_biguint(self.sign, digits), } } /// Borrow digits as Cow pub(crate) fn to_cow_biguint_and_scale(&self) -> (Cow<'_, BigUint>, i64) { let cow_int = Cow::Borrowed(self.digits); (cow_int, self.scale) } /// Sign of decimal pub fn sign(&self) -> Sign { self.sign } /// Return number of digits 'right' of the decimal point /// (including leading zeros) pub fn fractional_digit_count(&self) -> i64 { self.scale } /// Count total number of decimal digits pub fn count_digits(&self) -> u64 { count_decimal_digits_uint(self.digits) } /// Position of most significant digit of this decimal /// /// Equivalent to the exponent when written in scientific notation, /// or `⌊log10(n)⌋`. /// /// The order of magnitude of 0 is 0. /// pub fn order_of_magnitude(&self) -> i64 { if self.is_zero() { return 0; } self.count_digits() as i64 - self.scale - 1 } /// Return the number of trailing zeros in the referenced integer #[allow(dead_code)] fn count_trailing_zeroes(&self) -> usize { if self.digits.is_zero() || self.digits.is_odd() { return 0; } let digit_pairs = self.digits.to_radix_le(100); let loc = digit_pairs.iter().position(|&d| d != 0).unwrap_or(0); 2 * loc + usize::from(digit_pairs[loc] % 10 == 0) } /// Split into components pub(crate) fn as_parts(&self) -> (Sign, i64, &BigUint) { (self.sign, self.scale, self.digits) } /// Take absolute value of the decimal (non-negative sign) pub fn abs(&self) -> Self { Self { sign: self.sign * self.sign, digits: self.digits, scale: self.scale, } } /// Create BigDecimal from this reference, rounding to precision and /// with rounding-mode of the given context /// pub fn round_with_context(&self, ctx: &Context) -> BigDecimal { ctx.round_decimal_ref(*self) } /// Multiply another decimal-ref, limiting the precision using Context pub fn mul_with_context>>( self, rhs: T, ctx: &Context ) -> BigDecimal { ctx.multiply(self, rhs) } /// Compute the reciprical of the number: x-1 using the Context pub fn inverse(&self) -> BigDecimal { self.inverse_with_context(&Context::default()) } /// Return inverse of self, rounding with ctx pub fn inverse_with_context(&self, ctx: &Context) -> BigDecimal { if self.is_zero() { return self.to_owned(); } let result = arithmetic::inverse::impl_inverse_uint_scale( self.digits, self.scale, ctx ); // always copy sign result.take_with_sign(self.sign) } /// Take square root of this number pub fn sqrt_with_context(&self, ctx: &Context) -> Option { use Sign::*; let (sign, scale, uint) = self.as_parts(); match sign { Minus => None, NoSign => Some(Zero::zero()), Plus => Some(arithmetic::sqrt::impl_sqrt(uint, scale, ctx)), } } /// Take square root of absolute-value of the number pub fn sqrt_abs_with_context(&self, ctx: &Context) -> BigDecimal { let (_, scale, uint) = self.as_parts(); arithmetic::sqrt::impl_sqrt(uint, scale, ctx) } /// Take square root, copying sign of the initial decimal pub fn sqrt_copysign_with_context(&self, ctx: &Context) -> BigDecimal { let (sign, scale, uint) = self.as_parts(); let mut result = arithmetic::sqrt::impl_sqrt(uint, scale, ctx); if sign == Sign::Minus { result.int_val = result.int_val.neg(); } result } /// Return if the referenced decimal is zero pub fn is_zero(&self) -> bool { self.digits.is_zero() } /// Return if the referenced decimal is one pub fn is_one(&self) -> bool { if let Some(is_one) = self.is_one_quickcheck() { return is_one; } // full comparison of {int} == 10^{scale} // (because actual value is {int} * 10^{-scale}) self.digits == &ten_to_the_uint(self.scale as u64) } /// A check if this decimal is equal to one for purposes of optimization /// Returns None if the computation would be expensive pub fn is_one_quickcheck(&self) -> Option { if self.sign() != Sign::Plus { return Some(false); } self.is_abs_one_quickcheck() } /// Check if this decimal is equal to ±1, return None if it would /// require allocating to fully check pub(crate) fn is_abs_one_quickcheck(&self) -> Option { if self.scale < 0 { return Some(false); } let value = self.digits; // special case for very small scales: 1 == 10e-1, 100e-2, etc match (self.scale, value.to_u16()) { (0, Some(n)) => return Some(n == 1), (1, Some(n)) => return Some(n == 10), (2, Some(n)) => return Some(n == 100), (3, Some(n)) => return Some(n == 1000), (4, Some(n)) => return Some(n == 10000), // small scale but large integer: certainly not '1' (s, None) if s < 5 => return Some(false), _ => {} } // scale required to represent a value of 10^{pow} for // an int_val with this number of bits, quickly filter // any integers with wrong number of digits for the scale let approx_digits = (value.bits() as f64 * LOG10_2).floor() as i64; if approx_digits != self.scale { return Some(false); } // small value optimizations: compare with 10^{scale} using primitives // // TODO: benchmark to determine if is it worth separating u64 and u128 // match self.scale.to_u32() { Some(scale) if scale <= 19 => { let ten_pow_scale = 10u64.pow(scale); return value.to_u64().map(|n| n == ten_pow_scale).or(Some(false)); } Some(scale) if scale <= 38 => { let ten_pow_scale = 10u128.pow(scale); return value.to_u128().map(|n| n == ten_pow_scale).or(Some(false)); } _ => {} } // Indicate the calculation of '1.0' at this scale // is probably more expensive than the operation // being avoided None } /// Clone this value into dest pub fn clone_into(&self, dest: &mut BigDecimal) { dest.int_val = num_bigint::BigInt::from_biguint(self.sign, self.digits.clone()); dest.scale = self.scale; } } impl<'a> From<&'a BigDecimal> for BigDecimalRef<'a> { fn from(n: &'a BigDecimal) -> Self { let sign = n.int_val.sign(); let mag = n.int_val.magnitude(); Self { sign: sign, digits: mag, scale: n.scale, } } } impl<'a> From<&'a BigInt> for BigDecimalRef<'a> { fn from(n: &'a BigInt) -> Self { Self { sign: n.sign(), digits: n.magnitude(), scale: 0, } } } /// pair i64 'scale' with some other value #[derive(Clone, Copy, Default)] struct WithScale { pub value: T, pub scale: i64, } impl fmt::Debug for WithScale { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "(scale={} {:?})", self.scale, self.value) } } impl From<(T, i64)> for WithScale { fn from(pair: (T, i64)) -> Self { Self { value: pair.0, scale: pair.1 } } } impl<'a> From> for BigDecimalRef<'a> { fn from(obj: WithScale<&'a BigInt>) -> Self { Self { scale: obj.scale, sign: obj.value.sign(), digits: obj.value.magnitude(), } } } impl<'a> From> for BigDecimalRef<'a> { fn from(obj: WithScale<&'a BigUint>) -> Self { Self { scale: obj.scale, sign: Sign::Plus, digits: obj.value, } } } impl WithScale<&T> { fn is_zero(&self) -> bool { self.value.is_zero() } } #[rustfmt::skip] #[cfg(test)] #[allow(non_snake_case)] mod bigdecimal_tests { use super::*; use num_traits::{ToPrimitive, FromPrimitive, Signed, Zero, One}; use num_bigint; use paste::paste; mod from_biguint { use super::*; use num_bigint::BigUint; use num_bigint::Sign; macro_rules! impl_case { ($name:ident; $i:literal; $scale:literal) => { impl_case!($name; $i.into(); $scale; Plus); }; ($name:ident; $i:expr; $scale:literal; $sign:ident) => { #[test] fn $name() { let i: BigUint = $i; let d = BigDecimal::from_biguint(i.clone(), $scale); assert_eq!(d.int_val.magnitude(), &i); assert_eq!(d.scale, $scale); assert_eq!(d.sign(), Sign::$sign); } }; } impl_case!(case_0en3; BigUint::zero(); 3; NoSign); impl_case!(case_30e2; 30u8; -2); impl_case!(case_7446124798en5; 7446124798u128; 5); } #[test] fn test_fractional_digit_count() { // Zero value let vals = BigDecimal::from(0); assert_eq!(vals.fractional_digit_count(), 0); assert_eq!(vals.to_ref().fractional_digit_count(), 0); // Fractional part with trailing zeros let vals = BigDecimal::from_str("1.0").unwrap(); assert_eq!(vals.fractional_digit_count(), 1); assert_eq!(vals.to_ref().fractional_digit_count(), 1); // Fractional part let vals = BigDecimal::from_str("1.23").unwrap(); assert_eq!(vals.fractional_digit_count(), 2); assert_eq!(vals.to_ref().fractional_digit_count(), 2); // shifted to 'left' has negative scale let vals = BigDecimal::from_str("123e5").unwrap(); assert_eq!(vals.fractional_digit_count(), -5); assert_eq!(vals.to_ref().fractional_digit_count(), -5); } #[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_str("2.801000011968426406383514404296875").unwrap(); let sum = vals.iter().sum::(); assert_eq!(expected_sum, sum); } #[test] fn test_sum1() { let vals = vec![ BigDecimal::from_f32(0.1).unwrap(), BigDecimal::from_f32(0.2).unwrap(), ]; let expected_sum = BigDecimal::from_str("0.300000004470348358154296875").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_i128() { let vals = vec![ ("170141183460469231731687303715884105727", 170141183460469231731687303715884105727), ("-170141183460469231731687303715884105728", -170141183460469231731687303715884105728), ("12.34", 12), ("3.14", 3), ("-123.90", -123), ("50", 50), ("0.001", 0), ]; for (s, ans) in vals { let calculated = BigDecimal::from_str(s).unwrap().to_i128(); assert_eq!(Some(ans), calculated); } } #[test] fn test_to_u128() { let vals = vec![ ("340282366920938463463374607431768211455", 340282366920938463463374607431768211455), ("12.34", 12), ("3.14", 3), ("50", 50), ("0.001", 0), ]; for (s, ans) in vals { let calculated = BigDecimal::from_str(s).unwrap().to_u128().unwrap(); assert_eq!(ans, calculated); } } #[test] fn test_from_i8() { let vals = vec![ ("0", 0), ("1", 1), ("12", 12), ("-13", -13), ("111", 111), ("-128", i8::MIN), ("127", 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![ ("0.0", 0.0), ("1.0", 1.0), ("0.5", 0.5), ("0.25", 0.25), ("50.", 50.0), ("50000", 50000.), ("0.001000000047497451305389404296875", 0.001), ("12.340000152587890625", 12.34), ("0.15625", 0.15625), ("3.1415927410125732421875", stdlib::f32::consts::PI), ("31415.927734375", stdlib::f32::consts::PI * 10000.0), ("94247.78125", stdlib::f32::consts::PI * 30000.0), ("1048576", 1048576.), ]; for (s, n) in vals { let expected = BigDecimal::from_str(s).unwrap(); let value = BigDecimal::from_f32(n).unwrap(); assert_eq!(expected, value); } } #[test] fn test_from_f64() { let vals = vec![ ("1.0", 1.0f64), ("0.5", 0.5), ("50", 50.), ("50000", 50000.), ("0.001000000000000000020816681711721685132943093776702880859375", 0.001), ("0.25", 0.25), ("12.339999999999999857891452847979962825775146484375", 12.34), ("0.15625", 5.0 * 0.03125), ("0.333333333333333314829616256247390992939472198486328125", 1.0 / 3.0), ("3.141592653589793115997963468544185161590576171875", stdlib::f64::consts::PI), ("31415.926535897931898944079875946044921875", stdlib::f64::consts::PI * 10000.0f64), ("94247.779607693795696832239627838134765625", stdlib::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_nan_float() { assert!(BigDecimal::try_from(f32::NAN).is_err()); assert!(BigDecimal::try_from(f64::NAN).is_err()); } mod equals { use super::*; macro_rules! impl_case { ($name:ident: $input_a:literal == $input_b:literal) => { #[test] fn $name() { let a: BigDecimal = $input_a.parse().unwrap(); let b: BigDecimal = $input_b.parse().unwrap(); assert_eq!(&a, &b); assert_eq!(a.clone(), b.clone()); } }; ($name:ident: $input_a:literal != $input_b:literal) => { #[test] fn $name() { let a: BigDecimal = $input_a.parse().unwrap(); let b: BigDecimal = $input_b.parse().unwrap(); assert_ne!(&a, &b); assert_ne!(a.clone(), b.clone()); } }; } impl_case!(case_2: "2" == ".2e1"); impl_case!(case_0e1: "0e1" == "0.0"); impl_case!(case_n0: "-0" == "0.0"); impl_case!(case_n901d3: "-901.3" == "-0.901300e+3"); impl_case!(case_n0901300en3: "-901.3" == "-0901300e-3"); impl_case!(case_2123121e1231: "2123121e1231" == "212.3121e1235"); impl_case!(case_ne_2: "2" != ".2e2"); impl_case!(case_ne_1e45: "1e45" != "1e-900"); impl_case!(case_ne_1e900: "1e+900" != "1e-900"); } #[test] fn test_hash_equal() { use stdlib::DefaultHasher; use stdlib::hash::{Hash, Hasher}; 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 stdlib::DefaultHasher; use stdlib::hash::{Hash, Hasher}; 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 stdlib::DefaultHasher; use stdlib::hash::{Hash, Hasher}; 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), ("-1", 1), ("-6", 1), ("-10", 2), ("-999999999999999999999999", 24), ]; 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_round() { let test_cases = vec![ ("1.45", 1, "1.4"), ("1.444445", 1, "1.4"), ("1.44", 1, "1.4"), ("0.444", 2, "0.44"), ("4.5", 0, "4"), ("4.05", 1, "4.0"), ("4.050", 1, "4.0"), ("4.15", 1, "4.2"), ("0.0045", 2, "0.00"), ("5.5", -1, "10"), ("-1.555", 2, "-1.56"), ("-1.555", 99, "-1.555"), ("5.5", 0, "6"), ("-1", -1, "0"), ("5", -1, "0"), ("44", -1, "40"), ("44", -99, "0"), ("44", 99, "44"), ("1.4499999999", -1, "0"), ("1.4499999999", 0, "1"), ("1.4499999999", 1, "1.4"), ("1.4499999999", 2, "1.45"), ("1.4499999999", 3, "1.450"), ("1.4499999999", 4, "1.4500"), ("1.4499999999", 10, "1.4499999999"), ("1.4499999999", 15, "1.449999999900000"), ("-1.4499999999", 1, "-1.4"), ("1.449999999", 1, "1.4"), ("-9999.444455556666", 10, "-9999.4444555567"), ("-12345678987654321.123456789", 8, "-12345678987654321.12345679"), ("0.33333333333333333333333333333333333333333333333333333333333333333333333333333333333333", 0, "0"), ("0.1165085714285714285714285714285714285714", 0, "0"), ("0.1165085714285714285714285714285714285714", 2, "0.12"), ("0.1165085714285714285714285714285714285714", 5, "0.11651"), ("0.1165085714285714285714285714285714285714", 8, "0.11650857"), ("-1.5", 0, "-2"), ("-1.2", 0, "-1"), ("-0.68", 0, "-1"), ("-0.5", 0, "0"), ("-0.49", 0, "0"), ]; for &(x, digits, y) in test_cases.iter() { let a = BigDecimal::from_str(x).unwrap(); let b = BigDecimal::from_str(y).unwrap(); let rounded = a.round(digits); assert_eq!(rounded, b); } } #[test] fn round_large_number() { use super::BigDecimal; let z = BigDecimal::from_str("3.4613133327063255443352353815722045816611958409944513040035462804475524").unwrap(); let expected = BigDecimal::from_str("11.9806899871705702711783103817684242408972124568942276285200973527647213").unwrap(); let zsq = &z*&z; let zsq = zsq.round(70); debug_assert_eq!(zsq, expected); } #[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); } } mod double { use super::*; include!("lib.tests.double.rs"); } #[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); } } mod to_plain_string { use super::*; macro_rules! impl_test { ($name:ident: $input:literal => $expected:literal) => { #[test] fn $name() { let n: BigDecimal = $input.parse().unwrap(); let s = n.to_plain_string(); assert_eq!(&s, $expected); } }; } impl_test!(case_zero: "0" => "0"); impl_test!(case_1en18: "1e-18" => "0.000000000000000001"); impl_test!(case_n72e4: "-72e4" => "-720000"); impl_test!(case_95517338e30: "95517338e30" => "95517338000000000000000000000000000000"); impl_test!(case_29478en30: "29478e-30" => "0.000000000000000000000000029478"); impl_test!(case_30740d4897: "30740.4897" => "30740.4897"); } #[test] fn test_signed() { 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()); } mod normalize { use super::*; macro_rules! impl_case { ( $name:ident: ($i:literal, $s:literal) => ($e_int_val:literal, $e_scale:literal) ) => { #[test] fn $name() { let d = BigDecimal::new($i.into(), $s); let n = d.normalized(); assert_eq!(n.int_val, $e_int_val.into()); assert_eq!(n.scale, $e_scale); } } } impl_case!(case_0e3: (0, -3) => (0, 0)); impl_case!(case_0en50: (0, 50) => (0, 0)); impl_case!(case_10en2: (10, 2) => (1, 1)); impl_case!(case_11en2: (11, 2) => (11, 2)); impl_case!(case_132400en4: (132400, 4) => (1324, 2)); impl_case!(case_1_900_000en3: (1_900_000, 3) => (19, -2)); impl_case!(case_834700e4: (834700, -4) => (8347, -6)); impl_case!(case_n834700e4: (-9900, 2) => (-99, 0)); } #[test] fn test_from_i128() { let value = BigDecimal::from_i128(-368934881474191032320).unwrap(); let expected = BigDecimal::from_str("-368934881474191032320").unwrap(); assert_eq!(value, expected); } #[test] fn test_from_u128() { let value = BigDecimal::from_u128(668934881474191032320).unwrap(); let expected = BigDecimal::from_str("668934881474191032320").unwrap(); assert_eq!(value, expected); } #[test] fn test_parse_roundtrip() { let vals = vec![ "1.0", "0.5", "50", "50000", "0.001000000000000000020816681711721685132943093776702880859375", "0.25", "12.339999999999999857891452847979962825775146484375", "0.15625", "0.333333333333333314829616256247390992939472198486328125", "3.141592653589793115997963468544185161590576171875", "31415.926535897931898944079875946044921875", "94247.779607693795696832239627838134765625", "1331.107", "1.0", "2e1", "0.00123", "-123", "-1230", "12.3", "123e-1", "1.23e+1", "1.23E+3", "1.23E-8", "-1.23E-10", "123_", "31_862_140.830_686_979", "-1_1.2_2", "999.521_939", "679.35_84_03E-2", "271576662.__E4", // Large decimals with small text representations "1E10000", "1E-10000", "1.129387461293874682630000000487984723987459E10000", "11293874612938746826340000000087984723987459E10000", ]; for s in vals { let expected = BigDecimal::from_str(s).unwrap(); let display = format!("{}", expected); let parsed = BigDecimal::from_str(&display).unwrap(); assert_eq!(expected, parsed, "[{}] didn't round trip through [{}]", s, display); } } include!("lib.tests.rs"); mod ops { use super::*; include!("lib.tests.ops.div.rs"); } } #[cfg(test)] #[allow(non_snake_case)] mod test_with_scale_round { use super::*; use paste::paste; include!("lib.tests.with_scale_round.rs"); } #[cfg(all(test, property_tests))] extern crate proptest; #[cfg(all(test, property_tests))] mod proptests { use super::*; use paste::paste; use proptest::*; include!("lib.tests.property-tests.rs"); } bigdecimal-0.4.10/src/lib.tests.double.rs000064400000000000000000000016071046102023000163070ustar 00000000000000// Test BigDecimal::double macro_rules! impl_case { ($name:ident : $a:literal => $ex:literal ) => { paste! { #[test] fn $name() { let value = BigDecimal::from_str($a).unwrap(); let expected = BigDecimal::from_str($ex).unwrap(); let result = value.double(); assert_eq!(result, expected); assert_eq!(result.int_val, expected.int_val); assert_eq!(result.scale, expected.scale); } } }; } impl_case!(case_zero : "0" => "0"); impl_case!(case_1 : "1" => "2"); impl_case!(case_100Em2 : "1.00" => "2.00"); impl_case!(case_150Em2 : "1.50" => "3.00"); impl_case!(case_neg150Em2 : "-1.50" => "-3.00"); impl_case!(case_32909E4 : "32909E4" => "6.5818E+8"); impl_case!(case_1_1156024145937225657484 : "1.1156024145937225657484" => "2.2312048291874451314968"); bigdecimal-0.4.10/src/lib.tests.ops.div.rs000064400000000000000000000137601046102023000164220ustar 00000000000000 mod impl_div { use super::*; macro_rules! impl_case { ($name:ident: $numerator:literal / $denominator:literal => $quotient:literal) => { #[test] fn $name() { let a: BigDecimal = $numerator.parse().unwrap(); let b: BigDecimal = $denominator.parse().unwrap(); let c: BigDecimal = $quotient.parse().unwrap(); let q = a.clone() / b.clone(); assert_eq!(q, c); assert_eq!(q.scale, c.scale); assert_eq!(a.clone() / &b, c); assert_eq!(&a / b.clone(), c); assert_eq!(&a / &b, c); } }; } impl_case!(zero_over_one: "0" / "1" => "0"); impl_case!(zero_over_ten: "0" / "10" => "0"); impl_case!(two_over_one: "2" / "1" => "2"); impl_case!(div_2e1_one: "2e1" / "1" => "2e1"); impl_case!(div_10_10: "10" / "10" => "1"); impl_case!(div_100_10d0: "100" / "10.0" => "1e1"); impl_case!(div_20d0_200: "20.0" / "200" => "0.1"); impl_case!(div_4_2: "4" / "2" => "2"); impl_case!(div_15_3: "15" / "3" => "5"); impl_case!(div_1_2: "1" / "2" => "0.5"); impl_case!(div_1_2en2: "1" / "2e-2" => "5e1"); impl_case!(div_1_0d2: "1" / "0.2" => "5"); impl_case!(div_1d0_0d02: "1.0" / "0.02" => "5e1"); impl_case!(div_1_0d020: "1" / "0.020" => "5e1"); impl_case!(div_1d0_0d020: "1.0" / "0.020" => "5e1"); impl_case!(div_5d0_4d00: "5.0" / "4.00" => "1.25"); impl_case!(div_5d0_4d000: "5.0" / "4.000" => "1.25"); impl_case!(div_5_4d000: "5" / "4.000" => "1.25"); impl_case!(div_5_4: "5" / "4" => "125e-2"); impl_case!(div_100_5: "100" / "5" => "20"); impl_case!(div_n50_5: "-50" / "5" => "-10"); impl_case!(div_200_n5: "200" / "-5" => "-40."); impl_case!(div_1_3: "1" / "3" => ".3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333"); impl_case!(div_n2_n3: "-2" / "-3" => ".6666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667"); impl_case!(div_n12d34_1d233: "-12.34" / "1.233" => "-10.00811030008110300081103000811030008110300081103000811030008110300081103000811030008110300081103001"); impl_case!(div_125348_352d2283: "125348" / "352.2283" => "355.8714617763535752237966114591019517738921035021887792661748076460636467881768727839301952739175132"); impl_case!(div_22_7: "22" / "7" => "3.142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857143"); #[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() { let x = BigDecimal::from_str("3.14").unwrap(); let _r = x / BigDecimal::zero(); } #[test] fn test_division_by_large_number() { let n = 1u8; let d: BigDecimal = "79437738588056219546528239237352667078".parse().unwrap(); let quotient_n_ref_d = n / &d; let quotient_n_d = n / d.clone(); assert_eq!(quotient_n_ref_d, quotient_n_d); let expected: BigDecimal = "1.258847517281104957975270408416632052090243053529147458917576143852500316808428812104171430669001064E-38".parse().unwrap(); assert_eq!(quotient_n_ref_d, expected); } } #[test] fn divide_by_f32_infinity() { let num: BigDecimal = "123".parse().unwrap(); let quotient = num / f32::INFINITY; assert!(quotient.is_zero()); } #[test] fn divide_by_f32_nan() { let num: BigDecimal = "123".parse().unwrap(); let quotient = num / f32::NAN; assert!(quotient.is_zero()); } #[test] fn divide_by_f64_infinity() { let num: BigDecimal = "123".parse().unwrap(); let quotient = num / f64::INFINITY; assert!(quotient.is_zero()); } #[test] fn divide_by_f64_nan() { let num: BigDecimal = "123".parse().unwrap(); let quotient = num / f64::NAN; assert!(quotient.is_zero()); } macro_rules! impl_case { ($name:ident: num / $denom:literal => $expected:literal) => { #[test] fn $name() { let num = numerator(); let den = $denom; let expected: BigDecimal = $expected.parse().unwrap(); { let quotient = &num / den; assert_eq!("ient, &expected); } let quotient = num / den; assert_eq!(quotient, expected); } }; ($name:ident: $numer:literal / den => $expected:literal) => { #[test] fn $name() { let num = $numer; let den = denominator(); let expected: BigDecimal = $expected.parse().unwrap(); { let quotient = num / &den; assert_eq!("ient, &expected); } let quotient = num / den; assert_eq!(quotient, expected); } } } mod dec123_over_float { use super::*; fn numerator() -> BigDecimal { "123".parse().unwrap() } impl_case!(divide_by_one: num / 1.0 => "123"); impl_case!(divide_by_neg_one: num / -1.0 => "-123"); impl_case!(divide_by_two: num / 2.0 => "61.5"); impl_case!(divide_by_neg_two: num / -2.0 => "-61.5"); impl_case!(divide_by_half: num / 0.25 => "492"); impl_case!(divide_by_0d3: num / 0.3 => "410.0000000000000151730480032104732806385410274753293198491224660103204812897069364682009036747721645"); impl_case!(divide_by_n10d01: num / -10.01 => "-12.28771228771228797395438676755509642184314950109407611037730443717479254091338404424812715057130341"); } mod num_float_over_dec123 { use super::*; fn denominator() -> BigDecimal { "123".parse().unwrap() } impl_case!(num_one: 1.0 / den => "0.008130081300813008130081300813008130081300813008130081300813008130081300813008130081300813008130081301"); impl_case!(num_123: 123.0 / den => "1"); impl_case!(num_676d5: 676.5 / den => "5.5"); } bigdecimal-0.4.10/src/lib.tests.property-tests.rs000064400000000000000000000070211046102023000200550ustar 00000000000000// Property tests to be included by lib.rs (if enabled) mod arithmetic { use super::*; use stdlib::num::NonZeroI128; macro_rules! impl_test { ($t:ty) => { paste! { proptest! { #[test] fn [< add_ref $t >](n: $t, m: i128, e: i8) { let d = BigDecimal::new(m.into(), e as i64); let sum = n + &d; let s1 = &d + n; let s2 = d.clone() + n; prop_assert_eq!(&sum, &s1); prop_assert_eq!(&sum, &s2); let mut s = d; s += n; prop_assert_eq!(sum, s); } #[test] fn [< sub_ $t >](n: $t, m: i128, e: i8) { let d = BigDecimal::new(m.into(), e as i64); let diff_n_d = n - &d; let diff_d_n = d.clone() - n; prop_assert_eq!(&diff_n_d, &diff_d_n.neg()); let mut a = d.clone(); a -= n; prop_assert_eq!(&a, &diff_n_d.neg()); } #[test] fn [< mul_ $t >](n: $t, m: i128, e: i8) { let d = BigDecimal::new(m.into(), e as i64); let prod_n_d = n * &d; let prod_d_n = d.clone() * n; prop_assert_eq!(&prod_n_d, &prod_d_n); let mut r = d.clone(); r *= n; prop_assert_eq!(&prod_n_d, &r); let r = d.neg() * n; prop_assert_eq!(prod_n_d.neg(), r); } #[test] fn [< div_ $t >](n: $t, m: NonZeroI128, e: i8) { let d = BigDecimal::new(m.get().into(), e as i64); let quotient_n_ref_d = n / &d; let quotient_n_d = n / d.clone(); prop_assert_eq!("ient_n_ref_d, "ient_n_d); let prod = quotient_n_d * &d; let diff = n - ∏ prop_assert!(diff.abs() < BigDecimal::new(1.into(), 60)); } } } }; (float-div $t:ty) => { paste! { proptest! { #[test] fn [< div_ $t >](n: $t, m: NonZeroI128, e: i8) { let d = BigDecimal::new(m.get().into(), e as i64); let quotient_n_ref_d = n / &d; let quotient_n_d = n / d.clone(); prop_assert_eq!("ient_n_ref_d, "ient_n_d); let quotient_ref_d_n = &d / n; let quotient_d_n = d.clone() / n; prop_assert_eq!("ient_ref_d_n, "ient_d_n); let mut q = d.clone(); q /= n; prop_assert_eq!(&q, "ient_d_n); } } } }; } impl_test!(u8); impl_test!(u16); impl_test!(u32); impl_test!(u64); impl_test!(u128); impl_test!(i8); impl_test!(i16); impl_test!(i32); impl_test!(i64); impl_test!(i128); impl_test!(float-div f32); impl_test!(float-div f64); proptest! { #[test] fn square(f: f32) { // ignore non-normal numbers prop_assume!(f.is_normal()); let n: BigDecimal = BigDecimal::from_f32(f).unwrap(); let n_times_n = &n * &n; prop_assert_eq!(n_times_n, n.square()) } } } bigdecimal-0.4.10/src/lib.tests.rs000064400000000000000000000116211046102023000150330ustar 00000000000000 mod is_one { use super::*; #[test] fn all_from_1_1000() { let mut i = BigUint::from(1u8); for s in 1..1000 { i *= 10u8; let d = BigDecimalRef::from(WithScale { value: &i, scale: s }); assert!(d.is_one(), "{}", s); i += 1u8; let d = BigDecimalRef::from(WithScale { value: &i, scale: s }); assert!(!d.is_one(), "{}", s); i -= 1u8; } } macro_rules! impl_case { ($name:ident: $input:literal => $expected:literal) => { #[test] fn $name() { let d: BigDecimal = $input.parse().unwrap(); assert_eq!(d.is_one(), $expected); } }; } impl_case!(case_0: "0" => false); impl_case!(case_1: "1" => true); impl_case!(case_n1: "-1" => false); impl_case!(case_10en1: "10e-1" => true); impl_case!(case_100en2: "100e-2" => true); impl_case!(case_10000en4: "10000e-4" => true); impl_case!(case_1d00000000000000000: "1.00000000000000000" => true); impl_case!(case_1d000000000000000000: "1.000000000000000000" => true); impl_case!(case_1d0000000000000000000: "1.0000000000000000000" => true); impl_case!(case_1d00000000000000001: "1.00000000000000001" => false); impl_case!(case_1d000000000000000001: "1.000000000000000001" => false); impl_case!(case_1d0000000000000000001: "1.0000000000000000001" => false); impl_case!(case_1d00000000000000000000000000000000: "1.00000000000000000000000000000000" => true); impl_case!(case_1d00000000000000000000000000000001: "1.00000000000000000000000000000001" => false); impl_case!(case_10d0000000000000000000000000000000000: "10.00000000000000000000000000000000000" => false); } mod is_one_quickcheck { use super::*; #[test] fn all_from_1_1e39() { let mut i = BigUint::from(1u8); for s in 1..39 { i *= 10u8; let d = BigDecimalRef::from(WithScale { value: &i, scale: s }); assert_eq!(d.is_one_quickcheck(), Some(true), "{}", s); i += 1u8; let d = BigDecimalRef::from(WithScale { value: &i, scale: s }); assert_eq!(d.is_one_quickcheck(), Some(false), "{}", s); i -= 1u8; } } macro_rules! impl_case { ($name:ident: $input:literal => $expected:expr) => { #[test] fn $name() { let d: BigDecimal = $input.parse().unwrap(); assert_eq!(d.is_one_quickcheck(), $expected); } }; } impl_case!(case_0: "0" => Some(false)); impl_case!(case_1: "1" => Some(true)); impl_case!(case_n1: "-1" => Some(false)); impl_case!(case_10000000000000000000en19: "10000000000000000000e-19" => Some(true)); impl_case!(case_1d00000000000000000000: "1.00000000000000000000" => Some(true)); impl_case!(case_1d00000000000000000000000000000001: "1.00000000000000000000000000000001" => Some(false)); impl_case!(case_pi15: "3.141592653589793" => Some(false)); impl_case!(case_pi20: "3.14159265358979323846" => Some(false)); impl_case!(case_pi50: "3.1415926535897932384626433832795028841971693993751" => None); impl_case!(case_10d00000000000000000000: "10.00000000000000000000" => Some(false)); impl_case!(case_1000000000d00000000000000000000: "1000000000.00000000000000000000" => Some(false)); impl_case!(case_10000000000000000000000000d0000000000000000000000000000000000000000000: "10000000000000000000000000.0000000000000000000000000000000000000000000" => Some(false)); impl_case!(case_10000000000000000000000000d0x: "10000000000000000000000000.0" => Some(false)); } mod decimal_digit_count { use super::*; macro_rules! impl_case { ($name:ident: $input:literal => $expected:literal) => { #[test] fn $name() { let d: BigDecimal = $input.parse().unwrap(); assert_eq!(d.decimal_digit_count(), $expected); } }; } impl_case!(case_0: "0" => 1); impl_case!(case_1: "1" => 1); impl_case!(case_10: "10" => 2); impl_case!(case_10d01: "10.01" => 4); impl_case!(case_d00099999999999: ".00099999999999" => 11); } mod order_of_magnitude { use super::*; macro_rules! impl_case { ($name:ident: $input:literal => $expected:literal) => { #[test] fn $name() { let d: BigDecimal = $input.parse().unwrap(); assert_eq!(d.order_of_magnitude(), $expected); } }; } impl_case!(case_0: "0" => 0); impl_case!(case_1: "1" => 0); impl_case!(case_10: "10" => 1); impl_case!(case_1e1: "1e1" => 1); impl_case!(case_0e3: "0e3" => 0); impl_case!(case_30e2: "30e2" => 3); impl_case!(case_99en2: "99e-2" => -1); impl_case!(case_n100d0012e1: "-100.0012e1" => 3); impl_case!(case_16651567373773d553089: "16651567373773.553089" => 13); } bigdecimal-0.4.10/src/lib.tests.with_scale_round.rs000064400000000000000000000067261046102023000203750ustar 00000000000000// Test BigDecimal::with_scale_round macro_rules! impl_test { ( name=$($name:expr)*; $scale:literal : $mode:ident => $ex:literal ) => { paste! { #[test] fn [< $($name)* _rounding_ $mode >]() { let bigdecimal = test_input(); let result = bigdecimal.with_scale_round($scale as i64, RoundingMode::$mode); let expected = BigDecimal::from_str($ex).unwrap(); assert_eq!(result, expected); assert_eq!(result.int_val, expected.int_val); assert_eq!(result.scale, $scale); } } }; ( -$scale:literal $( : $($modes:ident),+ => $ex:literal )+ ) => { $( $( impl_test!(name=scale_neg_ $scale; -$scale : $modes => $ex); )* )* }; ( $scale:literal $( : $($modes:ident),+ => $ex:literal )+ ) => { $( $( impl_test!(name=scale_ $scale; $scale : $modes => $ex); )* )* }; } mod case_3009788271450eNeg9 { use super::*; fn test_input() -> BigDecimal { BigDecimal::from_str("3009.788271450").unwrap() } impl_test!(10 : Up, Down => "3009.7882714500"); impl_test!(9 : Up, Down => "3009.788271450"); impl_test!(8 : Up, Down, HalfEven => "3009.78827145"); impl_test!(7 : Up, Ceiling, HalfUp => "3009.7882715" : Down, Floor, HalfDown, HalfEven => "3009.7882714"); impl_test!(4 : Up, Ceiling, HalfUp, HalfDown, HalfEven => "3009.7883" : Down, Floor => "3009.7882"); impl_test!(2 : Up => "3009.79" : Down => "3009.78"); impl_test!(1 : Up => "3009.8" : Down => "3009.7"); impl_test!(0 : Up => "3010" : Down => "3009"); impl_test!( -1 : Up => "301e1"); impl_test!( -2 : Up => "31e2"); impl_test!( -3 : Up => "4e3"); impl_test!( -4 : Up => "1e4" ); impl_test!( -5 : Up => "1e5" : Down => "0"); impl_test!( -20 : Up => "1e20" : Down => "0"); } mod case_neg_636652287787259 { use super::*; fn test_input() -> BigDecimal { BigDecimal::from_str("-636652287787259").unwrap() } impl_test!(1 : Up, Down => "-636652287787259.0"); impl_test!(0 : Up, Down => "-636652287787259"); impl_test!(-1 : Up => "-63665228778726e1" : Down => "-63665228778725e1"); impl_test!(-12 : Up => "-637e12" : Down => "-636e12"); } mod case_99999999999999999999999eNeg4 { use super::*; fn test_input() -> BigDecimal { BigDecimal::from_str("99999999999999999999999e-4").unwrap() } impl_test!(4 : Up => "9999999999999999999.9999"); impl_test!(3 : Up => "10000000000000000000.000" : Down => "9999999999999999999.999"); impl_test!(-3 : Up => "10000000000000000e3" : Down => "9999999999999999e3"); } mod case_369708962060657eNeg30 { use super::*; fn test_input() -> BigDecimal { BigDecimal::from_str("369708962060657E-30").unwrap() } impl_test!(4 : Up => "1e-4"); impl_test!(20 : Up => "36971e-20" : Down => "36970e-20"); } mod case_682829560896740e30 { use super::*; fn test_input() -> BigDecimal { BigDecimal::from_str("682829560896740e30").unwrap() } impl_test!(4 : Up => "682829560896740000000000000000000000000000000.0000"); impl_test!(0 : Up => "682829560896740000000000000000000000000000000"); impl_test!(-35 : Up => "6828295609e35"); impl_test!(-36 : Up => "682829561e36"); impl_test!(-100 : Up => "1e100"); } bigdecimal-0.4.10/src/macros.rs000064400000000000000000000037671046102023000144240ustar 00000000000000// \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_communative_binop { (impl $trait:ident<$t1:ty>::$method:ident for $t2:ty) => { forward_communative_binop!( impl $trait<$t1>::$method for $t2; Output=BigDecimal ); }; (impl $trait:ident<$t1:ty>::$method:ident for $t2:ty; Output=$output:ty) => { impl $trait<$t1> for $t2 { type Output = $output; #[inline] fn $method(self, rhs: $t1) -> Self::Output { // swap operands $trait::$method(rhs, self) } } }; } /* 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); }; } */ bigdecimal-0.4.10/src/parsing.rs000064400000000000000000000165421046102023000145760ustar 00000000000000//! Routines for parsing values into BigDecimals use super::{BigDecimal, ParseBigDecimalError}; use stdlib::num::FpCategory; use stdlib::cmp::{self, Ordering}; use num_bigint::{BigInt, BigUint, Sign}; use num_traits::Zero; /// Try creating bigdecimal from f32 /// /// Non "normal" values will return Error case /// pub(crate) fn try_parse_from_f32(n: f32) -> Result { use stdlib::num::FpCategory::*; match n.classify() { Nan => Err(ParseBigDecimalError::Other("NAN".into())), Infinite => Err(ParseBigDecimalError::Other("Infinite".into())), Subnormal => Ok(parse_from_f32_subnormal(n)), Normal | Zero => Ok(parse_from_f32(n)), } } /// Return mantissa, exponent, and sign of given floating point number /// /// ```math /// f = frac * 2^pow /// ``` /// fn split_f32_into_parts(f: f32) -> (u32, i64, Sign) { let bits = f.to_bits(); let frac = (bits & ((1 << 23) - 1)) + (1 << 23); let exp = (bits >> 23) & 0xFF; let pow = exp as i64 - 127 - 23; let sign_bit = bits & (1 << 31); let sign = if sign_bit == 0 { Sign::Plus } else { Sign::Minus }; (frac, pow, sign) } /// Create bigdecimal from f32 /// pub(crate) fn parse_from_f32(n: f32) -> BigDecimal { if n.classify() == FpCategory::Subnormal { return parse_from_f32_subnormal(n); } let bits = n.to_bits(); if (bits << 1) == 0 { return Zero::zero(); } // n = frac * 2^pow let (frac, pow, sign) = split_f32_into_parts(n); let result; let scale; match pow.cmp(&0) { Ordering::Equal => { result = BigUint::from(frac); scale = 0; } Ordering::Less => { let trailing_zeros = cmp::min(frac.trailing_zeros(), -pow as u32); let reduced_frac = frac >> trailing_zeros; let reduced_pow = pow + trailing_zeros as i64; debug_assert!(reduced_pow <= 0); let shift = BigUint::from(5u8).pow(-reduced_pow as u32); result = reduced_frac * shift; scale = -reduced_pow; } Ordering::Greater => { let shift = BigUint::from(2u8).pow(pow.abs() as u32); result = frac * shift; scale = 0; } } BigDecimal { int_val: BigInt::from_biguint(sign, result), scale: scale, } } /// Create bigdecimal from subnormal f32 pub(crate) fn parse_from_f32_subnormal(n: f32) -> BigDecimal { debug_assert_eq!(n.classify(), FpCategory::Subnormal); let bits = n.to_bits(); let sign_bit = bits >> 31; debug_assert_eq!(bits >> 24, sign_bit << 7); let frac = bits - (sign_bit << 31); // 5^149 = 5^126 + 5^23 (f32-bit-bias=126, fraction-bits=23) let five_to_149 = BigUint::from_slice(&[ 1466336501, 2126633373, 2856417274, 1232167559, 2512314040, 1644054862, 3843013918, 3873995871, 858643596, 3706384338, 65604258 ]); let sign = if sign_bit == 0 { Sign::Plus } else { Sign::Minus }; let magnitude = BigUint::from(frac) * five_to_149; let scale = 149; let result = BigDecimal::new(BigInt::from_biguint(sign, magnitude), scale); return result; } #[cfg(test)] #[allow(non_snake_case)] mod test_parse_from_f32 { use super::*; include!("parsing.tests.parse_from_f32.rs"); } /// Try creating bigdecimal from f64 /// /// Non "normal" values will return Error case /// pub(crate) fn try_parse_from_f64(n: f64) -> Result { use stdlib::num::FpCategory::*; match n.classify() { Nan => Err(ParseBigDecimalError::Other("NAN".into())), Infinite => Err(ParseBigDecimalError::Other("Infinite".into())), Subnormal => Ok(parse_from_f64_subnormal(n)), Normal | Zero => Ok(parse_from_f64(n)), } } /// Return mantissa, exponent, and sign of given floating point number /// /// ```math /// f = frac * 2^pow /// ``` /// fn split_f64_into_parts(f: f64) -> (u64, i64, Sign) { let bits = f.to_bits(); let frac = (bits & ((1 << 52) - 1)) + (1 << 52); let exp = (bits >> 52) & 0x7FF; let pow = exp as i64 - 1023 - 52; let sign_bit = bits & (1 << 63); let sign = if sign_bit == 0 { Sign::Plus } else { Sign::Minus }; (frac, pow, sign) } /// Create bigdecimal from subnormal f64 pub(crate) fn parse_from_f64_subnormal(n: f64) -> BigDecimal { debug_assert_eq!(n.classify(), FpCategory::Subnormal); let bits = n.to_bits(); let sign_bit = bits >> 63; debug_assert_eq!(bits >> 52, sign_bit << 11); // 5^1074 = 5^1022 + 5^52 (f64-bit-bias=1022, fraction-bits=52) let five_to_1074 = BigUint::from_slice(&[ 2993937753, 2678407619, 3969251600, 2340035423, 635686544, 3544357150, 2618749834, 3195461310, 2593678749, 4014721034, 2512738537, 1379014958, 2606506302, 1209795638, 3422246832, 2235398534, 2765471138, 3453720203, 3699786234, 1752628667, 3832472493, 2479745915, 4210941784, 2088904316, 4137646701, 3840319652, 3815898978, 2202136831, 1022273801, 1470939580, 2032173740, 4063736241, 2069243191, 4077145663, 4033014231, 1920904652, 4195885152, 3551517817, 4246423481, 2447790869, 1797774111, 11284306, 195273359, 3811183395, 4065514955, 3382133286, 1078447835, 2100087074, 3915378083, 1127077286, 1409634978, 2331452623, 1301118814, 3692061923, 2506161869, 4270519152, 1066095370, 212429084, 3729063602, 3175008277, 2075072468, 2136773221, 4247151843, 2395660055, 449096848, 2439918400, 1564416362, 3638689409, 3054795416, 1803373736, 1506581328, 2791252870, 3391180271, 1768177410, 3891987426, 3655546435, 3881223940, 903390128 ]); let frac = bits - (sign_bit << 63); let sign = if sign_bit == 0 { Sign::Plus } else { Sign::Minus }; let magnitude = BigUint::from(frac) * five_to_1074; let scale = 1074; return BigDecimal::new(BigInt::from_biguint(sign, magnitude), scale); } /// Create bigdecimal from f64 /// /// Non "normal" values is undefined behavior /// pub(crate) fn parse_from_f64(n: f64) -> BigDecimal { if n.classify() == FpCategory::Subnormal { return parse_from_f64_subnormal(n); } let bits = n.to_bits(); // shift right by 1 bit to handle -0.0 if (bits << 1) == 0 { return Zero::zero(); } // n = frac * 2^pow let (frac, pow, sign) = split_f64_into_parts(n); debug_assert!(frac > 0); let result; let scale; match pow.cmp(&0) { Ordering::Equal => { result = BigUint::from(frac); scale = 0; } Ordering::Less => { let trailing_zeros = cmp::min(frac.trailing_zeros(), -pow as u32); let reduced_frac = frac >> trailing_zeros; let reduced_pow = pow + trailing_zeros as i64; debug_assert!(reduced_pow <= 0); let shift = BigUint::from(5u8).pow(-reduced_pow as u32); result = reduced_frac * shift; scale = -reduced_pow; } Ordering::Greater => { let shift = BigUint::from(2u8).pow(pow as u32); result = frac * shift; scale = 0; } } BigDecimal { int_val: BigInt::from_biguint(sign, result), scale: scale, } } #[cfg(test)] #[allow(non_snake_case)] mod test_parse_from_f64 { use super::*; include!("parsing.tests.parse_from_f64.rs"); } bigdecimal-0.4.10/src/parsing.tests.parse_from_f32.rs000064400000000000000000000106651046102023000205450ustar 00000000000000// tests for function bigdecimal::parsing::parse_from_f32 use paste::paste; use stdlib::f32; macro_rules! impl_test { ($name:ident : $input:literal == $expected:literal) => { paste! { #[test] fn [< case $name >]() { let n = $input as f32; let d = parse_from_f32(n); let expected: BigDecimal = $expected.parse().unwrap(); assert_eq!(d, expected); } #[test] fn [< case_neg $name >]() { let n = -($input as f32); let d = parse_from_f32(n); let expected: BigDecimal = concat!("-", $expected).parse().unwrap(); assert_eq!(d, expected); } } }; } impl_test!(_0 : 0.0 == "0"); impl_test!(_1 : 1.0 == "1"); impl_test!(_5en1 : 0.5 == "0.5"); impl_test!(_25en2 : 0.25 == "0.25"); impl_test!(_50 : 50. == "50"); impl_test!(_1en3 : 0.001 == "0.001000000047497451305389404296875"); impl_test!(_033203125en8 : 0.033203125 == "0.033203125"); impl_test!(_45En1 : 4.5 == "4.5"); impl_test!(_15625En5 : 0.15625 == "0.15625"); impl_test!(_1192092896En7 : 1.192092896e-7 == "1.1920928955078125E-7"); impl_test!(_1401757440 : 1401757440. == "1401757440"); impl_test!(_215092En1 : 21509.2 == "21509.19921875"); impl_test!(_2289620000 : 2289620000.0 == "2289619968"); impl_test!(_10000000 : 10000000. == "10000000"); impl_test!(_1en05 : 1e-5 == "0.00000999999974737875163555145263671875"); impl_test!(_1en1 : 1e-1 == "0.100000001490116119384765625"); impl_test!(_2en1 : 2e-1 == "0.20000000298023223876953125"); impl_test!(_80000197 : 80000197e0 == "80000200"); impl_test!(_23283064En16 : 2.3283064e-10 == "0.00000000023283064365386962890625"); impl_test!(_14693861798803098En17 : 0.14693861798803098 == "0.146938621997833251953125"); impl_test!(_1e20 : 1e20 == "100000002004087734272"); impl_test!(_1e30 : 1e30 == "1000000015047466219876688855040"); impl_test!(_1e38 : 1e38 == "99999996802856924650656260769173209088"); impl_test!(_317e36 : 317e36 == "317000006395220278118691742155288870912"); impl_test!(_23509889819en48 : 2.3509889819e-38 == "2.35098898190426788090088725919040801362055736959656341832065776397049129686767088287524529732763767242431640625E-38"); impl_test!(_235098744048en49 : 2.35098744048e-38 == "2.350987440475957123602109243087866394712812961308427354153308831195379018097479928428583662025630474090576171875E-38"); impl_test!(_6_99999952316 : 6.99999952316 == "6.999999523162841796875"); impl_test!(_317en40 : 317e-40 == "3.1700000098946435501119816090716154772221806896649747100732700841687651538425285480116144753992557525634765625E-38"); impl_test!(_4294967295 : 4294967295. == "4294967296"); impl_test!(_158456325029e18 : 1.58456325029e+29 == "158456325028528675187087900672"); impl_test!(_1_40129846432e_45 : 1.40129846432e-45 == "1.40129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125E-45"); impl_test!(_1_e42 : 1e-42 == "1.0005271035279193886395429224690001177341070264998322610345467546973108330377044694614596664905548095703125e-42"); impl_test!(_3_92E_n39 : 3.92E-39 == "3.91999933059456489828739575494312783522406115751507460249208160269472102366083987590172910131514072418212890625E-39"); impl_test!(_2_81341650018752E_n308 : 2.81341650018752E-308 == "0"); #[test] fn case_f32_min() { let n = f32::MIN; let d = parse_from_f32(n); assert_eq!(d, "-340282346638528859811704183484516925440".parse::().unwrap()); } #[test] fn case_f32_max() { let n = f32::MAX; let d = parse_from_f32(n); assert_eq!(d, "340282346638528859811704183484516925440".parse::().unwrap()); } #[test] fn case_f32_epsilon() { let n = f32::EPSILON; let d = parse_from_f32(n); assert_eq!(d, "1.1920928955078125E-7".parse::().unwrap()); } #[test] fn case_f32_pi() { let n = f32::consts::PI; let d = parse_from_f32(n); assert_eq!(d, "3.1415927410125732421875".parse::().unwrap()); } #[test] fn case_nan() { let n = f32::from_bits(0b01111111110000000000000000000000); assert!(n.is_nan()); let d = parse_from_f32(n); assert_eq!(d, "510423550381407695195061911147652317184".parse::().unwrap()); } #[test] fn case_try_from_nan() { let n = f32::NAN; let d = try_parse_from_f32(n); assert!(d.is_err()); } #[test] fn case_try_from_infinity() { let n = f32::INFINITY; let d = try_parse_from_f32(n); assert!(d.is_err()); } bigdecimal-0.4.10/src/parsing.tests.parse_from_f64.rs000064400000000000000000000147371046102023000205560ustar 00000000000000// tests for function bigdecimal::parsing::parse_from_f64 use paste::paste; use stdlib::f64; macro_rules! impl_test { ($input:literal == $expected:literal) => { paste! { impl_test!( [< "_" $input >] : $input == $expected); } }; ($name:ident : bits:$input:literal => $expected:literal) => { impl_test!($name : f64::from_bits($input) => $expected); }; ($name:ident : $input:literal == $expected:literal) => { impl_test!($name : ($input as f64) => $expected); }; ($name:ident : $input:expr => $expected:literal) => { paste! { #[test] fn [< case $name >]() { let n = $input; let d = parse_from_f64(n); let expected: BigDecimal = $expected.parse().unwrap(); assert_eq!(d, expected); } #[test] fn [< case_neg $name >]() { let n = f64::from_bits($input.to_bits() | (1<<63)); let d = parse_from_f64(n); let expected: BigDecimal = concat!("-", $expected).parse().unwrap(); assert_eq!(d, expected); } } }; } impl_test!(_0 : 0.0 == "0"); impl_test!(_1 : 1.0 == "1"); impl_test!(_2 : 2.0 == "2"); impl_test!(_3 : 3.0 == "3"); impl_test!(_5en1 : 0.5 == "0.5"); impl_test!(_25en2 : 0.25 == "0.25"); impl_test!(_1en1 : 0.1 == "0.1000000000000000055511151231257827021181583404541015625"); impl_test!(_1over3 : 0.333333333333333333333333333333 == "0.333333333333333314829616256247390992939472198486328125"); impl_test!(_pi : 3.141592653589793 == "3.141592653589793115997963468544185161590576171875"); impl_test!(_near_3 : 3.0000000000000004 == "3.000000000000000444089209850062616169452667236328125"); impl_test!(_8eneg306 : 8.544283616667655e-306 == "8.5442836166676545758745469881475846986178991076220674838778719735182619591847930738097459423424470941335996703553180065389909675214026779902482660710563190540056652827644969523715287333767167538014707594736533997824798692690142890189753467148541192574394234161821394612038920127719106177776787375705338074667624093006332620080979623387970617655687653904110103913103933178304212511707769987213793880764157458662751217010283883439888757033430556011326632895537144105152597427684695380215955244686097497705226475608085097617996058799189036784865947060736971859470127760066696392182317083388979882704968230500619384728741377732016919538675848783600526390429792978252568964346334556191024880163233082812954995600973750951114861484914086986464099027216434478759765625e-306"); impl_test!(_8e306 : 3e300 == "3000000000000000157514280765613260746113405743324477464747562346535407373966724587359114125241343592131113331498651634530827569706081291726934376554360120948545161602779727411213490701384364270178106859704912399835243357116902922640223958228340427483737776366460170528514347008416589160596378201620480"); impl_test!(_50 : 50. == "50"); impl_test!(_nanbits : bits:0b_0_11111111111_1000000000000000000000000000000000000000000000000001 => "269653970229347426076201969312749943170150807578117307259170330445749843759196293443300553362892619730839480672521111823337121537071529813188030913831084401350087805833926634314566788423582671529934053315387252306324360914392174188827078768228648633522131134987762597502339006422840407304422939101316534763520"); impl_test!(_3105036184601418e246 : bits:0b_0_11100000000_0000000000000000000000000000000000000000000000000000 => "3105036184601417870297958976925005110513772034233393222278104076052101905372753772661756817657292955900975461394262146412343160088229628782888574550082362278408909952041699811100530571263196889650525998387432937501785693707632115712"); impl_test!(_2_81341650018752E_308 : 2.81341650018752E-308 == "2.8134165001875198278759275525943498067505063001967969175506480744152639496835355462897889950138699429916690515722729976876607247658891051736045520063301219592298855232146428654590713004216312194773871772185068366206180596731958890086634117134422695105490626598276746331472433159429067991016548063113298957324839879447939977012897422163463450947345510093578791948321798481101505330952230105511530048812659083481787407026258844307461890753626327683153826358878159001221539330872743255707112001100520519610144879206546597846231715071742093092641158571855689231930930474890818690333095288369471228217443460522531282790309374378111440076317827545086535792316428407651758951233693496387904508572484340169054222573303301594335791590596740352481219815672375261783599853515625E-308"); #[test] fn case_f64_min() { let n = f64::MIN; let d = parse_from_f64(n); assert_eq!(d, "-179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368".parse::().unwrap()); } #[test] fn case_f64_max() { let n = f64::MAX; let d = parse_from_f64(n); assert_eq!(d, "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368".parse::().unwrap()); } #[test] fn case_f64_epsilon() { let n = f64::EPSILON; let d = parse_from_f64(n); assert_eq!(d, "2.220446049250313080847263336181640625e-16".parse::().unwrap()); } #[test] fn case_f64_pi() { let n = f64::consts::PI; let d = parse_from_f64(n); assert_eq!(d, "3.141592653589793115997963468544185161590576171875".parse::().unwrap()); } #[test] fn case_nan() { let n = f64::from_bits(0b0_11111111111_1000000000000000000000000000000000000000000000000000); assert!(n.is_nan()); let d = parse_from_f64(n); assert_eq!(d, "269653970229347386159395778618353710042696546841345985910145121736599013708251444699062715983611304031680170819807090036488184653221624933739271145959211186566651840137298227914453329401869141179179624428127508653257226023513694322210869665811240855745025766026879447359920868907719574457253034494436336205824".parse::().unwrap()); } #[test] fn case_try_from_nan() { let n = f64::NAN; let d = try_parse_from_f64(n); assert!(d.is_err()); } #[test] fn case_try_from_infinity() { let n = f64::INFINITY; let d = try_parse_from_f64(n); assert!(d.is_err()); } bigdecimal-0.4.10/src/rounding.rs000064400000000000000000000370251046102023000147570ustar 00000000000000//! Rounding structures and subroutines use crate::*; use crate::arithmetic::{add_carry, store_carry, extend_adding_with_carry}; use stdlib; use stdlib::num::NonZeroU64; // const DEFAULT_ROUNDING_MODE: RoundingMode = ${RUST_BIGDECIMAL_DEFAULT_ROUNDING_MODE} or HalfUp; include!(concat!(env!("OUT_DIR"), "/default_rounding_mode.rs")); /// Determines how to calculate the last digit of the number /// /// Default rounding mode is `HalfEven`, overwritable at compile-time /// by setting the environment-value `RUST_BIGDECIMAL_DEFAULT_ROUNDING_MODE` /// to the name of the mode. /// #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] pub enum RoundingMode { /// Always round away from zero /// /// /// * 5.5 → 6.0 /// * 2.5 → 3.0 /// * 1.6 → 2.0 /// * 1.1 → 2.0 /// * -1.1 → -2.0 /// * -1.6 → -2.0 /// * -2.5 → -3.0 /// * -5.5 → -6.0 Up, /// Always round towards zero /// /// * 5.5 → 5.0 /// * 2.5 → 2.0 /// * 1.6 → 1.0 /// * 1.1 → 1.0 /// * -1.1 → -1.0 /// * -1.6 → -1.0 /// * -2.5 → -2.0 /// * -5.5 → -5.0 Down, /// Towards +∞ /// /// * 5.5 → 6.0 /// * 2.5 → 3.0 /// * 1.6 → 2.0 /// * 1.1 → 2.0 /// * -1.1 → -1.0 /// * -1.6 → -1.0 /// * -2.5 → -2.0 /// * -5.5 → -5.0 Ceiling, /// Towards -∞ /// /// * 5.5 → 5.0 /// * 2.5 → 2.0 /// * 1.6 → 1.0 /// * 1.1 → 1.0 /// * -1.1 → -2.0 /// * -1.6 → -2.0 /// * -2.5 → -3.0 /// * -5.5 → -6.0 Floor, /// Round to 'nearest neighbor', or up if ending decimal is 5 /// /// * 5.5 → 6.0 /// * 2.5 → 3.0 /// * 1.6 → 2.0 /// * 1.1 → 1.0 /// * -1.1 → -1.0 /// * -1.6 → -2.0 /// * -2.5 → -3.0 /// * -5.5 → -6.0 HalfUp, /// Round to 'nearest neighbor', or down if ending decimal is 5 /// /// * 5.5 → 5.0 /// * 2.5 → 2.0 /// * 1.6 → 2.0 /// * 1.1 → 1.0 /// * -1.1 → -1.0 /// * -1.6 → -2.0 /// * -2.5 → -2.0 /// * -5.5 → -5.0 HalfDown, /// Round to 'nearest neighbor', if equidistant, round towards /// nearest even digit /// /// * 5.5 → 6.0 /// * 2.5 → 2.0 /// * 1.6 → 2.0 /// * 1.1 → 1.0 /// * -1.1 → -1.0 /// * -1.6 → -2.0 /// * -2.5 → -2.0 /// * -5.5 → -6.0 /// HalfEven, } impl RoundingMode { /// Perform the rounding operation /// /// Parameters /// ---------- /// * sign (Sign) - Sign of the number to be rounded /// * pair (u8, u8) - The two digits in question to be rounded. /// i.e. to round 0.345 to two places, you would pass (4, 5). /// As decimal digits, they /// must be less than ten! /// * trailing_zeros (bool) - True if all digits after the pair are zero. /// This has an effect if the right hand digit is 0 or 5. /// /// Returns /// ------- /// Returns the first number of the pair, rounded. The sign is not preserved. /// /// Examples /// -------- /// - To round 2341, pass in `Plus, (4, 1), true` → get 4 or 5 depending on scheme /// - To round -0.1051, to two places: `Minus, (0, 5), false` → returns either 0 or 1 /// - To round -0.1, pass in `true, (0, 1)` → returns either 0 or 1 /// /// Calculation of pair of digits from full number, and the replacement of that number /// should be handled separately /// pub fn round_pair(&self, sign: Sign, pair: (u8, u8), trailing_zeros: bool) -> u8 { use self::RoundingMode::*; use stdlib::cmp::Ordering::*; let (lhs, rhs) = pair; // if all zero after digit, never round if rhs == 0 && trailing_zeros { return lhs; } let up = lhs + 1; let down = lhs; match (*self, rhs.cmp(&5)) { (Up, _) => up, (Down, _) => down, (Floor, _) => if sign == Sign::Minus { up } else { down }, (Ceiling, _) => if sign == Sign::Minus { down } else { up }, (_, Less) => down, (_, Greater) => up, (_, Equal) if !trailing_zeros => up, (HalfUp, Equal) => up, (HalfDown, Equal) => down, (HalfEven, Equal) => if lhs % 2 == 0 { down } else { up }, } } /// Round digits, and if rounded up to 10, store 1 in carry and return zero pub(crate) fn round_pair_with_carry( &self, sign: Sign, pair: (u8, u8), trailing_zeros: bool, carry: &mut u8, ) -> u8 { let r = self.round_pair(sign, pair, trailing_zeros); store_carry(r, carry) } /// Round value at particular digit, returning replacement digit /// /// Parameters /// ---------- /// * at_digit (NonZeroU8) - 0-based index of digit at which to round. /// 0 would be the first digit, and would /// /// * sign (Sign) - Sign of the number to be rounded /// * value (u32) - The number containing digits to be rounded. /// * trailing_zeros (bool) - True if all digits after the value are zero. /// /// Returns /// ------- /// Returns the first number of the pair, rounded. The sign is not preserved. /// /// Examples /// -------- /// - To round 823418, at digit-index 3: `3, Plus, 823418, true` → 823000 or 824000, depending on scheme /// - To round -100205, at digit-index 1: `1, Minus, 100205, true` → 100200 or 100210 /// /// Calculation of pair of digits from full number, and the replacement of that number /// should be handled separately /// pub fn round_u32( &self, at_digit: stdlib::num::NonZeroU8, sign: Sign, value: u32, trailing_zeros: bool, ) -> u32 { let shift = 10u32.pow(at_digit.get() as u32 - 1); let splitter = shift * 10; // split 'value' into high and low let (top, bottom) = num_integer::div_rem(value, splitter); let lhs = (top % 10) as u8; let (rhs, remainder) = num_integer::div_rem(bottom, shift); let pair = (lhs, rhs as u8); let rounded = self.round_pair(sign, pair, trailing_zeros && remainder == 0); // replace low digit with rounded value let full = top - lhs as u32 + rounded as u32; // shift rounded value back to position full * splitter } /// Round the bigint to prec digits pub(crate) fn round_bigint_to_prec( self, n: num_bigint::BigInt, prec: NonZeroU64 ) -> WithScale { let (sign, mut biguint) = n.into_parts(); let ndrd = NonDigitRoundingData { mode: self, sign }; let ndigits = round_biguint_inplace(&mut biguint, prec, ndrd); let result = BigInt::from_biguint(sign, biguint); WithScale::from((result, -ndigits)) } /// Hint used to skip calculating trailing_zeros if they don't matter fn needs_trailing_zeros(&self, insig_digit: u8) -> bool { use RoundingMode::*; // only need trailing zeros if the rounding digit is 0 or 5 if matches!(self, HalfUp | HalfDown | HalfEven) { insig_digit == 5 } else { insig_digit == 0 } } } /// Return compile-time constant default rounding mode /// /// Defined by RUST_BIGDECIMAL_DEFAULT_ROUNDING_MODE at compile time /// impl Default for RoundingMode { fn default() -> Self { DEFAULT_ROUNDING_MODE } } /// All non-digit information required to round digits /// /// Just the mode and the sign. /// #[derive(Debug, Clone, Copy)] pub(crate) struct NonDigitRoundingData { /// Rounding mode pub mode: RoundingMode, /// Sign of digits pub sign: Sign, } impl NonDigitRoundingData { /// Round pair of digits, storing overflow (10) in the carry pub fn round_pair(&self, pair: (u8, u8), trailing_zeros: bool) -> u8 { self.mode.round_pair(self.sign, pair, trailing_zeros) } /// round-pair with carry-digits pub fn round_pair_with_carry(&self, pair: (u8, u8), trailing_zeros: bool, carry: &mut u8) -> u8 { self.mode.round_pair_with_carry(self.sign, pair, trailing_zeros, carry) } /// Use sign and default rounding mode pub fn default_with_sign(sign: Sign) -> Self { NonDigitRoundingData { sign, mode: RoundingMode::default() } } /// Round BigUint to requested precision, using mode and sign in self /// /// Returns the biguint with at most 'prec' digits, and scale /// indicating how many decimal digits were removed. /// pub(crate) fn round_biguint_to_prec( self, mut n: num_bigint::BigUint, prec: NonZeroU64 ) -> WithScale { let ndigits = round_biguint_inplace(&mut n, prec, self); WithScale::from((n, -ndigits)) } } /// Relevant information about insignificant digits, used for rounding /// /// If rounding at indicated point: /// /// ```txt /// aaaaizzzzzzzz /// ^ /// ``` /// /// 'a' values are significant, 'i' is the insignificant digit, /// and trailing_zeros is true if all 'z' are 0. /// #[derive(Debug,Clone,Copy)] pub(crate) struct InsigData { /// highest insignificant digit pub digit: u8, /// true if all digits more insignificant than 'digit' is zero /// /// This is only useful if relevant for the rounding mode, it /// may be 'wrong' in these cases. pub trailing_zeros: bool, /// rounding-mode and sign pub rounding_data: NonDigitRoundingData } #[allow(dead_code)] impl InsigData { /// Build from insig data and lazily calculated trailing-zeros callable pub fn from_digit_and_lazy_trailing_zeros( rounder: NonDigitRoundingData, insig_digit: u8, calc_trailing_zeros: impl FnOnce() -> bool ) -> Self { Self { digit: insig_digit, trailing_zeros: rounder.mode.needs_trailing_zeros(insig_digit) && calc_trailing_zeros(), rounding_data: rounder, } } /// Build from slice of insignificant little-endian digits pub fn from_digit_slice(rounder: NonDigitRoundingData, digits: &[u8]) -> Self { match digits.split_last() { Some((&d0, trailing)) => { Self::from_digit_and_lazy_trailing_zeros( rounder, d0, || trailing.iter().all(Zero::is_zero) ) } None => { Self { digit: 0, trailing_zeros: true, rounding_data: rounder, } } } } /// from sum of overlapping digits, (a is longer than b) pub fn from_overlapping_digits_backward_sum( rounder: NonDigitRoundingData, mut a_digits: stdlib::iter::Rev>, mut b_digits: stdlib::iter::Rev>, carry: &mut u8, ) -> Self { debug_assert!(a_digits.len() >= b_digits.len()); debug_assert_eq!(carry, &0); // most-significant insignificant digit let insig_digit; match (a_digits.next(), b_digits.next()) { (Some(a), Some(b)) => { // store 'full', initial sum, we will handle carry below insig_digit = a + b; } (Some(d), None) | (None, Some(d)) => { insig_digit = *d; } (None, None) => { // both digit slices were empty; all zeros return Self { digit: 0, trailing_zeros: true, rounding_data: rounder, }; } }; // find first non-nine value let mut sum = 9; while sum == 9 { let next_a = a_digits.next().unwrap_or(&0); let next_b = b_digits.next().unwrap_or(&0); sum = next_a + next_b; } // if previous sum was greater than ten, // the one would carry through all the 9s let sum = store_carry(sum, carry); // propagate carry to the highest insignificant digit let insig_digit = add_carry(insig_digit, carry); // if the last 'sum' value isn't zero, or if any remaining // digit is not zero, then it's not trailing zeros let trailing_zeros = sum == 0 && rounder.mode.needs_trailing_zeros(insig_digit) && a_digits.all(Zero::is_zero) && b_digits.all(Zero::is_zero); Self { digit: insig_digit, trailing_zeros: trailing_zeros, rounding_data: rounder, } } pub fn round_digit(&self, digit: u8) -> u8 { self.rounding_data.round_pair((digit, self.digit), self.trailing_zeros) } pub fn round_digit_with_carry(&self, digit: u8, carry: &mut u8) -> u8 { self.rounding_data.round_pair_with_carry((digit, self.digit), self.trailing_zeros, carry) } pub fn round_slice_into(&self, dest: &mut Vec, digits: &[u8]) { let (&d0, rest) = digits.split_first().unwrap_or((&0, &[])); let digits = rest.iter().copied(); let mut carry = 0; let r0 = self.round_digit_with_carry(d0, &mut carry); dest.push(r0); extend_adding_with_carry(dest, digits, &mut carry); if !carry.is_zero() { dest.push(carry); } } #[allow(dead_code)] pub fn round_slice_into_with_carry(&self, dest: &mut Vec, digits: &[u8], carry: &mut u8) { let (&d0, rest) = digits.split_first().unwrap_or((&0, &[])); let digits = rest.iter().copied(); let r0 = self.round_digit_with_carry(d0, carry); dest.push(r0); extend_adding_with_carry(dest, digits, carry); } } /// Round BigUint n to 'prec' digits fn round_biguint_inplace( n: &mut num_bigint::BigUint, prec: NonZeroU64, rounder: NonDigitRoundingData, ) -> i64 { use arithmetic::modulo::{mod_ten_2p64_le, mod_100_uint}; use arithmetic::decimal::count_digits_biguint; let digit_count = count_digits_biguint(n); let digits_to_remove = digit_count.saturating_sub(prec.get()); if digits_to_remove == 0 { return 0; } if digits_to_remove == 1 { let insig_digit = mod_ten_2p64_le(n.iter_u64_digits()); *n /= 10u8; let sig_digit = mod_ten_2p64_le(n.iter_u64_digits()); let rounded_digit = rounder.round_pair((sig_digit, insig_digit), true); *n += rounded_digit - sig_digit; if rounded_digit != 10 { return 1; } let digit_count = count_digits_biguint(n); if digit_count == prec.get() { return 1; } debug_assert_eq!(digit_count, prec.get() + 1); *n /= 10u8; return 2; } let shifter = ten_to_the_uint(digits_to_remove - 1); let low_digits = &(*n) % &shifter; let trailing_zeros = low_digits.is_zero(); *n /= &shifter; let u = mod_100_uint(n); let (sig_digit, insig_digit) = u.div_rem(&10); let rounded_digit = rounder.round_pair((sig_digit, insig_digit), trailing_zeros); *n /= 10u8; *n += rounded_digit - sig_digit; if rounded_digit != 10 { return digits_to_remove as i64; } let digit_count = count_digits_biguint(n); if digit_count == prec.get() { return digits_to_remove as i64; } debug_assert_eq!(digit_count, prec.get() + 1); // shift by another digit. Overflow means all significant // digits were nines, so no need to re-round *n /= 10u8; return digits_to_remove as i64 + 1; } #[cfg(test)] include!("rounding.tests.rs"); bigdecimal-0.4.10/src/rounding.tests.rs000064400000000000000000000245471046102023000161250ustar 00000000000000 #[allow(non_snake_case)] mod test_round_pair { use paste::paste; use super::*; macro_rules! impl_test { ( $($mode:ident),+ => $expected:literal) => { $( paste! { #[test] fn [< mode_ $mode >]() { let (pair, sign, trailing_zeros) = test_input(); let mode = self::RoundingMode::$mode; let result = mode.round_pair(sign, pair, trailing_zeros); assert_eq!(result, $expected); } } )* } } macro_rules! define_test_input { ( - $lhs:literal . $rhs:literal $($t:tt)* ) => { define_test_input!(sign=Sign::Minus, pair=($lhs, $rhs), $($t)*); }; ( $lhs:literal . $rhs:literal $($t:tt)*) => { define_test_input!(sign=Sign::Plus, pair=($lhs, $rhs), $($t)*); }; ( sign=$sign:expr, pair=$pair:expr, ) => { define_test_input!(sign=$sign, pair=$pair, trailing_zeros=true); }; ( sign=$sign:expr, pair=$pair:expr, 000x ) => { define_test_input!(sign=$sign, pair=$pair, trailing_zeros=false); }; ( sign=$sign:expr, pair=$pair:expr, trailing_zeros=$trailing_zeros:literal ) => { fn test_input() -> ((u8, u8), Sign, bool) { ($pair, $sign, $trailing_zeros) } }; } mod case_0_1 { use super::*; define_test_input!(0 . 1); impl_test!(Up, Ceiling => 1); impl_test!(Down, Floor, HalfUp, HalfDown, HalfEven => 0); } mod case_neg_0_1 { use super::*; define_test_input!(-0 . 1); impl_test!(Up, Floor => 1); impl_test!(Down, Ceiling, HalfUp, HalfDown, HalfEven => 0); } mod case_0_5 { use super::*; define_test_input!( 0 . 5 ); impl_test!(Up, Ceiling, HalfUp => 1); impl_test!(Down, Floor, HalfDown, HalfEven => 0); } mod case_neg_0_5 { use super::*; define_test_input!(-0 . 5); impl_test!(Up, Floor, HalfUp => 1); impl_test!(Down, Ceiling, HalfDown, HalfEven => 0); } mod case_0_5_000x { use super::*; // ...000x indicates a non-zero trailing digit; affects behavior of rounding N.0 and N.5 define_test_input!(0 . 5 000x); impl_test!(Up, Ceiling, HalfUp, HalfDown, HalfEven => 1); impl_test!(Down, Floor => 0); } mod case_neg_0_5_000x { use super::*; define_test_input!(-0 . 5 000x); impl_test!(Up, Floor, HalfUp, HalfDown, HalfEven => 1); impl_test!(Down, Ceiling => 0); } mod case_0_7 { use super::*; define_test_input!(0 . 7); impl_test!(Up, Ceiling, HalfUp, HalfDown, HalfEven => 1); impl_test!(Down, Floor => 0); } mod case_neg_0_7 { use super::*; define_test_input!(-0 . 7); impl_test!(Up, Floor, HalfUp, HalfDown, HalfEven => 1); impl_test!(Down, Ceiling => 0); } mod case_neg_4_3_000x { use super::*; define_test_input!(-4 . 3 000x); impl_test!(Up, Floor => 5); impl_test!(Down, Ceiling, HalfUp, HalfDown, HalfEven => 4); } mod case_9_5_000x { use super::*; define_test_input!(9 . 5 000x); impl_test!(Up, Ceiling, HalfDown, HalfUp, HalfEven => 10); impl_test!(Down, Floor => 9); } mod case_9_5 { use super::*; define_test_input!(9 . 5); impl_test!(Up, Ceiling, HalfUp, HalfEven => 10); impl_test!(Down, Floor, HalfDown => 9); } mod case_8_5 { use super::*; define_test_input!(8 . 5); impl_test!(Up, Ceiling, HalfUp => 9); impl_test!(Down, Floor, HalfDown, HalfEven => 8); } mod case_neg_6_5 { use super::*; define_test_input!(-6 . 5); impl_test!(Up, Floor, HalfUp => 7); impl_test!(Down, Ceiling, HalfDown, HalfEven => 6); } mod case_neg_6_5_000x { use super::*; define_test_input!(-6 . 5 000x); impl_test!(Up, Floor, HalfUp, HalfDown, HalfEven => 7); impl_test!(Down, Ceiling => 6); } mod case_3_0 { use super::*; define_test_input!(3 . 0); impl_test!(Up, Down, Ceiling, Floor, HalfUp, HalfDown, HalfEven => 3); } mod case_3_0_000x { use super::*; define_test_input!(3 . 0 000x); impl_test!(Up, Ceiling => 4); impl_test!(Down, Floor, HalfUp, HalfDown, HalfEven => 3); } mod case_neg_2_0 { use super::*; define_test_input!(-2 . 0); impl_test!(Up, Down, Ceiling, Floor, HalfUp, HalfDown, HalfEven => 2); } mod case_neg_2_0_000x { use super::*; define_test_input!(-2 . 0 000x); impl_test!(Up, Floor => 3); impl_test!(Down, Ceiling, HalfUp, HalfDown, HalfEven => 2); } } #[cfg(test)] #[allow(non_snake_case)] mod test_round_u32 { use paste::paste; use super::*; macro_rules! impl_test { ( $pos:literal :: $($mode:ident),+ => $expected:literal) => { $( paste! { #[test] fn [< digit_ $pos _mode_ $mode >]() { let (value, sign, trailing_zeros) = test_input(); let mode = self::RoundingMode::$mode; let pos = stdlib::num::NonZeroU8::new($pos as u8).unwrap(); let result = mode.round_u32(pos, sign, value, trailing_zeros); assert_eq!(result, $expected); } } )* } } macro_rules! define_test_input { ( - $value:literal $($t:tt)* ) => { define_test_input!(sign=Sign::Minus, value=$value $($t)*); }; ( $value:literal $($t:tt)* ) => { define_test_input!(sign=Sign::Plus, value=$value $($t)*); }; ( sign=$sign:expr, value=$value:literal ...000x ) => { define_test_input!(sign=$sign, value=$value, trailing_zeros=false); }; ( sign=$sign:expr, value=$value:literal ) => { define_test_input!(sign=$sign, value=$value, trailing_zeros=true); }; ( sign=$sign:expr, value=$value:expr, trailing_zeros=$trailing_zeros:literal ) => { fn test_input() -> (u32, Sign, bool) { ($value, $sign, $trailing_zeros) } }; } mod case_13950000 { use super::*; define_test_input!(13950000); impl_test!(3 :: Up => 13950000); impl_test!(5 :: Up, Ceiling, HalfUp, HalfEven => 14000000); impl_test!(5 :: Down, HalfDown => 13900000); } mod case_neg_35488622_000x { use super::*; // ...000x indicates non-zero trailing digit define_test_input!(-35488622 ...000x); impl_test!(1 :: Up => 35488630); impl_test!(1 :: Down => 35488620); impl_test!(2 :: Up => 35488700); impl_test!(2 :: Down => 35488600); impl_test!(7 :: Up, Floor => 40000000); impl_test!(7 :: Down, Ceiling => 30000000); impl_test!(8 :: Up => 100000000); impl_test!(8 :: Down => 0); } } #[allow(non_snake_case)] mod test_round_biguint_inplace { use super::*; use paste::paste; macro_rules! impl_test { (IMPL; $prec:literal, $mode:ident => $expected:literal, $exp:literal) => { paste! { #[test] fn [< prec $prec _mode_ $mode >]() { let mut n = test_input(); let rounder = NonDigitRoundingData { mode: self::RoundingMode::$mode, sign: Sign::Plus, }; let prec = NonZeroU64::new($prec).unwrap(); let result = round_biguint_inplace(&mut n, prec, rounder); let expected: BigUint = $expected.parse().unwrap(); assert_eq!(&expected, &n); assert_eq!($exp, result); } } }; ($prec:literal: $($mode:ident),+ => $expected:literal E $exp:literal) => { $( impl_test!(IMPL; $prec, $mode => $expected, $exp); )* }; ($prec:literal: $($($mode:ident),+ => $expected:literal E $exp:literal),+ ) => { $( impl_test!($prec: $($mode),* => $expected E $exp); )* }; } mod case_14414008876e200 { use super::*; fn test_input() -> BigUint { "1441400887642029388383856645559897315584165538408309505171135258930500598075662511441702498467332463786833300335785089981027498174604649257434184055851638492438374046355824930138046686225938550901559011829587689".parse().unwrap() } impl_test!(15: Up => "144140088764203" E 196, Down => "144140088764202" E 196); impl_test!(11: Down, HalfEven => "14414008876" E 200, Up => "14414008877" E 200); impl_test!(1: Down, HalfEven => "1" E 210, Up => "2" E 210); } mod case_99191529355902971933631238546419824884699 { use super::*; fn test_input() -> BigUint { "99191529355902971933631238546419824884699".parse().unwrap() } impl_test!(42: Down, Up => "99191529355902971933631238546419824884699" E 0); impl_test!(41: Down, Up, HalfEven => "99191529355902971933631238546419824884699" E 0); impl_test!(40: Up => "9919152935590297193363123854641982488470" E 1, Down => "9919152935590297193363123854641982488469" E 1); impl_test!(13: Up => "9919152935591" E 28, Down => "9919152935590" E 28); impl_test!(4: Up => "9920" E 37, Down => "9919" E 37); impl_test!(3: Up => "992" E 38, Down => "991" E 38); impl_test!(2: Up => "10" E 40, Down => "99" E 39); impl_test!(1: Up => "1" E 41, Down => "9" E 40); } mod case_99 { use super::*; fn test_input() -> BigUint { "99".parse().unwrap() } impl_test!(2: Up => "99" E 0, Down => "99" E 0); impl_test!(1: Up => "1" E 2, Down => "9" E 1); } } bigdecimal-0.4.10/src/with_std.rs000064400000000000000000000007501046102023000147520ustar 00000000000000 // Wrap std:: modules in namespace #[allow(unused_imports)] mod stdlib { pub use std::{ cmp, convert, default, fmt, hash, marker, mem, num, ops, iter, slice, str, string, f32, f64, }; #[cfg(test)] pub use std::collections::hash_map::DefaultHasher; pub use std::borrow; pub use std::boxed::{self, Box}; pub use std::vec::{self, Vec}; } bigdecimal-0.4.10/src/without_std.rs000064400000000000000000000014511046102023000155010ustar 00000000000000#[allow(unused_imports)] #[macro_use] extern crate alloc; #[cfg(test)] extern crate siphasher; // Without this import we get the following error: // error[E0599]: no method naemed `powi` found for type `f64` in the current scope #[allow(unused_imports)] use num_traits::float::FloatCore; // Wrap core:: modules in namespace #[allow(unused_imports)] mod stdlib { pub use core::{ cmp, convert, default, fmt, hash, marker, mem, num, ops, iter, slice, str, i8, f32, f64, }; #[cfg(test)] pub use siphasher::sip::SipHasher as DefaultHasher; pub use alloc::borrow; pub use alloc::string; pub use alloc::boxed::{self, Box}; pub use alloc::vec::{self, Vec}; }