Bug 1716518 - Upgrade rust_decimal to v1.14.2.

Differential Revision: https://phabricator.services.mozilla.com/D117846
This commit is contained in:
Mike Hommey 2021-06-15 09:24:45 +00:00
Родитель 92aeb7b3c6
Коммит 56e1ee0ba7
26 изменённых файлов: 8498 добавлений и 1961 удалений

5
Cargo.lock сгенерированный
Просмотреть файл

@ -4370,10 +4370,11 @@ dependencies = [
[[package]]
name = "rust_decimal"
version = "1.7.0"
version = "1.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95ba36e8c41bf675947e200af432325f332f60a0aea0ef2dc456636c2f6037d7"
checksum = "9787e62372fc0c5a0f3af64c392652db72d3ec1cc0cff1becc175d2c11e6fbcc"
dependencies = [
"arrayvec",
"num-traits",
"serde",
]

Просмотреть файл

@ -1 +1 @@
{"files":{"CODE_OF_CONDUCT.md":"64765f10290cfce7191b4208cb21698b708a118568f5016602cccc304846a09a","CONTRIBUTING.md":"471d6281fb5038e17e32d3b4450aacf542a396709605aa170e07d3971d70b9c1","Cargo.toml":"5bcdb31d3230d6592b1940f0730bc6a0a07c05ef245a4a71ae9ff48b83cc5f38","LICENSE":"f8218253704e32441cafea1b9b3bcb2c6a3c51c5553cd8513d179290202bccb2","README.md":"2e6fc38c2289725da3fea1e2429fdc6482484e32b3e11d0216b719d871193fc5","VERSION.md":"172eea9bab41bd1493cd6a4a03a6df5cdfba66a9f02ec79b776fe71ad55d5be8","benches/lib_benches.rs":"39a5a691cd614aee08c0be202d715045dfe1d27e0a998fd983b8cc2ceaca7b55","rustfmt.toml":"f33bda44a494d17c95b7bc1b3dd88c203030b75be766f3a7f9b63ef45d960bb0","src/decimal.rs":"23b00c66f1024c7883f654d492fa6563173b47aa7ad26b4641315883a8278ea4","src/error.rs":"7f546cbfb6b1fdc6bb7bb3d6ef9f1a2462e30beba6f561e1890e7515c9bfb640","src/lib.rs":"104050f8a7d36317da0021dd4b42973e5f6cd928d748f3d0621f100d8d66fa6e","src/postgres.rs":"454630887e43403011dacee0682d163e92aed0071f3258ee616624ec11b82eb6","src/serde_types.rs":"9eadeca56538e69cd909853dd378bffecf2acc98c651ca2eec3192b81044b0a1","tests/decimal_tests.rs":"6c2d5a178a064e4a5e1131ed0d6c14527e9ac819f52379c0225872fa23788bcf"},"package":"95ba36e8c41bf675947e200af432325f332f60a0aea0ef2dc456636c2f6037d7"}
{"files":{"CODE_OF_CONDUCT.md":"64765f10290cfce7191b4208cb21698b708a118568f5016602cccc304846a09a","CONTRIBUTING.md":"471d6281fb5038e17e32d3b4450aacf542a396709605aa170e07d3971d70b9c1","Cargo.toml":"06f73d418d4346f1634ad611b064b5bef0ed3214bf4b30a2b9b1b196e8516e44","LICENSE":"f8218253704e32441cafea1b9b3bcb2c6a3c51c5553cd8513d179290202bccb2","Makefile.toml":"071b9b03210ab5978a75476c5ad93ab467cbbf8ae2ef36e4382ed4cd6bbf7cc3","README.md":"2378fe36c615a4c5922a74da0bf2b0d5e97830b2d1ed82155eaef745823f9a3b","VERSION.md":"fe774af618f4e648eb15e6df9a260f4ceca08a7d8c84b65f9230acac5147c264","benches/lib_benches.rs":"1525a2b3424e04da73153a0a57f8ee6e3c7ba93f3d847940ee596be57d469248","rustfmt.toml":"f33bda44a494d17c95b7bc1b3dd88c203030b75be766f3a7f9b63ef45d960bb0","src/constants.rs":"a182285f5e0ee03282f4b142709041bc7125ac99ea97391e6e0fca0f676339f7","src/db.rs":"d6bd647c670a2e95a98483a18312feebfe8196e1adb9abc4f92634b4a3b115df","src/decimal.rs":"5a5e9d711c14fe494ccbe45e2ae73bdd4fd99de221d913e2f0c4b430751d126a","src/error.rs":"35ca9f0e124c218bd684de72bfd7238eaa65b6902a9a9c6e5df5fc0db99cbed2","src/fuzz.rs":"86c07d8d541b9ee92a51275993b686902712f94c30785ba93f38997f3569e700","src/lib.rs":"52e74246198118fa860aa01ba14a39acd5fdff9642900ade5ed80e51a05aeb59","src/maths.rs":"a4e7f435d7a8bcf3bfcdf94e69da37a04afb7f4fa0eca4f7bc0c575ef898be3a","src/ops.rs":"4d426a35f73b0b69cbceee6e01c6eff59b8cc09aab7c885570aea52d8f258f66","src/ops/add.rs":"a85b6214be92a5563e8bb4a936275d8de094507d77384c9184d63583a78b3f55","src/ops/array.rs":"7a5e3b57ecee0bd9e51e8cc43c6e97aced6002fc58d913ec2956ad721e239cfc","src/ops/cmp.rs":"2019326946d413154fdc62b28da43267df7c1e527e6f9e8d23e9ae87fca3ed05","src/ops/common.rs":"6d48ecfa4796a38cb9d4c48f50ffed5d1ee79ba8e168a175615b6fe97194b7c2","src/ops/div.rs":"6b1e90b383293eb51f20f22846002a61f17211f7791860d4e9d6f82ad940fb87","src/ops/legacy.rs":"e0f68a2f26cb40872b6b85d20e092f604e8a3ad86fbbd2829eb3b6e49e960f64","src/ops/mul.rs":"6dd157135ddcc61b669e9883e73cefcc6cfa19ec0569f37ae3ba4bd21b497f35","src/ops/rem.rs":"c81383cf27f76d8d5372f63ae93fd5cbc0b85ced9515ede32430b1cd526af293","src/serde.rs":"f88438ac63d5eb4d78397f70948aba4063d0ab0064266350d606cdb40e374d96","src/str.rs":"eb61689426c1d219005e19fbdde1facbddbcb1f10c03c88dd587ff97596141f1","tests/decimal_tests.rs":"9a29dc7ab20c2fc25ad4cf136223a250ee1a74891a945ea36fe9e452c1cb63dd"},"package":"9787e62372fc0c5a0f3af64c392652db72d3ec1cc0cff1becc175d2c11e6fbcc"}

61
third_party/rust/rust_decimal/Cargo.toml поставляемый
Просмотреть файл

@ -13,8 +13,9 @@
[package]
edition = "2018"
name = "rust_decimal"
version = "1.7.0"
version = "1.14.2"
authors = ["Paul Mason <paul@form1.co.nz>"]
exclude = ["tests/generated/*"]
description = "A Decimal Implementation written in pure Rust suitable for financial calculations."
documentation = "https://docs.rs/rust_decimal/"
readme = "./README.md"
@ -22,13 +23,26 @@ keywords = ["decimal", "financial", "fixed", "precision"]
categories = ["science", "data-structures"]
license = "MIT"
repository = "https://github.com/paupino/rust-decimal"
[package.metadata.docs.rs]
all-features = true
[dependencies.arbitrary]
version = "1.0"
optional = true
default-features = false
[dependencies.arrayvec]
version = "0.5"
default-features = false
[dependencies.byteorder]
version = "1.3"
optional = true
default-features = false
[dependencies.bytes]
version = "0.5"
version = "1.0"
optional = true
default-features = false
[dependencies.diesel]
version = "1.4"
@ -38,30 +52,40 @@ default-features = false
[dependencies.num-traits]
version = "0.2"
features = ["i128"]
default-features = false
[dependencies.postgres]
version = "0.17"
version = "0.19"
optional = true
default-features = false
[dependencies.serde]
version = "1.0"
optional = true
default-features = false
[dependencies.serde_json]
version = "1.0"
optional = true
default-features = false
[dependencies.tokio-postgres]
version = "0.5"
version = "0.7"
optional = true
default-features = false
[dev-dependencies.bincode]
version = "1.3"
[dev-dependencies.bytes]
version = "0.5"
version = "1.0"
[dev-dependencies.csv]
version = "1"
[dev-dependencies.futures]
version = "0.3"
[dev-dependencies.rand]
version = "0.7"
[dev-dependencies.serde_derive]
version = "1.0"
@ -69,14 +93,21 @@ version = "1.0"
version = "1.0"
[dev-dependencies.tokio]
version = "0.2"
features = ["rt-threaded", "test-util", "macros"]
version = "1.0"
features = ["rt-multi-thread", "test-util", "macros"]
[features]
db-diesel-postgres = ["diesel"]
db-postgres = ["postgres", "bytes", "byteorder"]
db-tokio-postgres = ["postgres", "tokio-postgres", "bytes", "byteorder"]
default = ["serde"]
serde-bincode = ["serde"]
c-repr = []
db-diesel-postgres = ["diesel", "std"]
db-postgres = ["byteorder", "bytes", "postgres", "std"]
db-tokio-postgres = ["byteorder", "bytes", "postgres", "std", "tokio-postgres"]
default = ["serde", "std"]
legacy-ops = []
maths = []
rust-fuzz = ["arbitrary"]
serde-arbitrary-precision = ["serde", "serde_json/arbitrary_precision"]
serde-bincode = ["serde-str"]
serde-float = ["serde"]
serde-str = ["serde"]
std = ["arrayvec/std"]
tokio-pg = ["db-tokio-postgres"]

170
third_party/rust/rust_decimal/Makefile.toml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,170 @@
[config]
default_to_workspace = false
[tasks.build]
command = "cargo"
args = ["build"]
[tasks.bench]
toolchain = "nightly"
command = "cargo"
args = ["bench", "${@}"]
[tasks.bench-legacy]
toolchain = "nightly"
command = "cargo"
args = ["bench", "--no-default-features", "--features", "serde,std,legacy-ops", "${@}"]
[tasks.benchcmp]
dependencies = [
"benchcmp-legacy",
"benchcmp-default"
]
install_crate = "benchcmp"
command = "cargo"
args = ["benchcmp", "target/legacy.bench", "target/default.bench"]
[tasks.benchcmp-default]
script = "cargo +nightly bench > target/default.bench"
[tasks.benchcmp-legacy]
script = "cargo +nightly bench --no-default-features --features serde,std,legacy-ops > target/legacy.bench"
[tasks.coverage]
dependencies = ["codecov-clean"]
env = { "CARGO_INCREMENTAL" = "0", "RUSTFLAGS" = "-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort", "RUSTDOCFLAGS" = "-Cpanic=abort" }
run_task = "codecov-grcov"
[tasks.codecov-grcov]
dependencies = ["codecov-build", "codecov-test"]
command = "grcov"
args = [".", "-s", ".", "--binary-path", "./target/debug/", "-t", "html", "--branch", "--ignore-not-existing", "-o", "./target/debug/coverage/"]
[tasks.codecov-open]
command = "open"
args = [ "./target/debug/coverage/index.html" ]
[tasks.codecov-clean]
toolchain = "nightly"
command = "cargo"
args = [ "clean" ]
[tasks.codecov-build]
toolchain = "nightly"
command = "cargo"
args = [ "build", "-p", "rust_decimal", "--features=default" ]
[tasks.codecov-test]
toolchain = "nightly"
command = "cargo"
args = [ "test", "-p", "rust_decimal", "--features=default" ]
# Always test no-std with std tests
[tasks.test]
dependencies = ["test-no-std"]
command = "cargo"
args = ["test"]
[tasks.format]
workspace = true
install_crate = "rustfmt"
command = "cargo"
args = ["fmt", "--", "--emit=files"]
[tasks.outdated]
install_crate = "cargo-outdated"
command = "cargo"
args = ["outdated", "-R"]
[tasks.test-all]
dependencies = [
"test-no-std",
"test-default",
"test-legacy-ops",
"test-maths",
"test-misc",
"test-db",
"test-serde",
"test-macros"
]
[tasks.test-db]
dependencies = [
"test-db-postgres",
"test-db-tokio-postgres",
"test-db-diesel-postgres"
]
[tasks.test-serde]
dependencies = [
"test-serde-float",
"test-serde-str",
"test-serde-str-float",
"test-serde-arbitrary-precision",
"test-serde-arbitrary-precision-float"
]
[tasks.test-macros]
workspace = true
[tasks.test-no-std]
command = "cargo"
args = ["test", "--no-default-features"]
[tasks.test-default]
command = "cargo"
args = ["test", "--workspace", "--features=default"]
[tasks.test-legacy-ops]
command = "cargo"
args = ["test", "--workspace", "--features=legacy-ops"]
[tasks.test-maths]
dependencies = [
"test-maths-default",
"test-maths-legacy",
]
[tasks.test-maths-default]
command = "cargo"
args = ["test", "--workspace", "--no-default-features", "--features=maths", "maths", "--", "--skip", "generated"]
[tasks.test-maths-legacy]
command = "cargo"
args = ["test", "--workspace", "--no-default-features", "--features=maths,legacy-ops", "maths", "--", "--skip", "generated"]
[tasks.test-misc]
command = "cargo"
args = ["test", "--workspace", "--no-default-features", "--features=rust-fuzz", "rust_fuzz", "--", "--skip", "generated"]
[tasks.test-db-postgres]
command = "cargo"
args = ["test", "--workspace", "--tests", "--features=db-postgres", "db", "--", "--skip", "generated"]
[tasks.test-db-tokio-postgres]
command = "cargo"
args = ["test", "--workspace", "--tests", "--features=db-tokio-postgres", "db", "--", "--skip", "generated"]
[tasks.test-db-diesel-postgres]
command = "cargo"
args = ["test", "--workspace", "--tests", "--features=db-diesel-postgres", "db", "--", "--skip", "generated"]
[tasks.test-serde-float]
command = "cargo"
args = ["test", "--workspace", "--tests", "--features=serde-float", "serde", "--", "--skip", "generated"]
[tasks.test-serde-str]
command = "cargo"
args = ["test", "--workspace", "--tests", "--features=serde-str", "serde", "--", "--skip", "generated"]
[tasks.test-serde-str-float]
command = "cargo"
args = ["test", "--workspace", "--tests", "--features=serde-str,serde-float", "serde", "--", "--skip", "generated"]
[tasks.test-serde-arbitrary-precision]
command = "cargo"
args = ["test", "--workspace", "--tests", "--features=serde-arbitrary-precision", "serde", "--", "--skip", "generated"]
[tasks.test-serde-arbitrary-precision-float]
command = "cargo"
args = ["test", "--workspace", "--tests", "--features=serde-arbitrary-precision,serde-float", "serde", "--", "--skip", "generated"]

95
third_party/rust/rust_decimal/README.md поставляемый
Просмотреть файл

@ -1,15 +1,25 @@
# Decimal &emsp; [![Build Status]][actions] [![Latest Version]][crates.io]
# Decimal &emsp; [![Build Status]][actions] [![Latest Version]][crates.io] [![Docs Badge]][docs]
[Build Status]: https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fpaupino%2Frust-decimal%2Fbadge&label=build&logo=none
[actions]: https://actions-badge.atrox.dev/paupino/rust-decimal/goto
[Latest Version]: https://img.shields.io/crates/v/rust-decimal.svg
[crates.io]: https://crates.io/crates/rust-decimal
[Docs Badge]: https://docs.rs/rust_decimal/badge.svg
[docs]: https://docs.rs/rust_decimal
A Decimal implementation written in pure Rust suitable for financial calculations that require significant integral and fractional digits with no round-off errors.
The binary representation consists of a 96 bit integer number, a scaling factor used to specify the decimal fraction and a 1 bit sign. Because of this representation, trailing zeros are preserved and may be exposed when in string form. These can be truncated using the `normalize` or `round_dp` functions.
[Documentation](https://docs.rs/rust_decimal/)
## Getting started
To get started, add `rust_decimal` and optionally `rust_decimal_macros` to your `Cargo.toml`:
```toml
[dependencies]
rust_decimal = "1.14"
rust_decimal_macros = "1.14"
```
## Usage
@ -17,37 +27,67 @@ Decimal numbers can be created in a few distinct ways. The easiest and most opti
```rust
// Procedural macros need importing directly
use rust_decimal_macros::*;
use rust_decimal_macros::dec;
let number = dec!(-1.23);
assert_eq!("-1.23", number.to_string());
```
Alternatively you can also use one of the Decimal number convenience functions:
```rust
// Using the prelude can help importing trait based functions (e.g. core::str::FromStr).
use rust_decimal::prelude::*;
// Using an integer followed by the decimal points
let scaled = Decimal::new(202, 2); // 2.02
let scaled = Decimal::new(202, 2);
assert_eq!("2.02", scaled.to_string());
// From a string representation
let from_string = Decimal::from_str("2.02").unwrap(); // 2.02
let from_string = Decimal::from_str("2.02").unwrap();
assert_eq!("2.02", from_string.to_string());
// From a string representation in a different base
let from_string_base16 = Decimal::from_str_radix("ffff", 16).unwrap();
assert_eq!("65535", from_string_base16.to_string());
// Using the `Into` trait
let my_int : Decimal = 3i32.into();
let my_int: Decimal = 3i32.into();
assert_eq!("3", my_int.to_string());
// Using the raw decimal representation
// 3.1415926535897932384626433832
let pi = Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28);
assert_eq!("3.1415926535897932384626433832", pi.to_string());
```
Once you have instantiated your `Decimal` number you can perform calculations with it just like any other number:
```rust
use rust_decimal::prelude::*;
let amount = Decimal::from_str("25.12").unwrap();
let tax = Decimal::from_str("0.085").unwrap();
let total = amount + (amount * tax).round_dp(2);
assert_eq!(total.to_string(), "27.26");
```
## Features
* [c-repr](#c-repr)
* [db-postgres](#db-postgres)
* [db-tokio-postgres](#db-tokio-postgres)
* [db-diesel-postgres](#db-diesel-postgres)
* [legacy-ops](#legacy-ops)
* [maths](#maths)
* [rust-fuzz](#rust-fuzz)
* [serde-float](#serde-float)
* [serde-bincode](#serde-bincode)
* [serde-str](#serde-str)
* [serde-arbitrary-precision](#serde-arbitrary-precision)
* [std](#std)
## `c-repr`
Forces `Decimal` to use `[repr(C)]`. The corresponding target layout is 128 bit aligned.
## `db-postgres`
@ -62,23 +102,52 @@ Enables the tokio postgres module allowing for async communication with PostgreS
Enable `diesel` PostgreSQL support.
## `legacy-ops`
As of `1.10` the algorithms used to perform basic operations have changed which has benefits of significant speed improvements.
To maintain backwards compatibility this can be opted out of by enabling the `legacy-ops` feature.
## `maths`
The `maths` feature enables additional complex mathematical functions such as `pow`, `ln`, `enf`, `exp` etc.
Documentation detailing the additional functions can be found on the
[`MathematicalOps`](https://docs.rs/rust_decimal/latest/rust_decimal/trait.MathematicalOps.html) trait.
## `rust-fuzz`
Enable `rust-fuzz` support by implementing the `Arbitrary` trait.
## `serde-float`
Enable this so that JSON serialization of Decimal types are sent as a float instead of a string (default).
Enable this so that JSON serialization of `Decimal` types are sent as a float instead of a string (default).
e.g. with this turned on, JSON serialization would output:
```
```json
{
"value": 1.234
}
```
## `serde-bincode`
## `serde-str`
This is typically useful for `bincode` or `csv` like implementations.
Since `bincode` does not specify type information, we need to ensure that a type hint is provided in order to
correctly be able to deserialize. Enabling this feature on it's own will force deserialization to use `deserialize_str`
correctly be able to deserialize. Enabling this feature on its own will force deserialization to use `deserialize_str`
instead of `deserialize_any`.
If, for some reason, you also have `serde-float` enabled then this will use `deserialize_f64` as a type hint. Because
converting to `f64` _loses_ precision, it's highly recommended that you do NOT enable this feature when working with
`bincode`. That being said, this will only use 8 bytes so is slightly more efficient in regards to storage size.
`bincode`. That being said, this will only use 8 bytes so is slightly more efficient in terms of storage size.
## `serde-arbitrary-precision`
This is used primarily with `serde_json` and consequently adds it as a "weak dependency". This supports the
`arbitrary_precision` feature inside `serde_json` when parsing decimals.
This is recommended when parsing "float" looking data as it will prevent data loss.
## `std`
Enable `std` library support. This is enabled by default, however in the future will be opt in. For now, to support `no_std`
libraries, this crate can be compiled with `--no-default-features`.

189
third_party/rust/rust_decimal/VERSION.md поставляемый
Просмотреть файл

@ -1,5 +1,194 @@
# Version History
## 1.14.2
Fixes an overflow issue during division under some specific circumstances. ([#392](https://github.com/paupino/rust-decimal/issues/392))
## 1.14.1
A bug fix release following on from `1.14.0`:
* Fixes an issue whereby in some cases when subtracting a 64 bit `Decimal` a negating overflow would occur during underflow.
[#384](https://github.com/paupino/rust-decimal/issues/384). Thank you to [@c410-f3r](https://github.com/c410-f3r) for finding
this as part of fuzz testing.
* Fixes an issue with `exp` whereby negative values lost accuracy due to inability to converge.
[#378](https://github.com/paupino/rust-decimal/issues/378). Thank you to [@schungx](https://github.com/schungx) for
finding this and proposing a fix.
* Fixes some documentation issues.
## 1.14.0
* Added `checked_exp` and `checked_norm_pdf` functions [#375](https://github.com/paupino/rust-decimal/pull/375).
* Fixes bug in division under certain circumstances whereby overflow would occur during rounding. [#377](https://github.com/paupino/rust-decimal/pull/377)
* Documentation improvements
Thank you to [@falsetru](https://github.com/falsetru), [@schungx](https://github.com/schungx) and [@blasrodri](https://github.com/blasrodri) for your
help with this release!
## 1.13.0
This is a minor update to the library providing a few new features and one breaking change (I'm not using semver properly here
sorry).
* `#[must_use]` added to functions to provide additional compiler hints.
* `try_from_i128_with_scale` function added to safely handle `i128` overflow errors.
* New `c-repr` feature added which will ensure that `#[repr(C)]` is used on the `Decimal` type. Thanks [@jean-airoldie](https://github.com/jean-airoldie).
* Small improvements to `from_scientific`. It now supports a wider range of values as well has slightly faster performance.
* Support for negative and decimal `pow` functions. This is *breaking* since `powi(u64)` has been renamed to `powi(i64)`. If you want to
continue using `u64` arguments then please use `powu(u64)`. The fractional functions should be considered experimental for the time being
and may have subtle issues that still need ironing out. Functions are now:
* `powi`, `checked_powi` - When the exponent is a signed integer.
* `powu`, `checked_powu` - When the exponent is an unsigned integer.
* `powf`, `checked_powf` - When the exponent is a floating point number. Please note, numbers with a fractional component
will use an approximation function.
* `powd`, `checked_powd` - When the exponent is a `Decimal`. Please note, numbers with a fractional component will use
an approximation function.
## 1.12.4
Adds `num_traits::One` back to `rust_decimal::prelude` to prevent unnecessary downstream dependency breakages. Thanks [@spearman](https://github.com/spearman).
## 1.12.3
Fixes an issue [#361](https://github.com/paupino/rust-decimal/issues/361) when rounding a small number towards zero.
## 1.12.2
Fixes small regression whereby `0 - 0` was producing `-0`. Thank you [@KonishchevDmitry](https://github.com/KonishchevDmitry) for
providing a swift fix ([#356](https://github.com/paupino/rust-decimal/pull/356)).
## 1.12.1
Added `num_traits::Zero` back to `rust_decimal::prelude` to prevent unnecessary downstream dependency breakages.
## 1.12.0
This version releases faster operation support for `add`, `sub`, `cmp`, `rem` and `mul` to match the renewed `div` strategy.
It does this by leveraging 64 bit support when it makes sense, while attempting to still keep 32 bit optimizations in place.
To ensure correct functionality, thousands more tests were included to cover a wide variety of different scenarios
and bit combinations. Compared to previous operations, we get the following speed improvements:
* `add` - up to 2.2x faster
* `div` - up to 428x faster
* `mul` - up to 1.8x faster
* `rem` - up to 1.08x faster
* `sub` - up to 2.5x faster
Of course, if old functionality is desired, it can be re-enabled by using the `legacy-ops` feature.
Other improvements include:
* Remove unnecessary `String` allocation when parsing a scientific number format. Thanks [@thomcc](https://github.com/thomcc) for the fix [#350](https://github.com/paupino/rust-decimal/pull/350).
* Fixes overflow bug with `sqrt` when using the smallest possible representable number. [#349](https://github.com/paupino/rust-decimal/pull/349).
* Some minor optimizations in the `maths` feature. Future work will involve speeding up this feature by keeping operations
in an internal format until required.
* Added associated constants for `MIN`, `MAX` and `ZERO`. Deprecated `min_value()` and `max_value()` in favor of these new
constants.
* `-0` now gets corrected to `0`. During operation rewrite I needed to consider operations such as `-0 * 2` - in cases like
this I opted towards `0` always being the right number and `-0` being superfluous (since `+0 == -0`). Consequently, parsing
`-0` etc _in general_ will automatically be parsed as `0`. Of course, this _may_ be a breaking change so if this
functionality is required then please create an issue with the use case described.
* Small breaking change by renaming `is_negative` to `negative` in `UnpackedDecimal`.
* Some internal housekeeping was made to help make way for version 2.0 improvements.
## 1.11.1
This is a documentation only release and has no new functionality included. Thank you [@c410-f3r](https://github.com/c410-f3r) for the documentation fix.
## 1.11.0
This release includes a number of bug fixes and ergonomic improvements.
* Mathematical functionality is now behind a feature flag. This should help optimize library size when functions such as
`log` and `pow` are not required (e.g. simple financial applications). Mathematical functionality is now behind the `maths`
feature flag. [#321](https://github.com/paupino/rust-decimal/pull/321).
* Numerous test coverage improvements to ensure broader coverage. [#322](https://github.com/paupino/rust-decimal/pull/322),
[#323](https://github.com/paupino/rust-decimal/pull/323)
* Various documentation improvements. [#324](https://github.com/paupino/rust-decimal/pull/324), [#342](https://github.com/paupino/rust-decimal/pull/342)
* Fixes `u128` and `i128` parsing. [#332](https://github.com/paupino/rust-decimal/pull/332)
* Implemented `Checked*` traits from `num_traits`. [#333](https://github.com/paupino/rust-decimal/pull/333). Thank you
[@teoxoy](https://github.com/teoxoy)
* Added `checked_powi` function to `maths` feature. [#336](https://github.com/paupino/rust-decimal/pull/336)
* Updated `from_parts` to avoid accidental scale clobbering. [#337](https://github.com/paupino/rust-decimal/pull/337)
* Added support for the `Arbitrary` trait for `rust-fuzz` support. This is behind the feature flag `rust-fuzz`.
[#338](https://github.com/paupino/rust-decimal/pull/338)
* Fixes `e^-1` returning an incorrect approximation. [#339](https://github.com/paupino/rust-decimal/pull/339)
* Revamp of `RoundingStrategy` naming and documentation ([#340](https://github.com/paupino/rust-decimal/pull/340)).
The old naming was ambiguous in interpretation - the new naming
convention follows guidance from other libraries to ensure an easy to follow scheme. The `RoundingStrategy` enum now
includes:
* `MidpointNearestEven` (previously `BankersRounding`)
* `MidpointAwayFromZero` (previously `RoundHalfUp`)
* `MidpointTowardZero` (previously `RoundHalfDown`)
* `ToZero` (previously `RoundDown`)
* `AwayFromZero` (previously `RoundUp`)
* `ToNegativeInfinity` - new rounding strategy
* `ToPositiveInfinity` - new rounding strategy
* Added function to access `mantissa` directly. [#341](https://github.com/paupino/rust-decimal/pull/341)
* Added a feature to `rust_decimal_macros` to make re-exporting the macro from a downstream crate more approachable.
Enabling the `reexportable` feature will ensure that the generated code doesn't require `rust_decimal` to be exposed at
the root level. [#343](https://github.com/paupino/rust-decimal/pull/343)
## 1.10.3
* Fixes bug in bincode serialization where a negative symbol causes a buffer overflow (#317).
## 1.10.2
* Fixes a bug introduced in division whereby certain values when using a large remainder cause an incorrect results (#314).
## 1.10.1
* Fixes bug introduced in `neg` whereby sign would always be turned negative as opposed to being correctly negated.
Thank you [KonishchevDmitry](https://github.com/KonishchevDmitry) for finding and fixing this.
## 1.10.0
* Upgrade `postgres` to `0.19` and `tokio-postgres` to `0.7`.
* Faster `serde` serialization by preventing heap allocation.
* Alternative division algorithm which provides significant speed improvements. The new algorithms are enabled by default,
but can be disabled with the feature: `legacy-ops`. Further work to improve other operations will
be made available in future versions.
* Add `TryFrom` for `f32`/`f64` to/from Decimal
Thank you for the the community help and support for making this release happen, in particular:
[jean-airoldie](https://github.com/jean-airoldie), [gakonst](https://github.com/gakonst), [okaneco](https://github.com/okaneco) and
[c410-f3r](https://github.com/c410-f3r).
## 1.9.0
* Added arbitrary precision support for `serde_json` deserialization (#283)
* Add `u128` and `i128` `FromPrimitive` overrides to prevent default implementation kicking in. Also adds default `From`
interceptors to avoid having to use trait directly. (#282)
* Alias `serde-bincode` as `serde-str` to make usage clearer (#279)
* Adds scientific notation to format strings via `UpperExp` and `LowerExp` traits. (#271)
* Upgrade `tokio-postgres` and `postgres` libraries.
* Add statistical function support for `powi`, `sqrt`, `exp`, `norm_cdf`, `norm_pdf`, `ln` & `erf` (#281, #287)
* Allow `sum` across immutable references (#280)
Thank you for all the community help and support with this release, in particular [xilec](https://github.com/xilec),
[remkade](https://github.com/remkade) and [Anders429](https://github.com/Anders429).
## 1.8.1
Make `std` support the default to prevent breaking downstream library dependencies. To enable `no_std` support please set
default features to false and opt-in to any required components. e.g.
```
rust_decimal = { default-features = false, version = "1.8.0" }
```
## 1.8.0
* `no_std` support added to Rust Decimal by default. `std` isn't required to use Rust Decimal, however can be enabled by
using the `std` feature. [#190](https://github.com/paupino/rust-decimal/issues/190)
* Fixes issue with Decimal sometimes losing precision through `to_f64`. [#267](https://github.com/paupino/rust-decimal/issues/267).
* Add `Clone`, `Copy`, `PartialEq` and `Eq` derives to `RoundingStrategy`.
* Remove Proc Macro hack due to procedural macros as expressions being stabilized.
* Minor optimizations
Thank you to [@c410-f3r](https://github.com/c410-f3r), [@smessmer](https://github.com/smessmer) and [@KiChjang](https://github.com/KiChjang).
## 1.7.0
* Enables `bincode` support via the feature `serde-bincode`. This provides a long term fix for a regression

Просмотреть файл

@ -2,14 +2,15 @@
extern crate test;
use bincode::Options as _;
use core::str::FromStr;
use rust_decimal::Decimal;
use std::str::FromStr;
macro_rules! bench_decimal_op {
($name:ident, $op:tt, $y:expr) => {
($name:ident, $op:tt, $x:expr, $y:expr) => {
#[bench]
fn $name(b: &mut ::test::Bencher) {
let x = Decimal::from_str("2.01").unwrap();
let x = Decimal::from_str($x).unwrap();
let y = Decimal::from_str($y).unwrap();
b.iter(|| {
let result = x $op y;
@ -41,46 +42,53 @@ macro_rules! bench_fold_op {
}
/* Add */
bench_decimal_op!(add_one, +, "1");
bench_decimal_op!(add_two, +, "2");
bench_decimal_op!(add_one_hundred, +, "100");
bench_decimal_op!(add_point_zero_one, +, "0.01");
bench_decimal_op!(add_negative_point_five, +, "-0.5");
bench_decimal_op!(add_pi, +, "3.1415926535897932384626433832");
bench_decimal_op!(add_negative_pi, +, "-3.1415926535897932384626433832");
bench_decimal_op!(add_self, +, "2.01", "2.01");
bench_decimal_op!(add_simple, +, "2", "1");
bench_decimal_op!(add_one, +, "2.01", "1");
bench_decimal_op!(add_two, +, "2.01", "2");
bench_decimal_op!(add_one_hundred, +, "2.01", "100");
bench_decimal_op!(add_point_zero_one, +, "2.01", "0.01");
bench_decimal_op!(add_negative_point_five, +, "2.01", "-0.5");
bench_decimal_op!(add_pi, +, "2.01", "3.1415926535897932384626433832");
bench_decimal_op!(add_negative_pi, +, "2.01", "-3.1415926535897932384626433832");
bench_fold_op!(add_10k, +, 0, 10_000);
/* Sub */
bench_decimal_op!(sub_one, -, "1");
bench_decimal_op!(sub_two, -, "2");
bench_decimal_op!(sub_one_hundred, -, "100");
bench_decimal_op!(sub_point_zero_one, -, "0.01");
bench_decimal_op!(sub_negative_point_five, -, "-0.5");
bench_decimal_op!(sub_pi, -, "3.1415926535897932384626433832");
bench_decimal_op!(sub_negative_pi, -, "-3.1415926535897932384626433832");
bench_decimal_op!(sub_self, -, "2.01", "2.01");
bench_decimal_op!(sub_simple, -, "2", "1");
bench_decimal_op!(sub_one, -, "2.01", "1");
bench_decimal_op!(sub_two, -, "2.01", "2");
bench_decimal_op!(sub_one_hundred, -, "2.01", "100");
bench_decimal_op!(sub_point_zero_one, -, "2.01", "0.01");
bench_decimal_op!(sub_negative_point_five, -, "2.01", "-0.5");
bench_decimal_op!(sub_pi, -, "2.01", "3.1415926535897932384626433832");
bench_decimal_op!(sub_negative_pi, -, "2.01", "-3.1415926535897932384626433832");
bench_fold_op!(sub_10k, -, 5_000_000, 10_000);
/* Mul */
bench_decimal_op!(mul_one, *, "1");
bench_decimal_op!(mul_two, *, "2");
bench_decimal_op!(mul_one_hundred, *, "100");
bench_decimal_op!(mul_point_zero_one, *, "0.01");
bench_decimal_op!(mul_negative_point_five, *, "-0.5");
bench_decimal_op!(mul_pi, *, "3.1415926535897932384626433832");
bench_decimal_op!(mul_negative_pi, *, "-3.1415926535897932384626433832");
bench_decimal_op!(mul_one, *, "2.01", "1");
bench_decimal_op!(mul_two, *, "2.01", "2");
bench_decimal_op!(mul_one_hundred, *, "2.01", "100");
bench_decimal_op!(mul_point_zero_one, *, "2.01", "0.01");
bench_decimal_op!(mul_negative_point_five, *, "2.01", "-0.5");
bench_decimal_op!(mul_pi, *, "2.01", "3.1415926535897932384626433832");
bench_decimal_op!(mul_negative_pi, *, "2.01", "-3.1415926535897932384626433832");
bench_fold_op!(mul_25, *, Decimal::from_str("1.1").unwrap(), 25);
/* Div */
bench_decimal_op!(div_one, /, "1");
bench_decimal_op!(div_two, /, "2");
bench_decimal_op!(div_one_hundred, /, "100");
bench_decimal_op!(div_point_zero_one, /, "0.01");
bench_decimal_op!(div_negative_point_five, /, "-0.5");
bench_decimal_op!(div_pi, /, "3.1415926535897932384626433832");
bench_decimal_op!(div_negative_pi, /, "-3.1415926535897932384626433832");
bench_fold_op!(div_10k, /, Decimal::max_value(), 10_000);
bench_decimal_op!(div_one, /, "2.01", "1");
bench_decimal_op!(div_two, /, "2.01", "2");
bench_decimal_op!(div_one_hundred, /, "2.01", "100");
bench_decimal_op!(div_point_zero_one, /, "2.01", "0.01");
bench_decimal_op!(div_negative_point_five, /, "2.01", "-0.5");
bench_decimal_op!(div_pi, /, "2.01", "3.1415926535897932384626433832");
bench_decimal_op!(div_negative_pi, /, "2.01", "-3.1415926535897932384626433832");
bench_decimal_op!(div_no_underflow, /, "1.02343545345", "0.35454343453");
bench_fold_op!(div_10k, /, Decimal::MAX, 10_000);
bench_fold_op!(rem_10k, %, Decimal::MAX, 10_000);
/* Iteration */
struct DecimalIterator {
@ -126,69 +134,218 @@ fn iterator_sum(b: &mut ::test::Bencher) {
});
}
const SAMPLE_STRS: &[&str] = &[
"3950.123456",
"3950",
"0.1",
"0.01",
"0.001",
"0.0001",
"0.00001",
"0.000001",
"1",
"-100",
"-123.456",
"119996.25",
"1000000",
"9999999.99999",
"12340.56789",
];
#[bench]
fn decimal_from_str(b: &mut test::Bencher) {
let samples_strs = &[
"3950.123456",
"3950",
"0.1",
"0.01",
"0.001",
"0.0001",
"0.00001",
"0.000001",
"1",
"-100",
"-123.456",
"119996.25",
"1000000",
"9999999.99999",
"12340.56789",
];
fn serialize_bincode(b: &mut test::Bencher) {
let decimals: Vec<Decimal> = SAMPLE_STRS.iter().map(|s| Decimal::from_str(s).unwrap()).collect();
b.iter(|| {
for s in samples_strs {
for d in &decimals {
let bytes = bincode::options().serialize(d).unwrap();
test::black_box(bytes);
}
})
}
#[cfg(feature = "serde-str")]
#[bench]
fn deserialize_bincode(b: &mut test::Bencher) {
let payloads: Vec<Vec<u8>> = SAMPLE_STRS
.iter()
.map(|s| bincode::options().serialize(&Decimal::from_str(s).unwrap()).unwrap())
.collect();
b.iter(|| {
for payload in &payloads {
let decimal: Decimal = bincode::options().deserialize(payload).unwrap();
test::black_box(decimal);
}
})
}
#[bench]
fn decimal_from_str(b: &mut test::Bencher) {
b.iter(|| {
for s in SAMPLE_STRS {
let result = Decimal::from_str(s).unwrap();
test::black_box(result);
}
})
}
#[bench]
fn decimal_to_string(b: &mut test::Bencher) {
let decimals: Vec<Decimal> = SAMPLE_STRS.iter().map(|s| Decimal::from_str(s).unwrap()).collect();
b.iter(|| {
for s in decimals.iter() {
let string = s.to_string();
test::black_box(string);
}
})
}
#[cfg(feature = "postgres")]
#[bench]
fn to_from_sql(b: &mut ::test::Bencher) {
use bytes::BytesMut;
use postgres::types::{FromSql, Kind, ToSql, Type};
let samples_strs = &[
"3950.123456",
"3950",
"0.1",
"0.01",
"0.001",
"0.0001",
"0.00001",
"0.000001",
"1",
"-100",
"-123.456",
"119996.25",
"1000000",
"9999999.99999",
"12340.56789",
];
let samples: Vec<Decimal> = test::black_box(samples_strs.iter().map(|x| Decimal::from_str(x).unwrap()).collect());
let t = Type::_new("".into(), 0, Kind::Simple, "".into());
let mut vec = Vec::<u8>::with_capacity(100);
let samples: Vec<Decimal> = test::black_box(SAMPLE_STRS.iter().map(|x| Decimal::from_str(x).unwrap()).collect());
let t = Type::new("".into(), 0, Kind::Simple, "".into());
let mut bytes: BytesMut = BytesMut::with_capacity(100).into();
b.iter(|| {
for _ in 0..100 {
for sample in &samples {
vec.clear();
sample.to_sql(&t, &mut vec).unwrap();
let result = Decimal::from_sql(&t, &vec).unwrap();
bytes.clear();
sample.to_sql(&t, &mut bytes).unwrap();
let result = Decimal::from_sql(&t, &bytes).unwrap();
::test::black_box(result);
}
}
});
}
#[cfg(feature = "maths")]
mod maths {
use rust_decimal::prelude::*;
#[bench]
fn powi(b: &mut ::test::Bencher) {
// These exponents have to be fairly small because multiplcation overflows easily
let samples = &[
(Decimal::from_str("36.7").unwrap(), 5),
(Decimal::from_str("0.00000007").unwrap(), 5),
(Decimal::from(2), 64),
(Decimal::from_str("8819287.19276555").unwrap(), 3),
(Decimal::from_str("-8819287.19276555").unwrap(), 3),
];
b.iter(|| {
for sample in samples.iter() {
let result = sample.0.powi(sample.1);
::test::black_box(result);
}
});
}
#[bench]
fn sqrt(b: &mut ::test::Bencher) {
let samples = &[
Decimal::from_str("36.7").unwrap(),
Decimal::from_str("0.00000007").unwrap(),
Decimal::from(2),
Decimal::from_str("8819287.19276555").unwrap(),
Decimal::from_str("-8819287.19276555").unwrap(),
];
b.iter(|| {
for sample in samples.iter() {
let result = sample.sqrt();
::test::black_box(result);
}
});
}
#[bench]
fn exp(b: &mut ::test::Bencher) {
let samples = &[
Decimal::from_str("3.7").unwrap(),
Decimal::from_str("0.07").unwrap(),
Decimal::from(2),
Decimal::from_str("8.19").unwrap(),
Decimal::from_str("-8.19").unwrap(),
];
b.iter(|| {
for sample in samples.iter() {
let result = sample.exp();
::test::black_box(result);
}
});
}
#[bench]
fn norm_cdf(b: &mut ::test::Bencher) {
let samples = &[
Decimal::from_str("3.7").unwrap(),
Decimal::from_str("0.007").unwrap(),
Decimal::from(2),
Decimal::from_str("1.19").unwrap(),
Decimal::from_str("-1.19").unwrap(),
];
b.iter(|| {
for sample in samples.iter() {
let result = sample.norm_cdf();
::test::black_box(result);
}
});
}
#[bench]
fn norm_pdf(b: &mut ::test::Bencher) {
let samples = &[
Decimal::from_str("3.7").unwrap(),
Decimal::from_str("0.007").unwrap(),
Decimal::from(2),
Decimal::from_str("1.19").unwrap(),
Decimal::from_str("-1.19").unwrap(),
];
b.iter(|| {
for sample in samples.iter() {
let result = sample.norm_pdf();
::test::black_box(result);
}
});
}
#[bench]
fn ln(b: &mut ::test::Bencher) {
let samples = &[
Decimal::from_str("36.7").unwrap(),
Decimal::from_str("0.00000007").unwrap(),
Decimal::from(2),
Decimal::from_str("8819287.19").unwrap(),
Decimal::from_str("-8819287.19").unwrap(),
];
b.iter(|| {
for sample in samples.iter() {
let result = sample.ln();
::test::black_box(result);
}
});
}
#[bench]
fn erf(b: &mut ::test::Bencher) {
let samples = &[
Decimal::from(0),
Decimal::from(1),
Decimal::from_str("-0.98717").unwrap(),
Decimal::from_str("0.07").unwrap(),
Decimal::from_str("0.1111").unwrap(),
Decimal::from_str("0.4").unwrap(),
];
b.iter(|| {
for sample in samples.iter() {
let result = sample.erf();
::test::black_box(result);
}
});
}
}

64
third_party/rust/rust_decimal/src/constants.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,64 @@
// Sign mask for the flags field. A value of zero in this bit indicates a
// positive Decimal value, and a value of one in this bit indicates a
// negative Decimal value.
pub const SIGN_MASK: u32 = 0x8000_0000;
pub const UNSIGN_MASK: u32 = 0x4FFF_FFFF;
// Scale mask for the flags field. This byte in the flags field contains
// the power of 10 to divide the Decimal value by. The scale byte must
// contain a value between 0 and 28 inclusive.
pub const SCALE_MASK: u32 = 0x00FF_0000;
pub const U8_MASK: u32 = 0x0000_00FF;
pub const U32_MASK: u64 = 0xFFFF_FFFF;
// Number of bits scale is shifted by.
pub const SCALE_SHIFT: u32 = 16;
// Number of bits sign is shifted by.
pub const SIGN_SHIFT: u32 = 31;
// The maximum string buffer size used for serialization purposes. 31 is optimal, however we align
// to the byte boundary for simplicity.
pub const MAX_STR_BUFFER_SIZE: usize = 32;
// The maximum supported precision
pub const MAX_PRECISION: u32 = 28;
#[cfg(not(feature = "legacy-ops"))]
pub const MAX_PRECISION_I32: i32 = 28;
// 79,228,162,514,264,337,593,543,950,335
pub const MAX_I128_REPR: i128 = 0x0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF;
// Fast access for 10^n where n is 0-9
pub const POWERS_10: [u32; 10] = [
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000,
];
// Fast access for 10^n where n is 1-19
pub const BIG_POWERS_10: [u64; 19] = [
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
10000000000,
100000000000,
1000000000000,
10000000000000,
100000000000000,
1000000000000000,
10000000000000000,
100000000000000000,
1000000000000000000,
10000000000000000000,
];
#[cfg(not(feature = "legacy-ops"))]
// The maximum power of 10 that a 32 bit integer can store
pub const MAX_I32_SCALE: i32 = 9;
#[cfg(not(feature = "legacy-ops"))]
// The maximum power of 10 that a 64 bit integer can store
pub const MAX_I64_SCALE: u32 = 19;
#[cfg(not(feature = "legacy-ops"))]
pub const U32_MAX: u64 = u32::MAX as u64;

Просмотреть файл

@ -1,10 +1,10 @@
use num_traits::Zero;
use crate::Decimal;
use std::{convert::TryInto, error, fmt, result::*};
use crate::decimal::{div_by_u32, is_all_zero, mul_by_u32, MAX_PRECISION};
use crate::constants::MAX_PRECISION;
use crate::{
ops::array::{div_by_u32, is_all_zero, mul_by_u32},
Decimal,
};
use core::{convert::TryInto, fmt};
use std::error;
#[derive(Debug, Clone)]
pub struct InvalidDecimal {
@ -38,13 +38,13 @@ impl Decimal {
digits,
weight,
}: PostgresDecimal<D>,
) -> Result<Self, InvalidDecimal> {
) -> Self {
let mut digits = digits.into_iter().collect::<Vec<_>>();
let fractionals_part_count = digits.len() as i32 + (-weight as i32) - 1;
let integers_part_count = weight as i32 + 1;
let mut result = Decimal::zero();
let mut result = Decimal::ZERO;
// adding integer part
if integers_part_count > 0 {
let (start_integers, last) = if integers_part_count > digits.len() as i32 {
@ -70,8 +70,7 @@ impl Decimal {
} else if fract_pow == MAX_PRECISION + 4 {
// rounding last digit
if digit >= 5000 {
result +=
Decimal::new(1 as i64, 0) / Decimal::from_i128_with_scale(10i128.pow(MAX_PRECISION), 0);
result += Decimal::new(1_i64, 0) / Decimal::from_i128_with_scale(10i128.pow(MAX_PRECISION), 0);
}
}
}
@ -80,8 +79,7 @@ impl Decimal {
result.set_sign_negative(neg);
// Rescale to the postgres value, automatically rounding as needed.
result.rescale(scale as u32);
Ok(result)
result
}
fn to_postgres(self) -> PostgresDecimal<Vec<i16>> {
@ -144,7 +142,6 @@ impl Decimal {
#[cfg(feature = "diesel")]
mod diesel {
use super::*;
use ::diesel::{
deserialize::{self, FromSql},
pg::data_types::PgNumeric,
@ -152,10 +149,8 @@ mod diesel {
serialize::{self, Output, ToSql},
sql_types::Numeric,
};
use ::std::{
convert::{TryFrom, TryInto},
io::Write,
};
use core::convert::{TryFrom, TryInto};
use std::io::Write;
impl<'a> TryFrom<&'a PgNumeric> for Decimal {
type Error = Box<dyn error::Error + Send + Sync>;
@ -180,8 +175,7 @@ mod diesel {
weight,
scale,
digits: digits.iter().copied().map(|v| v.try_into().unwrap()),
})
.map_err(Box::new)?)
}))
}
}
@ -194,11 +188,6 @@ mod diesel {
}
impl<'a> From<&'a Decimal> for PgNumeric {
// NOTE(clippy): Clippy suggests to replace the `.take_while(|i| i.is_zero())`
// with `.take_while(Zero::is_zero)`, but that's a false positive.
// The closure gets an `&&i16` due to autoderef `<i16 as Zero>::is_zero(&self) -> bool`
// is called. There is no impl for `&i16` that would work with this closure.
#[allow(clippy::assign_op_pattern, clippy::redundant_closure)]
fn from(decimal: &'a Decimal) -> Self {
let PostgresDecimal {
neg,
@ -207,8 +196,6 @@ mod diesel {
digits,
} = decimal.to_postgres();
let digits = digits.into_iter().map(|v| v.try_into().unwrap()).collect();
if neg {
PgNumeric::Negative { digits, scale, weight }
} else {
@ -239,7 +226,7 @@ mod diesel {
#[cfg(test)]
mod pg_tests {
use super::*;
use std::str::FromStr;
use core::str::FromStr;
#[test]
fn test_unnecessary_zeroes() {
@ -476,11 +463,10 @@ mod diesel {
#[cfg(feature = "postgres")]
mod postgres {
use super::*;
use ::byteorder::{BigEndian, ReadBytesExt};
use ::bytes::{BufMut, BytesMut};
use ::postgres::types::*;
use ::std::io::Cursor;
use ::postgres::types::{to_sql_checked, FromSql, IsNull, ToSql, Type};
use byteorder::{BigEndian, ReadBytesExt};
use bytes::{BufMut, BytesMut};
use std::io::Cursor;
impl<'a> FromSql<'a> for Decimal {
// Decimals are represented as follows:
@ -490,7 +476,7 @@ mod postgres {
// u16 sign (0x0000 = positive, 0x4000 = negative, 0xC000 = NaN)
// i16 dscale. Number of digits (in base 10) to print after decimal separator
//
// Psuedo code :
// Pseudo code :
// const Decimals [
// 0.0000000000000000000000000001,
// 0.000000000000000000000001,
@ -556,15 +542,11 @@ mod postgres {
weight,
scale,
digits: groups.into_iter(),
})
.map_err(Box::new)?)
}))
}
fn accepts(ty: &Type) -> bool {
match ty {
&Type::NUMERIC => true,
_ => false,
}
matches!(*ty, Type::NUMERIC)
}
}
@ -603,10 +585,7 @@ mod postgres {
}
fn accepts(ty: &Type) -> bool {
match ty {
&Type::NUMERIC => true,
_ => false,
}
matches!(*ty, Type::NUMERIC)
}
to_sql_checked!();
@ -615,10 +594,8 @@ mod postgres {
#[cfg(test)]
mod test {
use super::*;
use ::postgres::{Client, NoTls};
use std::str::FromStr;
use core::str::FromStr;
/// Gets the URL for connecting to PostgreSQL for testing. Set the POSTGRES_URL
/// environment variable to change from the default of "postgres://postgres@localhost".
@ -708,8 +685,8 @@ mod postgres {
#[tokio::test]
#[cfg(feature = "tokio-pg")]
async fn async_test_null() {
use ::futures::future::FutureExt;
use ::tokio_postgres::connect;
use futures::future::FutureExt;
use tokio_postgres::connect;
let (client, connection) = connect(&get_postgres_url(), NoTls).await.unwrap();
let connection = connection.map(|e| e.unwrap());
@ -748,8 +725,8 @@ mod postgres {
#[tokio::test]
#[cfg(feature = "tokio-pg")]
async fn async_read_numeric_type() {
use ::futures::future::FutureExt;
use ::tokio_postgres::connect;
use futures::future::FutureExt;
use tokio_postgres::connect;
let (client, connection) = connect(&get_postgres_url(), NoTls).await.unwrap();
let connection = connection.map(|e| e.unwrap());
@ -786,8 +763,8 @@ mod postgres {
#[tokio::test]
#[cfg(feature = "tokio-pg")]
async fn async_write_numeric_type() {
use ::futures::future::FutureExt;
use ::tokio_postgres::connect;
use futures::future::FutureExt;
use tokio_postgres::connect;
let (client, connection) = connect(&get_postgres_url(), NoTls).await.unwrap();
let connection = connection.map(|e| e.unwrap());
@ -829,8 +806,8 @@ mod postgres {
#[tokio::test]
#[cfg(feature = "tokio-pg")]
async fn async_numeric_overflow() {
use ::futures::future::FutureExt;
use ::tokio_postgres::connect;
use futures::future::FutureExt;
use tokio_postgres::connect;
let tests = [(4, 4, "3950.1234")];
let (client, connection) = connect(&get_postgres_url(), NoTls).await.unwrap();

2209
third_party/rust/rust_decimal/src/decimal.rs поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

59
third_party/rust/rust_decimal/src/error.rs поставляемый
Просмотреть файл

@ -1,31 +1,42 @@
use std::{error, fmt};
use crate::constants::MAX_PRECISION;
use alloc::string::String;
use core::fmt;
/// Error type for the library.
#[derive(Clone, Debug)]
pub struct Error {
message: String,
#[derive(Clone, Debug, PartialEq)]
pub enum Error {
ErrorString(String),
ExceedsMaximumPossibleValue,
LessThanMinimumPossibleValue,
ScaleExceedsMaximumPrecision(u32),
}
impl Error {
/// Instantiate an error with the specified error message.
///
/// This function is only available within the crate as there should never
/// be a need to create this error outside of the library.
pub(crate) fn new<S: Into<String>>(message: S) -> Error {
Error {
message: message.into(),
impl<S> From<S> for Error
where
S: Into<String>,
{
#[inline]
fn from(from: S) -> Self {
Self::ErrorString(from.into())
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::ErrorString(ref err) => f.pad(&err),
Self::ExceedsMaximumPossibleValue => {
write!(f, "Number exceeds maximum value that can be represented.")
}
Self::LessThanMinimumPossibleValue => {
write!(f, "Number less than minimum value that can be represented.")
}
Self::ScaleExceedsMaximumPrecision(ref scale) => {
write!(f, "Scale exceeds maximum precision: {} > {}", scale, MAX_PRECISION)
}
}
}
}
impl error::Error for Error {
fn description(&self) -> &str {
&self.message
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.pad(&self.message)
}
}

14
third_party/rust/rust_decimal/src/fuzz.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,14 @@
use crate::Decimal;
use arbitrary::{Arbitrary, Result as ArbitraryResult, Unstructured};
impl Arbitrary<'_> for crate::Decimal {
fn arbitrary(u: &mut Unstructured<'_>) -> ArbitraryResult<Self> {
let lo = u32::arbitrary(u)?;
let mid = u32::arbitrary(u)?;
let hi = u32::arbitrary(u)?;
let negative = bool::arbitrary(u)?;
let scale = u32::arbitrary(u)?;
Ok(Decimal::from_parts(lo, mid, hi, negative, scale))
}
}

176
third_party/rust/rust_decimal/src/lib.rs поставляемый
Просмотреть файл

@ -9,48 +9,186 @@
//! preserved and may be exposed when in string form. These can be
//! truncated using the `normalize` or `round_dp` functions.
//!
//! ## Getting started
//!
//! To get started, add `rust_decimal` and optionally `rust_decimal_macros` to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! rust_decimal = "1.14"
//! rust_decimal_macros = "1.14"
//! ```
//!
//! ## Usage
//!
//! Decimal numbers can be created in a few distinct ways, depending
//! on the rust compiler version you're targeting.
//! Decimal numbers can be created in a few distinct ways. The easiest and most optimal
//! method of creating a Decimal is to use the procedural macro within the
//! `rust_decimal_macros` crate:
//!
//! The stable version of rust requires you to create a Decimal number
//! using one of it's convenience methods.
//! ```ignore
//! // Procedural macros need importing directly
//! use rust_decimal_macros::dec;
//!
//! let number = dec!(-1.23);
//! assert_eq!("-1.23", number.to_string());
//! ```
//!
//! Alternatively you can also use one of the Decimal number convenience functions:
//!
//! ```rust
//! // Using the prelude can help importing trait based functions (e.g. core::str::FromStr).
//! use rust_decimal::prelude::*;
//!
//! // Using an integer followed by the decimal points
//! let scaled = Decimal::new(202, 2);
//! assert_eq!("2.02", scaled.to_string());
//!
//! // From a string representation
//! let from_string = Decimal::from_str("2.02").unwrap();
//! assert_eq!("2.02", from_string.to_string());
//!
//! // From a string representation in a different base
//! let from_string_base16 = Decimal::from_str_radix("ffff", 16).unwrap();
//! assert_eq!("65535", from_string_base16.to_string());
//!
//! // Using the `Into` trait
//! let my_int: Decimal = 3i32.into();
//! assert_eq!("3", my_int.to_string());
//!
//! // Using the raw decimal representation
//! let pi = Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28);
//! assert_eq!("3.1415926535897932384626433832", pi.to_string());
//! ```
//!
//! Once you have instantiated your `Decimal` number you can perform calculations with it just like any other number:
//!
//! ```rust
//! use rust_decimal::prelude::*;
//!
//! // Using an integer followed by the decimal points
//! let scaled = Decimal::new(202, 2); // 2.02
//!
//! // From a string representation
//! let from_string = Decimal::from_str("2.02").unwrap(); // 2.02
//!
//! // Using the `Into` trait
//! let my_int : Decimal = 3i32.into();
//!
//! // Using the raw decimal representation
//! // 3.1415926535897932384626433832
//! let pi = Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28);
//! let amount = Decimal::from_str("25.12").unwrap();
//! let tax = Decimal::from_str("0.085").unwrap();
//! let total = amount + (amount * tax).round_dp(2);
//! assert_eq!(total.to_string(), "27.26");
//! ```
//!
//! ## Features
//!
//! * [c-repr](#c-repr)
//! * [db-postgres](#db-postgres)
//! * [db-tokio-postgres](#db-tokio-postgres)
//! * [db-diesel-postgres](#db-diesel-postgres)
//! * [legacy-ops](#legacy-ops)
//! * [maths](#maths)
//! * [rust-fuzz](#rust-fuzz)
//! * [serde-float](#serde-float)
//! * [serde-str](#serde-str)
//! * [serde-arbitrary-precision](#serde-arbitrary-precision)
//! * [std](#std)
//!
//! ## `c-repr`
//!
//! Forces `Decimal` to use `[repr(C)]`. The corresponding target layout is 128 bit aligned.
//!
//! ## `db-postgres`
//!
//! This feature enables a PostgreSQL communication module. It allows for reading and writing the `Decimal`
//! type by transparently serializing/deserializing into the `NUMERIC` data type within PostgreSQL.
//!
//! ## `db-tokio-postgres`
//!
//! Enables the tokio postgres module allowing for async communication with PostgreSQL.
//!
//! ## `db-diesel-postgres`
//!
//! Enable `diesel` PostgreSQL support.
//!
//! ## `legacy-ops`
//!
//! As of `1.10` the algorithms used to perform basic operations have changed which has benefits of significant speed improvements.
//! To maintain backwards compatibility this can be opted out of by enabling the `legacy-ops` feature.
//!
//! ## `maths`
//!
//! The `maths` feature enables additional complex mathematical functions such as `pow`, `ln`, `enf`, `exp` etc.
//! Documentation detailing the additional functions can be found on the
//! [`MathematicalOps`](https://docs.rs/rust_decimal/latest/rust_decimal/trait.MathematicalOps.html) trait.
//!
//! ## `rust-fuzz`
//!
//! Enable `rust-fuzz` support by implementing the `Arbitrary` trait.
//!
//! ## `serde-float`
//!
//! Enable this so that JSON serialization of `Decimal` types are sent as a float instead of a string (default).
//!
//! e.g. with this turned on, JSON serialization would output:
//! ```json
//! {
//! "value": 1.234
//! }
//! ```
//!
//! ## `serde-str`
//!
//! This is typically useful for `bincode` or `csv` like implementations.
//!
//! Since `bincode` does not specify type information, we need to ensure that a type hint is provided in order to
//! correctly be able to deserialize. Enabling this feature on its own will force deserialization to use `deserialize_str`
//! instead of `deserialize_any`.
//!
//! If, for some reason, you also have `serde-float` enabled then this will use `deserialize_f64` as a type hint. Because
//! converting to `f64` _loses_ precision, it's highly recommended that you do NOT enable this feature when working with
//! `bincode`. That being said, this will only use 8 bytes so is slightly more efficient in terms of storage size.
//!
//! ## `serde-arbitrary-precision`
//!
//! This is used primarily with `serde_json` and consequently adds it as a "weak dependency". This supports the
//! `arbitrary_precision` feature inside `serde_json` when parsing decimals.
//!
//! This is recommended when parsing "float" looking data as it will prevent data loss.
//!
//! ## `std`
//!
//! Enable `std` library support. This is enabled by default, however in the future will be opt in. For now, to support `no_std`
//! libraries, this crate can be compiled with `--no-default-features`.
//!
#![forbid(unsafe_code)]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
mod constants;
mod decimal;
mod error;
mod ops;
mod str;
#[cfg(any(feature = "postgres", feature = "diesel"))]
mod postgres;
mod db;
#[cfg(feature = "rust-fuzz")]
mod fuzz;
#[cfg(feature = "maths")]
mod maths;
#[cfg(feature = "serde")]
mod serde_types;
mod serde;
pub use decimal::{Decimal, RoundingStrategy};
pub use error::Error;
#[cfg(feature = "maths")]
pub use maths::MathematicalOps;
/// A convenience module appropriate for glob imports (`use rust_decimal::prelude::*;`).
pub mod prelude {
#[cfg(feature = "maths")]
pub use crate::maths::MathematicalOps;
pub use crate::{Decimal, RoundingStrategy};
pub use core::str::FromStr;
pub use num_traits::{FromPrimitive, One, ToPrimitive, Zero};
pub use std::str::FromStr;
}
#[cfg(feature = "diesel")]
#[macro_use]
extern crate diesel;
/// Shortcut for `core::result::Result<T, rust_decimal::Error>`. Useful to distinguish
/// between `rust_decimal` and `std` types.
pub type Result<T> = core::result::Result<T, Error>;

522
third_party/rust/rust_decimal/src/maths.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,522 @@
use crate::prelude::*;
use num_traits::pow::Pow;
const TWO: Decimal = Decimal::from_parts_raw(2, 0, 0, 0);
const PI: Decimal = Decimal::from_parts_raw(1102470953, 185874565, 1703060790, 1835008);
const EXP_TOLERANCE: Decimal = Decimal::from_parts(2, 0, 0, false, 7);
// Table representing {index}!
const FACTORIAL: [Decimal; 28] = [
Decimal::from_parts(1, 0, 0, false, 0),
Decimal::from_parts(1, 0, 0, false, 0),
Decimal::from_parts(2, 0, 0, false, 0),
Decimal::from_parts(6, 0, 0, false, 0),
Decimal::from_parts(24, 0, 0, false, 0),
// 5!
Decimal::from_parts(120, 0, 0, false, 0),
Decimal::from_parts(720, 0, 0, false, 0),
Decimal::from_parts(5040, 0, 0, false, 0),
Decimal::from_parts(40320, 0, 0, false, 0),
Decimal::from_parts(362880, 0, 0, false, 0),
// 10!
Decimal::from_parts(3628800, 0, 0, false, 0),
Decimal::from_parts(39916800, 0, 0, false, 0),
Decimal::from_parts(479001600, 0, 0, false, 0),
Decimal::from_parts(1932053504, 1, 0, false, 0),
Decimal::from_parts(1278945280, 20, 0, false, 0),
// 15!
Decimal::from_parts(2004310016, 304, 0, false, 0),
Decimal::from_parts(2004189184, 4871, 0, false, 0),
Decimal::from_parts(4006445056, 82814, 0, false, 0),
Decimal::from_parts(3396534272, 1490668, 0, false, 0),
Decimal::from_parts(109641728, 28322707, 0, false, 0),
// 20!
Decimal::from_parts(2192834560, 566454140, 0, false, 0),
Decimal::from_parts(3099852800, 3305602358, 2, false, 0),
Decimal::from_parts(3772252160, 4003775155, 60, false, 0),
Decimal::from_parts(862453760, 1892515369, 1401, false, 0),
Decimal::from_parts(3519021056, 2470695900, 33634, false, 0),
// 25!
Decimal::from_parts(2076180480, 1637855376, 840864, false, 0),
Decimal::from_parts(2441084928, 3929534124, 21862473, false, 0),
Decimal::from_parts(1484783616, 3018206259, 590286795, false, 0),
];
/// Trait exposing various mathematical operations that can be applied using a Decimal. This is only
/// present when the `maths` feature has been enabled.
pub trait MathematicalOps {
/// The estimated exponential function, e<sup>x</sup>. Stops calculating when it is within
/// tolerance of roughly `0.0000002`.
fn exp(&self) -> Decimal;
/// The estimated exponential function, e<sup>x</sup>. Stops calculating when it is within
/// tolerance of roughly `0.0000002`. Returns `None` on overflow.
fn checked_exp(&self) -> Option<Decimal>;
/// The estimated exponential function, e<sup>x</sup> using the `tolerance` provided as a hint
/// as to when to stop calculating. A larger tolerance will cause the number to stop calculating
/// sooner at the potential cost of a slightly less accurate result.
fn exp_with_tolerance(&self, tolerance: Decimal) -> Decimal;
/// The estimated exponential function, e<sup>x</sup> using the `tolerance` provided as a hint
/// as to when to stop calculating. A larger tolerance will cause the number to stop calculating
/// sooner at the potential cost of a slightly less accurate result.
/// Returns `None` on overflow.
fn checked_exp_with_tolerance(&self, tolerance: Decimal) -> Option<Decimal>;
/// Raise self to the given integer exponent: x<sup>y</sup>
fn powi(&self, exp: i64) -> Decimal;
/// Raise self to the given integer exponent x<sup>y</sup> returning `None` on overflow.
fn checked_powi(&self, exp: i64) -> Option<Decimal>;
/// Raise self to the given unsigned integer exponent: x<sup>y</sup>
fn powu(&self, exp: u64) -> Decimal;
/// Raise self to the given unsigned integer exponent x<sup>y</sup> returning `None` on overflow.
fn checked_powu(&self, exp: u64) -> Option<Decimal>;
/// Raise self to the given floating point exponent: x<sup>y</sup>
fn powf(&self, exp: f64) -> Decimal;
/// Raise self to the given floating point exponent x<sup>y</sup> returning `None` on overflow.
fn checked_powf(&self, exp: f64) -> Option<Decimal>;
/// Raise self to the given Decimal exponent: x<sup>y</sup>. If `exp` is not whole then the approximation
/// e<sup>y*ln(x)</sup> is used.
fn powd(&self, exp: Decimal) -> Decimal;
/// Raise self to the given Decimal exponent x<sup>y</sup> returning `None` on overflow.
/// If `exp` is not whole then the approximation e<sup>y*ln(x)</sup> is used.
fn checked_powd(&self, exp: Decimal) -> Option<Decimal>;
/// The square root of a Decimal. Uses a standard Babylonian method.
fn sqrt(&self) -> Option<Decimal>;
/// The natural logarithm for a Decimal. Uses a [fast estimation algorithm](https://en.wikipedia.org/wiki/Natural_logarithm#High_precision)
/// This is more accurate on larger numbers and less on numbers less than 1.
fn ln(&self) -> Decimal;
/// Abramowitz Approximation of Error Function from [wikipedia](https://en.wikipedia.org/wiki/Error_function#Numerical_approximations)
fn erf(&self) -> Decimal;
/// The Cumulative distribution function for a Normal distribution
fn norm_cdf(&self) -> Decimal;
/// The Probability density function for a Normal distribution.
fn norm_pdf(&self) -> Decimal;
/// The Probability density function for a Normal distribution returning `None` on overflow.
fn checked_norm_pdf(&self) -> Option<Decimal>;
}
impl MathematicalOps for Decimal {
fn exp(&self) -> Decimal {
self.exp_with_tolerance(EXP_TOLERANCE)
}
fn checked_exp(&self) -> Option<Decimal> {
self.checked_exp_with_tolerance(EXP_TOLERANCE)
}
fn exp_with_tolerance(&self, tolerance: Decimal) -> Decimal {
match self.checked_exp_with_tolerance(tolerance) {
Some(d) => d,
None => {
if self.is_sign_negative() {
panic!("Exp underflowed")
} else {
panic!("Exp overflowed")
}
}
}
}
fn checked_exp_with_tolerance(&self, tolerance: Decimal) -> Option<Decimal> {
if self.is_zero() {
return Some(Decimal::ONE);
}
if self.is_sign_negative() {
let mut flipped = *self;
flipped.set_sign_positive(true);
let exp = flipped.checked_exp_with_tolerance(tolerance)?;
return Decimal::ONE.checked_div(exp);
}
let mut term = *self;
let mut result = self + Decimal::ONE;
for factorial in FACTORIAL.iter().skip(2) {
term = self.checked_mul(term)?;
let next = result + (term / factorial);
let diff = (next - result).abs();
result = next;
if diff <= tolerance {
break;
}
}
Some(result)
}
fn powi(&self, exp: i64) -> Decimal {
match self.checked_powi(exp) {
Some(result) => result,
None => panic!("Pow overflowed"),
}
}
fn checked_powi(&self, exp: i64) -> Option<Decimal> {
// For negative exponents we change x^-y into 1 / x^y.
// Otherwise, we calculate a standard unsigned exponent
if exp >= 0 {
return self.checked_powu(exp as u64);
}
// Get the unsigned exponent
let exp = exp.unsigned_abs();
let pow = match self.checked_powu(exp) {
Some(v) => v,
None => return None,
};
Decimal::ONE.checked_div(pow)
}
fn powu(&self, exp: u64) -> Decimal {
match self.checked_powu(exp) {
Some(result) => result,
None => panic!("Pow overflowed"),
}
}
fn checked_powu(&self, exp: u64) -> Option<Decimal> {
match exp {
0 => Some(Decimal::ONE),
1 => Some(*self),
2 => self.checked_mul(*self),
_ => {
// Get the squared value
let squared = match self.checked_mul(*self) {
Some(s) => s,
None => return None,
};
// Square self once and make an infinite sized iterator of the square.
let iter = core::iter::repeat(squared);
// We then take half of the exponent to create a finite iterator and then multiply those together.
let mut product = Decimal::ONE;
for x in iter.take((exp >> 1) as usize) {
match product.checked_mul(x) {
Some(r) => product = r,
None => return None,
};
}
// If the exponent is odd we still need to multiply once more
if exp & 0x1 > 0 {
match self.checked_mul(product) {
Some(p) => product = p,
None => return None,
}
}
product.normalize_assign();
Some(product)
}
}
}
fn powf(&self, exp: f64) -> Decimal {
match self.checked_powf(exp) {
Some(result) => result,
None => panic!("Pow overflowed"),
}
}
fn checked_powf(&self, exp: f64) -> Option<Decimal> {
let exp = match Decimal::from_f64(exp) {
Some(f) => f,
None => return None,
};
self.checked_powd(exp)
}
fn powd(&self, exp: Decimal) -> Decimal {
match self.checked_powd(exp) {
Some(result) => result,
None => panic!("Pow overflowed"),
}
}
fn checked_powd(&self, exp: Decimal) -> Option<Decimal> {
if exp.is_zero() {
return Some(Decimal::ONE);
}
if self.is_zero() {
return Some(Decimal::ZERO);
}
if self.is_one() {
return Some(Decimal::ONE);
}
if exp.is_one() {
return Some(*self);
}
// If the scale is 0 then it's a trivial calculation
let exp = exp.normalize();
if exp.scale() == 0 {
if exp.mid() != 0 || exp.hi() != 0 {
// Exponent way too big
return None;
}
if exp.is_sign_negative() {
return self.checked_powi(-(exp.lo() as i64));
} else {
return self.checked_powu(exp.lo() as u64);
}
}
// We do some approximations since we've got a decimal exponent.
// For positive bases: a^b = exp(b*ln(a))
let negative = self.is_sign_negative();
let e = match self.abs().ln().checked_mul(exp) {
Some(e) => e,
None => return None,
};
let mut result = e.checked_exp()?;
result.set_sign_negative(negative);
Some(result)
}
fn sqrt(&self) -> Option<Decimal> {
if self.is_sign_negative() {
return None;
}
if self.is_zero() {
return Some(Decimal::ZERO);
}
// Start with an arbitrary number as the first guess
let mut result = self / TWO;
// Too small to represent, so we start with self
// Future iterations could actually avoid using a decimal altogether and use a buffered
// vector, only combining back into a decimal on return
if result.is_zero() {
result = *self;
}
let mut last = result + Decimal::ONE;
// Keep going while the difference is larger than the tolerance
let mut circuit_breaker = 0;
while last != result {
circuit_breaker += 1;
assert!(circuit_breaker < 1000, "geo mean circuit breaker");
last = result;
result = (result + self / result) / TWO;
}
Some(result)
}
fn ln(&self) -> Decimal {
const C4: Decimal = Decimal::from_parts_raw(4, 0, 0, 0);
const C256: Decimal = Decimal::from_parts_raw(256, 0, 0, 0);
const EIGHT_LN2: Decimal = Decimal::from_parts(1406348788, 262764557, 3006046716, false, 28);
if self.is_sign_positive() {
if *self == Decimal::ONE {
Decimal::ZERO
} else {
let rhs = C4 / (self * C256);
let arith_geo_mean = arithmetic_geo_mean_of_2(&Decimal::ONE, &rhs);
(PI / (arith_geo_mean * TWO)) - EIGHT_LN2
}
} else {
Decimal::ZERO
}
}
fn erf(&self) -> Decimal {
if self.is_sign_positive() {
let one = &Decimal::ONE;
let xa1 = self * Decimal::from_parts(705230784, 0, 0, false, 10);
let xa2 = self.powi(2) * Decimal::from_parts(422820123, 0, 0, false, 10);
let xa3 = self.powi(3) * Decimal::from_parts(92705272, 0, 0, false, 10);
let xa4 = self.powi(4) * Decimal::from_parts(1520143, 0, 0, false, 10);
let xa5 = self.powi(5) * Decimal::from_parts(2765672, 0, 0, false, 10);
let xa6 = self.powi(6) * Decimal::from_parts(430638, 0, 0, false, 10);
let sum = one + xa1 + xa2 + xa3 + xa4 + xa5 + xa6;
one - (one / sum.powi(16))
} else {
-self.abs().erf()
}
}
fn norm_cdf(&self) -> Decimal {
(Decimal::ONE + (self / Decimal::from_parts(2318911239, 3292722, 0, false, 16)).erf()) / TWO
}
fn norm_pdf(&self) -> Decimal {
match self.checked_norm_pdf() {
Some(d) => d,
None => panic!("Norm Pdf overflowed"),
}
}
fn checked_norm_pdf(&self) -> Option<Decimal> {
let sqrt2pi = Decimal::from_parts_raw(2133383024, 2079885984, 1358845910, 1835008);
let factor = -self.checked_powi(2)?;
let factor = factor.checked_div(TWO)?;
factor.checked_exp()?.checked_div(sqrt2pi)
}
}
impl Pow<Decimal> for Decimal {
type Output = Decimal;
fn pow(self, rhs: Decimal) -> Self::Output {
MathematicalOps::powd(&self, rhs)
}
}
impl Pow<u64> for Decimal {
type Output = Decimal;
fn pow(self, rhs: u64) -> Self::Output {
MathematicalOps::powu(&self, rhs)
}
}
impl Pow<i64> for Decimal {
type Output = Decimal;
fn pow(self, rhs: i64) -> Self::Output {
MathematicalOps::powi(&self, rhs)
}
}
impl Pow<f64> for Decimal {
type Output = Decimal;
fn pow(self, rhs: f64) -> Self::Output {
MathematicalOps::powf(&self, rhs)
}
}
/// Returns the convergence of both the arithmetic and geometric mean.
/// Used internally.
fn arithmetic_geo_mean_of_2(a: &Decimal, b: &Decimal) -> Decimal {
const TOLERANCE: Decimal = Decimal::from_parts(5, 0, 0, false, 7);
let diff = (a - b).abs();
if diff < TOLERANCE {
*a
} else {
arithmetic_geo_mean_of_2(&mean_of_2(a, b), &geo_mean_of_2(a, b))
}
}
/// The Arithmetic mean. Used internally.
fn mean_of_2(a: &Decimal, b: &Decimal) -> Decimal {
(a + b) / TWO
}
/// The geometric mean. Used internally.
fn geo_mean_of_2(a: &Decimal, b: &Decimal) -> Decimal {
// TODO: This can overflow unnecessarily. We should keep this in an internal representation until
// absolutely necessary to convert back.
(a * b).sqrt().unwrap()
}
#[cfg(test)]
mod test {
use super::*;
use std::str::FromStr;
#[test]
fn factorials() {
assert_eq!("1", FACTORIAL[0].to_string(), "0!");
assert_eq!("1", FACTORIAL[1].to_string(), "1!");
assert_eq!("2", FACTORIAL[2].to_string(), "2!");
assert_eq!("6", FACTORIAL[3].to_string(), "3!");
assert_eq!("24", FACTORIAL[4].to_string(), "4!");
assert_eq!("120", FACTORIAL[5].to_string(), "5!");
assert_eq!("720", FACTORIAL[6].to_string(), "6!");
assert_eq!("5040", FACTORIAL[7].to_string(), "7!");
assert_eq!("40320", FACTORIAL[8].to_string(), "8!");
assert_eq!("362880", FACTORIAL[9].to_string(), "9!");
assert_eq!("3628800", FACTORIAL[10].to_string(), "10!");
assert_eq!("39916800", FACTORIAL[11].to_string(), "11!");
assert_eq!("479001600", FACTORIAL[12].to_string(), "12!");
assert_eq!("6227020800", FACTORIAL[13].to_string(), "13!");
assert_eq!("87178291200", FACTORIAL[14].to_string(), "14!");
assert_eq!("1307674368000", FACTORIAL[15].to_string(), "15!");
assert_eq!("20922789888000", FACTORIAL[16].to_string(), "16!");
assert_eq!("355687428096000", FACTORIAL[17].to_string(), "17!");
assert_eq!("6402373705728000", FACTORIAL[18].to_string(), "18!");
assert_eq!("121645100408832000", FACTORIAL[19].to_string(), "19!");
assert_eq!("2432902008176640000", FACTORIAL[20].to_string(), "20!");
assert_eq!("51090942171709440000", FACTORIAL[21].to_string(), "21!");
assert_eq!("1124000727777607680000", FACTORIAL[22].to_string(), "22!");
assert_eq!("25852016738884976640000", FACTORIAL[23].to_string(), "23!");
assert_eq!("620448401733239439360000", FACTORIAL[24].to_string(), "24!");
assert_eq!("15511210043330985984000000", FACTORIAL[25].to_string(), "25!");
assert_eq!("403291461126605635584000000", FACTORIAL[26].to_string(), "26!");
assert_eq!("10888869450418352160768000000", FACTORIAL[27].to_string(), "27!");
}
#[test]
fn test_geo_mean_of_2() {
let test_cases = &[
(
Decimal::from_str("2").unwrap(),
Decimal::from_str("2").unwrap(),
Decimal::from_str("2").unwrap(),
),
(
Decimal::from_str("4").unwrap(),
Decimal::from_str("3").unwrap(),
Decimal::from_str("3.4641016151377545870548926830").unwrap(),
),
(
Decimal::from_str("12").unwrap(),
Decimal::from_str("3").unwrap(),
Decimal::from_str("6.000000000000000000000000000").unwrap(),
),
];
for case in test_cases {
assert_eq!(case.2, geo_mean_of_2(&case.0, &case.1));
}
}
#[test]
fn test_mean_of_2() {
let test_cases = &[
(
Decimal::from_str("2").unwrap(),
Decimal::from_str("2").unwrap(),
Decimal::from_str("2").unwrap(),
),
(
Decimal::from_str("4").unwrap(),
Decimal::from_str("3").unwrap(),
Decimal::from_str("3.5").unwrap(),
),
(
Decimal::from_str("12").unwrap(),
Decimal::from_str("3").unwrap(),
Decimal::from_str("7.5").unwrap(),
),
];
for case in test_cases {
assert_eq!(case.2, mean_of_2(&case.0, &case.1));
}
}
}

34
third_party/rust/rust_decimal/src/ops.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,34 @@
// This code (in fact, this library) is heavily inspired by the dotnet Decimal number library
// implementation. Consequently, a huge thank you for to all the contributors to that project
// whose work has also inspired the solutions found here.
pub(crate) mod array;
#[cfg(feature = "legacy-ops")]
mod legacy;
#[cfg(feature = "legacy-ops")]
pub(crate) use legacy::{add_impl, cmp_impl, div_impl, mul_impl, rem_impl, sub_impl};
#[cfg(not(feature = "legacy-ops"))]
mod add;
#[cfg(not(feature = "legacy-ops"))]
mod cmp;
#[cfg(not(feature = "legacy-ops"))]
pub(in crate::ops) mod common;
#[cfg(not(feature = "legacy-ops"))]
mod div;
#[cfg(not(feature = "legacy-ops"))]
mod mul;
#[cfg(not(feature = "legacy-ops"))]
mod rem;
#[cfg(not(feature = "legacy-ops"))]
pub(crate) use add::{add_impl, sub_impl};
#[cfg(not(feature = "legacy-ops"))]
pub(crate) use cmp::cmp_impl;
#[cfg(not(feature = "legacy-ops"))]
pub(crate) use div::div_impl;
#[cfg(not(feature = "legacy-ops"))]
pub(crate) use mul::mul_impl;
#[cfg(not(feature = "legacy-ops"))]
pub(crate) use rem::rem_impl;

382
third_party/rust/rust_decimal/src/ops/add.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,382 @@
use crate::constants::{MAX_I32_SCALE, POWERS_10, SCALE_MASK, SCALE_SHIFT, SIGN_MASK, U32_MASK, U32_MAX};
use crate::decimal::{CalculationResult, Decimal};
use crate::ops::common::{Buf24, Dec64};
pub(crate) fn add_impl(d1: &Decimal, d2: &Decimal) -> CalculationResult {
add_sub_internal(d1, d2, false)
}
pub(crate) fn sub_impl(d1: &Decimal, d2: &Decimal) -> CalculationResult {
add_sub_internal(d1, d2, true)
}
#[inline]
fn add_sub_internal(d1: &Decimal, d2: &Decimal, subtract: bool) -> CalculationResult {
if d1.is_zero() {
// 0 - x or 0 + x
let mut result = *d2;
if subtract && !d2.is_zero() {
result.set_sign_negative(d2.is_sign_positive());
}
return CalculationResult::Ok(result);
}
if d2.is_zero() {
// x - 0 or x + 0
return CalculationResult::Ok(*d1);
}
// Work out whether we need to rescale and/or if it's a subtract still given the signs of the
// numbers.
let flags = d1.flags() ^ d2.flags();
let subtract = subtract ^ ((flags & SIGN_MASK) != 0);
let rescale = (flags & SCALE_MASK) > 0;
// We optimize towards using 32 bit logic as much as possible. It's noticeably faster at
// scale, even on 64 bit machines
if d1.mid() | d1.hi() == 0 && d2.mid() | d2.hi() == 0 {
// We'll try to rescale, however we may end up with 64 bit (or more) numbers
// If we do, we'll choose a different flow than fast_add
if rescale {
// This is less optimized if we scale to a 64 bit integer. We can add some further logic
// here later on.
let rescale_factor = ((d2.flags() & SCALE_MASK) as i32 - (d1.flags() & SCALE_MASK) as i32) >> SCALE_SHIFT;
if rescale_factor < 0 {
// We try to rescale the rhs
if let Some(rescaled) = rescale32(d2.lo(), -rescale_factor) {
return fast_add(d1.lo(), rescaled, d1.flags(), subtract);
}
} else {
// We try to rescale the lhs
if let Some(rescaled) = rescale32(d1.lo(), rescale_factor) {
return fast_add(
rescaled,
d2.lo(),
(d2.flags() & SCALE_MASK) | (d1.flags() & SIGN_MASK),
subtract,
);
}
}
} else {
return fast_add(d1.lo(), d2.lo(), d1.flags(), subtract);
}
}
// Continue on with the slower 64 bit method
let d1 = Dec64::new(d1);
let d2 = Dec64::new(d2);
// If we're not the same scale then make sure we're there first before starting addition
if rescale {
let rescale_factor = d2.scale as i32 - d1.scale as i32;
if rescale_factor < 0 {
let negative = subtract ^ d1.negative;
let scale = d1.scale;
unaligned_add(d2, d1, negative, scale, -rescale_factor, subtract)
} else {
let negative = d1.negative;
let scale = d2.scale;
unaligned_add(d1, d2, negative, scale, rescale_factor, subtract)
}
} else {
let neg = d1.negative;
let scale = d1.scale;
aligned_add(d1, d2, neg, scale, subtract)
}
}
#[inline(always)]
fn rescale32(num: u32, rescale_factor: i32) -> Option<u32> {
if rescale_factor > MAX_I32_SCALE {
return None;
}
num.checked_mul(POWERS_10[rescale_factor as usize])
}
fn fast_add(lo1: u32, lo2: u32, flags: u32, subtract: bool) -> CalculationResult {
if subtract {
// Sub can't overflow because we're ensuring the bigger number always subtracts the smaller number
if lo1 < lo2 {
return CalculationResult::Ok(Decimal::from_parts_raw(lo2 - lo1, 0, 0, flags ^ SIGN_MASK));
}
return CalculationResult::Ok(Decimal::from_parts_raw(lo1 - lo2, 0, 0, flags));
}
// Add can overflow however, so we check for that explicitly
let lo = lo1.wrapping_add(lo2);
let mid = if lo < lo1 { 1 } else { 0 };
CalculationResult::Ok(Decimal::from_parts_raw(lo, mid, 0, flags))
}
fn aligned_add(lhs: Dec64, rhs: Dec64, negative: bool, scale: u32, subtract: bool) -> CalculationResult {
if subtract {
// Signs differ, so subtract
let mut result = Dec64 {
negative,
scale,
low64: lhs.low64.wrapping_sub(rhs.low64),
hi: lhs.hi.wrapping_sub(rhs.hi),
};
// Check for carry
if result.low64 > lhs.low64 {
result.hi = result.hi.wrapping_sub(1);
if result.hi >= lhs.hi {
flip_sign(&mut result);
}
} else if result.hi > lhs.hi {
flip_sign(&mut result);
}
CalculationResult::Ok(result.to_decimal())
} else {
// Signs are the same, so add
let mut result = Dec64 {
negative,
scale,
low64: lhs.low64.wrapping_add(rhs.low64),
hi: lhs.hi.wrapping_add(rhs.hi),
};
// Check for carry
if result.low64 < lhs.low64 {
result.hi = result.hi.wrapping_add(1);
if result.hi <= lhs.hi {
if result.scale == 0 {
return CalculationResult::Overflow;
}
reduce_scale(&mut result);
}
} else if result.hi < lhs.hi {
if result.scale == 0 {
return CalculationResult::Overflow;
}
reduce_scale(&mut result);
}
CalculationResult::Ok(result.to_decimal())
}
}
fn flip_sign(result: &mut Dec64) {
// Bitwise not the high portion
result.hi = !result.hi;
let low64 = ((result.low64 as i64).wrapping_neg()) as u64;
if low64 == 0 {
result.hi += 1;
}
result.low64 = low64;
result.negative = !result.negative;
}
fn reduce_scale(result: &mut Dec64) {
let mut low64 = result.low64;
let mut hi = result.hi;
let mut num = (hi as u64) + (1u64 << 32);
hi = (num / 10u64) as u32;
num = ((num - (hi as u64) * 10u64) << 32) + (low64 >> 32);
let mut div = (num / 10) as u32;
num = ((num - (div as u64) * 10u64) << 32) + (low64 & U32_MASK);
low64 = (div as u64) << 32;
div = (num / 10u64) as u32;
low64 = low64.wrapping_add(div as u64);
let remainder = (num as u32).wrapping_sub(div.wrapping_mul(10));
// Finally, round. This is optimizing slightly toward non-rounded numbers
if remainder >= 5 && (remainder > 5 || (low64 & 1) > 0) {
low64 = low64.wrapping_add(1);
if low64 == 0 {
hi += 1;
}
}
result.low64 = low64;
result.hi = hi;
result.scale -= 1;
}
// Assumption going into this function is that the LHS is the larger number and will "absorb" the
// smaller number.
fn unaligned_add(
lhs: Dec64,
rhs: Dec64,
negative: bool,
scale: u32,
rescale_factor: i32,
subtract: bool,
) -> CalculationResult {
let mut lhs = lhs;
let mut low64 = lhs.low64;
let mut high = lhs.hi;
let mut rescale_factor = rescale_factor;
// First off, we see if we can get away with scaling small amounts (or none at all)
if high == 0 {
if low64 <= U32_MAX {
// We know it's not zero, so we start scaling.
// Start with reducing the scale down for the low portion
while low64 <= U32_MAX {
if rescale_factor <= MAX_I32_SCALE {
low64 *= POWERS_10[rescale_factor as usize] as u64;
lhs.low64 = low64;
return aligned_add(lhs, rhs, negative, scale, subtract);
}
rescale_factor -= MAX_I32_SCALE;
low64 *= POWERS_10[9] as u64;
}
}
// Reduce the scale for the high portion
while high == 0 {
let power = if rescale_factor <= MAX_I32_SCALE {
POWERS_10[rescale_factor as usize] as u64
} else {
POWERS_10[9] as u64
};
let tmp_low = (low64 & U32_MASK) * power;
let tmp_hi = (low64 >> 32) * power + (tmp_low >> 32);
low64 = (tmp_low & U32_MASK) + (tmp_hi << 32);
high = (tmp_hi >> 32) as u32;
rescale_factor -= MAX_I32_SCALE;
if rescale_factor <= 0 {
lhs.low64 = low64;
lhs.hi = high;
return aligned_add(lhs, rhs, negative, scale, subtract);
}
}
}
// See if we can get away with keeping it in the 96 bits. Otherwise, we need a buffer
let mut tmp64: u64;
loop {
let power = if rescale_factor <= MAX_I32_SCALE {
POWERS_10[rescale_factor as usize] as u64
} else {
POWERS_10[9] as u64
};
let tmp_low = (low64 & U32_MASK) * power;
tmp64 = (low64 >> 32) * power + (tmp_low >> 32);
low64 = (tmp_low & U32_MASK) + (tmp64 << 32);
tmp64 >>= 32;
tmp64 += (high as u64) * power;
rescale_factor -= MAX_I32_SCALE;
if tmp64 > U32_MAX {
break;
} else {
high = tmp64 as u32;
if rescale_factor <= 0 {
lhs.low64 = low64;
lhs.hi = high;
return aligned_add(lhs, rhs, negative, scale, subtract);
}
}
}
let mut buffer = Buf24::zero();
buffer.set_low64(low64);
buffer.set_mid64(tmp64);
let mut upper_word = buffer.upper_word();
while rescale_factor > 0 {
let power = if rescale_factor <= MAX_I32_SCALE {
POWERS_10[rescale_factor as usize] as u64
} else {
POWERS_10[9] as u64
};
tmp64 = 0;
for (index, part) in buffer.data.iter_mut().enumerate() {
tmp64 = tmp64.wrapping_add((*part as u64) * power);
*part = tmp64 as u32;
tmp64 >>= 32;
if index + 1 > upper_word {
break;
}
}
if tmp64 & U32_MASK > 0 {
// Extend the result
upper_word += 1;
buffer.data[upper_word] = tmp64 as u32;
}
rescale_factor -= MAX_I32_SCALE;
}
// Do the add
tmp64 = buffer.low64();
low64 = rhs.low64;
let tmp_hi = buffer.data[2];
high = rhs.hi;
if subtract {
low64 = tmp64.wrapping_sub(low64);
high = tmp_hi.wrapping_sub(high);
// Check for carry
let carry = if low64 > tmp64 {
high = high.wrapping_sub(1);
high >= tmp_hi
} else {
high > tmp_hi
};
if carry {
for part in buffer.data.iter_mut().skip(3) {
*part = part.wrapping_sub(1);
if *part > 0 {
break;
}
}
if buffer.data[upper_word] == 0 && upper_word < 3 {
return CalculationResult::Ok(Decimal::from_parts(
low64 as u32,
(low64 >> 32) as u32,
high,
negative,
scale,
));
}
}
} else {
low64 = low64.wrapping_add(tmp64);
high = high.wrapping_add(tmp_hi);
// Check for carry
let carry = if low64 < tmp64 {
high = high.wrapping_add(1);
high <= tmp_hi
} else {
high < tmp_hi
};
if carry {
for (index, part) in buffer.data.iter_mut().enumerate().skip(3) {
if upper_word < index {
*part = 1;
upper_word = index;
break;
}
*part = part.wrapping_add(1);
if *part > 0 {
break;
}
}
}
}
buffer.set_low64(low64);
buffer.data[2] = high;
if let Some(scale) = buffer.rescale(upper_word, scale) {
CalculationResult::Ok(Decimal::from_parts(
buffer.data[0],
buffer.data[1],
buffer.data[2],
negative,
scale,
))
} else {
CalculationResult::Overflow
}
}

326
third_party/rust/rust_decimal/src/ops/array.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,326 @@
use crate::constants::U32_MASK;
/// Rescales the given decimal to new scale.
/// e.g. with 1.23 and new scale 3 rescale the value to 1.230
#[inline(always)]
pub(crate) fn rescale_internal(value: &mut [u32; 3], value_scale: &mut u32, new_scale: u32) {
if *value_scale == new_scale {
// Nothing to do
return;
}
if is_all_zero(value) {
*value_scale = new_scale;
return;
}
if *value_scale > new_scale {
let mut diff = *value_scale - new_scale;
// Scaling further isn't possible since we got an overflow
// In this case we need to reduce the accuracy of the "side to keep"
// Now do the necessary rounding
let mut remainder = 0;
while diff > 0 {
if is_all_zero(value) {
*value_scale = new_scale;
return;
}
diff -= 1;
// Any remainder is discarded if diff > 0 still (i.e. lost precision)
remainder = div_by_u32(value, 10);
}
if remainder >= 5 {
for part in value.iter_mut() {
let digit = u64::from(*part) + 1u64;
remainder = if digit > 0xFFFF_FFFF { 1 } else { 0 };
*part = (digit & 0xFFFF_FFFF) as u32;
if remainder == 0 {
break;
}
}
}
*value_scale = new_scale;
} else {
let mut diff = new_scale - *value_scale;
let mut working = [value[0], value[1], value[2]];
while diff > 0 && mul_by_10(&mut working) == 0 {
value.copy_from_slice(&working);
diff -= 1;
}
*value_scale = new_scale - diff;
}
}
pub(crate) fn add_by_internal(value: &mut [u32], by: &[u32]) -> u32 {
let mut carry: u64 = 0;
let vl = value.len();
let bl = by.len();
if vl >= bl {
let mut sum: u64;
for i in 0..bl {
sum = u64::from(value[i]) + u64::from(by[i]) + carry;
value[i] = (sum & U32_MASK) as u32;
carry = sum >> 32;
}
if vl > bl && carry > 0 {
for i in value.iter_mut().skip(bl) {
sum = u64::from(*i) + carry;
*i = (sum & U32_MASK) as u32;
carry = sum >> 32;
if carry == 0 {
break;
}
}
}
} else if vl + 1 == bl {
// Overflow, by default, is anything in the high portion of by
let mut sum: u64;
for i in 0..vl {
sum = u64::from(value[i]) + u64::from(by[i]) + carry;
value[i] = (sum & U32_MASK) as u32;
carry = sum >> 32;
}
if by[vl] > 0 {
carry += u64::from(by[vl]);
}
} else {
panic!("Internal error: add using incompatible length arrays. {} <- {}", vl, bl);
}
carry as u32
}
#[inline]
pub(crate) fn add_one_internal(value: &mut [u32]) -> u32 {
let mut carry: u64 = 1; // Start with one, since adding one
let mut sum: u64;
for i in value.iter_mut() {
sum = (*i as u64) + carry;
*i = (sum & U32_MASK) as u32;
carry = sum >> 32;
}
carry as u32
}
pub(crate) fn sub_by_internal(value: &mut [u32], by: &[u32]) -> u32 {
// The way this works is similar to long subtraction
// Let's assume we're working with bytes for simplicity in an example:
// 257 - 8 = 249
// 0000_0001 0000_0001 - 0000_0000 0000_1000 = 0000_0000 1111_1001
// We start by doing the first byte...
// Overflow = 0
// Left = 0000_0001 (1)
// Right = 0000_1000 (8)
// Firstly, we make sure the left and right are scaled up to twice the size
// Left = 0000_0000 0000_0001
// Right = 0000_0000 0000_1000
// We then subtract right from left
// Result = Left - Right = 1111_1111 1111_1001
// We subtract the overflow, which in this case is 0.
// Because left < right (1 < 8) we invert the high part.
// Lo = 1111_1001
// Hi = 1111_1111 -> 0000_0001
// Lo is the field, hi is the overflow.
// We do the same for the second byte...
// Overflow = 1
// Left = 0000_0001
// Right = 0000_0000
// Result = Left - Right = 0000_0000 0000_0001
// We subtract the overflow...
// Result = 0000_0000 0000_0001 - 1 = 0
// And we invert the high, just because (invert 0 = 0).
// So our result is:
// 0000_0000 1111_1001
let mut overflow = 0;
let vl = value.len();
let bl = by.len();
for i in 0..vl {
if i >= bl {
break;
}
let (lo, hi) = sub_part(value[i], by[i], overflow);
value[i] = lo;
overflow = hi;
}
overflow
}
fn sub_part(left: u32, right: u32, overflow: u32) -> (u32, u32) {
let part = 0x1_0000_0000u64 + u64::from(left) - (u64::from(right) + u64::from(overflow));
let lo = part as u32;
let hi = 1 - ((part >> 32) as u32);
(lo, hi)
}
// Returns overflow
#[inline]
pub(crate) fn mul_by_10(bits: &mut [u32; 3]) -> u32 {
let mut overflow = 0u64;
for b in bits.iter_mut() {
let result = u64::from(*b) * 10u64 + overflow;
let hi = (result >> 32) & U32_MASK;
let lo = (result & U32_MASK) as u32;
*b = lo;
overflow = hi;
}
overflow as u32
}
// Returns overflow
pub(crate) fn mul_by_u32(bits: &mut [u32], m: u32) -> u32 {
let mut overflow = 0;
for b in bits.iter_mut() {
let (lo, hi) = mul_part(*b, m, overflow);
*b = lo;
overflow = hi;
}
overflow
}
pub(crate) fn mul_part(left: u32, right: u32, high: u32) -> (u32, u32) {
let result = u64::from(left) * u64::from(right) + u64::from(high);
let hi = ((result >> 32) & U32_MASK) as u32;
let lo = (result & U32_MASK) as u32;
(lo, hi)
}
// Returns remainder
pub(crate) fn div_by_u32(bits: &mut [u32], divisor: u32) -> u32 {
if divisor == 0 {
// Divide by zero
panic!("Internal error: divide by zero");
} else if divisor == 1 {
// dividend remains unchanged
0
} else {
let mut remainder = 0u32;
let divisor = u64::from(divisor);
for part in bits.iter_mut().rev() {
let temp = (u64::from(remainder) << 32) + u64::from(*part);
remainder = (temp % divisor) as u32;
*part = (temp / divisor) as u32;
}
remainder
}
}
#[inline]
pub(crate) fn shl1_internal(bits: &mut [u32], carry: u32) -> u32 {
let mut carry = carry;
for part in bits.iter_mut() {
let b = *part >> 31;
*part = (*part << 1) | carry;
carry = b;
}
carry
}
#[inline]
pub(crate) fn cmp_internal(left: &[u32; 3], right: &[u32; 3]) -> core::cmp::Ordering {
let left_hi: u32 = left[2];
let right_hi: u32 = right[2];
let left_lo: u64 = u64::from(left[1]) << 32 | u64::from(left[0]);
let right_lo: u64 = u64::from(right[1]) << 32 | u64::from(right[0]);
if left_hi < right_hi || (left_hi <= right_hi && left_lo < right_lo) {
core::cmp::Ordering::Less
} else if left_hi == right_hi && left_lo == right_lo {
core::cmp::Ordering::Equal
} else {
core::cmp::Ordering::Greater
}
}
#[inline]
pub(crate) fn is_all_zero(bits: &[u32]) -> bool {
bits.iter().all(|b| *b == 0)
}
#[cfg(test)]
mod test {
// Tests on private methods.
//
// All public tests should go under `tests/`.
use super::*;
use crate::prelude::*;
#[test]
fn it_can_rescale_internal() {
fn extract(value: &str) -> ([u32; 3], u32) {
let v = Decimal::from_str(value).unwrap();
(v.mantissa_array3(), v.scale())
}
let tests = &[
("1", 0, "1"),
("1", 1, "1.0"),
("1", 5, "1.00000"),
("1", 10, "1.0000000000"),
("1", 20, "1.00000000000000000000"),
("0.6386554621848739495798319328", 27, "0.638655462184873949579831933"),
(
"843.65000000", // Scale 8
25, // 25
"843.6500000000000000000000000", // 25
),
(
"843.65000000", // Scale 8
30, // 30
"843.6500000000000000000000000000", // 28
),
];
for &(value_raw, new_scale, expected_value) in tests {
let (expected_value, _) = extract(expected_value);
let (mut value, mut value_scale) = extract(value_raw);
rescale_internal(&mut value, &mut value_scale, new_scale);
assert_eq!(value, expected_value);
}
}
#[test]
fn test_shl1_internal() {
struct TestCase {
// One thing to be cautious of is that the structure of a number here for shifting left is
// the reverse of how you may conceive this mentally. i.e. a[2] contains the higher order
// bits: a[2] a[1] a[0]
given: [u32; 3],
given_carry: u32,
expected: [u32; 3],
expected_carry: u32,
}
let tests = [
TestCase {
given: [1, 0, 0],
given_carry: 0,
expected: [2, 0, 0],
expected_carry: 0,
},
TestCase {
given: [1, 0, 2147483648],
given_carry: 1,
expected: [3, 0, 0],
expected_carry: 1,
},
];
for case in &tests {
let mut test = [case.given[0], case.given[1], case.given[2]];
let carry = shl1_internal(&mut test, case.given_carry);
assert_eq!(
test, case.expected,
"Bits: {:?} << 1 | {}",
case.given, case.given_carry
);
assert_eq!(
carry, case.expected_carry,
"Carry: {:?} << 1 | {}",
case.given, case.given_carry
)
}
}
}

101
third_party/rust/rust_decimal/src/ops/cmp.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,101 @@
use crate::constants::{MAX_I32_SCALE, POWERS_10, U32_MASK, U32_MAX};
use crate::decimal::Decimal;
use crate::ops::common::Dec64;
use core::cmp::Ordering;
pub(crate) fn cmp_impl(d1: &Decimal, d2: &Decimal) -> Ordering {
if d2.is_zero() {
return if d1.is_zero() {
return Ordering::Equal;
} else if d1.is_sign_negative() {
Ordering::Less
} else {
Ordering::Greater
};
}
if d1.is_zero() {
return if d2.is_sign_negative() {
Ordering::Greater
} else {
Ordering::Less
};
}
// If the sign is different, then it's an easy answer
if d1.is_sign_negative() != d2.is_sign_negative() {
return if d1.is_sign_negative() {
Ordering::Less
} else {
Ordering::Greater
};
}
// Otherwise, do a deep comparison
let d1 = Dec64::new(&d1);
let d2 = Dec64::new(&d2);
// We know both signs are the same here so flip it here.
// Negative is handled differently. i.e. 0.5 > 0.01 however -0.5 < -0.01
if d1.negative {
cmp_internal(&d2, &d1)
} else {
cmp_internal(&d1, &d2)
}
}
pub(in crate::ops) fn cmp_internal(d1: &Dec64, d2: &Dec64) -> Ordering {
// This function ignores sign
let mut d1_low = d1.low64;
let mut d1_high = d1.hi;
let mut d2_low = d2.low64;
let mut d2_high = d2.hi;
// If the scale factors aren't equal then
if d1.scale != d2.scale {
let mut diff = d2.scale as i32 - d1.scale as i32;
if diff < 0 {
diff = -diff;
if !rescale(&mut d2_low, &mut d2_high, diff as u32) {
return Ordering::Less;
}
} else if !rescale(&mut d1_low, &mut d1_high, diff as u32) {
return Ordering::Greater;
}
}
// They're the same scale, do a standard bitwise comparison
let hi_order = d1_high.cmp(&d2_high);
if hi_order != Ordering::Equal {
return hi_order;
}
d1_low.cmp(&d2_low)
}
fn rescale(low64: &mut u64, high: &mut u32, diff: u32) -> bool {
let mut diff = diff as i32;
// We need to modify d1 by 10^diff to get it to the same scale as d2
loop {
let power = if diff >= MAX_I32_SCALE {
POWERS_10[9]
} else {
POWERS_10[diff as usize]
} as u64;
let tmp_lo_32 = (*low64 & U32_MASK) * power;
let mut tmp = (*low64 >> 32) * power + (tmp_lo_32 >> 32);
*low64 = (tmp_lo_32 & U32_MASK) + (tmp << 32);
tmp >>= 32;
tmp = tmp.wrapping_add((*high as u64) * power);
// Indicates > 96 bits
if tmp > U32_MAX {
return false;
}
*high = tmp as u32;
// Keep scaling if there is more to go
diff -= MAX_I32_SCALE;
if diff <= 0 {
break;
}
}
true
}

455
third_party/rust/rust_decimal/src/ops/common.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,455 @@
use crate::constants::{MAX_I32_SCALE, MAX_PRECISION_I32, POWERS_10};
use crate::Decimal;
#[derive(Debug)]
pub struct Buf12 {
pub data: [u32; 3],
}
impl Buf12 {
pub(super) const fn from_dec64(value: &Dec64) -> Self {
Buf12 {
data: [value.low64 as u32, (value.low64 >> 32) as u32, value.hi],
}
}
pub(super) const fn from_decimal(value: &Decimal) -> Self {
Buf12 {
data: value.mantissa_array3(),
}
}
#[inline(always)]
pub const fn lo(&self) -> u32 {
self.data[0]
}
#[inline(always)]
pub const fn mid(&self) -> u32 {
self.data[1]
}
#[inline(always)]
pub const fn hi(&self) -> u32 {
self.data[2]
}
#[inline(always)]
pub fn set_lo(&mut self, value: u32) {
self.data[0] = value;
}
#[inline(always)]
pub fn set_mid(&mut self, value: u32) {
self.data[1] = value;
}
#[inline(always)]
pub fn set_hi(&mut self, value: u32) {
self.data[2] = value;
}
#[inline(always)]
pub const fn low64(&self) -> u64 {
((self.data[1] as u64) << 32) | (self.data[0] as u64)
}
#[inline(always)]
pub fn set_low64(&mut self, value: u64) {
self.data[1] = (value >> 32) as u32;
self.data[0] = value as u32;
}
#[inline(always)]
pub const fn high64(&self) -> u64 {
((self.data[2] as u64) << 32) | (self.data[1] as u64)
}
#[inline(always)]
pub fn set_high64(&mut self, value: u64) {
self.data[2] = (value >> 32) as u32;
self.data[1] = value as u32;
}
// Determine the maximum value of x that ensures that the quotient when scaled up by 10^x
// still fits in 96 bits. Ultimately, we want to make scale positive - if we can't then
// we're going to overflow. Because x is ultimately used to lookup inside the POWERS array, it
// must be a valid value 0 <= x <= 9
pub fn find_scale(&self, scale: i32) -> Option<usize> {
const OVERFLOW_MAX_9_HI: u32 = 4;
const OVERFLOW_MAX_8_HI: u32 = 42;
const OVERFLOW_MAX_7_HI: u32 = 429;
const OVERFLOW_MAX_6_HI: u32 = 4294;
const OVERFLOW_MAX_5_HI: u32 = 42949;
const OVERFLOW_MAX_4_HI: u32 = 429496;
const OVERFLOW_MAX_3_HI: u32 = 4294967;
const OVERFLOW_MAX_2_HI: u32 = 42949672;
const OVERFLOW_MAX_1_HI: u32 = 429496729;
const OVERFLOW_MAX_9_LOW64: u64 = 5441186219426131129;
let hi = self.data[2];
let low64 = self.low64();
let mut x = 0usize;
// Quick check to stop us from trying to scale any more.
//
if hi > OVERFLOW_MAX_1_HI {
// If it's less than 0, which it probably is - overflow. We can't do anything.
if scale < 0 {
return None;
}
return Some(x);
}
if scale > MAX_PRECISION_I32 - 9 {
// We can't scale by 10^9 without exceeding the max scale factor.
// Instead, we'll try to scale by the most that we can and see if that works.
// This is safe to do due to the check above. e.g. scale > 19 in the above, so it will
// evaluate to 9 or less below.
x = (MAX_PRECISION_I32 - scale) as usize;
if hi < POWER_OVERFLOW_VALUES[x - 1].data[2] {
if x as i32 + scale < 0 {
// We still overflow
return None;
}
return Some(x);
}
} else if hi < OVERFLOW_MAX_9_HI || hi == OVERFLOW_MAX_9_HI && low64 <= OVERFLOW_MAX_9_LOW64 {
return Some(9);
}
// Do a binary search to find a power to scale by that is less than 9
x = if hi > OVERFLOW_MAX_5_HI {
if hi > OVERFLOW_MAX_3_HI {
if hi > OVERFLOW_MAX_2_HI {
1
} else {
2
}
} else if hi > OVERFLOW_MAX_4_HI {
3
} else {
4
}
} else if hi > OVERFLOW_MAX_7_HI {
if hi > OVERFLOW_MAX_6_HI {
5
} else {
6
}
} else if hi > OVERFLOW_MAX_8_HI {
7
} else {
8
};
// Double check what we've found won't overflow. Otherwise, we go one below.
if hi == POWER_OVERFLOW_VALUES[x - 1].data[2] && low64 > POWER_OVERFLOW_VALUES[x - 1].low64() {
x -= 1;
}
// Confirm we've actually resolved things
if x as i32 + scale < 0 {
None
} else {
Some(x)
}
}
}
// This is a table of the largest values that will not overflow when multiplied
// by a given power as represented by the index.
static POWER_OVERFLOW_VALUES: [Buf12; 8] = [
Buf12 {
data: [2576980377, 2576980377, 429496729],
},
Buf12 {
data: [687194767, 4123168604, 42949672],
},
Buf12 {
data: [2645699854, 1271310319, 4294967],
},
Buf12 {
data: [694066715, 3133608139, 429496],
},
Buf12 {
data: [2216890319, 2890341191, 42949],
},
Buf12 {
data: [2369172679, 4154504685, 4294],
},
Buf12 {
data: [4102387834, 2133437386, 429],
},
Buf12 {
data: [410238783, 4078814305, 42],
},
];
pub(super) struct Dec64 {
pub negative: bool,
pub scale: u32,
pub hi: u32,
pub low64: u64,
}
impl Dec64 {
pub(super) const fn new(d: &Decimal) -> Dec64 {
let m = d.mantissa_array3();
if m[1] == 0 {
Dec64 {
negative: d.is_sign_negative(),
scale: d.scale(),
hi: m[2],
low64: m[0] as u64,
}
} else {
Dec64 {
negative: d.is_sign_negative(),
scale: d.scale(),
hi: m[2],
low64: ((m[1] as u64) << 32) | (m[0] as u64),
}
}
}
#[inline(always)]
pub(super) const fn lo(&self) -> u32 {
self.low64 as u32
}
#[inline(always)]
pub(super) const fn mid(&self) -> u32 {
(self.low64 >> 32) as u32
}
#[inline(always)]
pub(super) const fn high64(&self) -> u64 {
(self.low64 >> 32) | ((self.hi as u64) << 32)
}
pub(super) const fn to_decimal(&self) -> Decimal {
Decimal::from_parts(
self.low64 as u32,
(self.low64 >> 32) as u32,
self.hi,
self.negative,
self.scale,
)
}
}
pub struct Buf16 {
pub data: [u32; 4],
}
impl Buf16 {
pub const fn zero() -> Self {
Buf16 { data: [0, 0, 0, 0] }
}
pub const fn low64(&self) -> u64 {
((self.data[1] as u64) << 32) | (self.data[0] as u64)
}
pub fn set_low64(&mut self, value: u64) {
self.data[1] = (value >> 32) as u32;
self.data[0] = value as u32;
}
pub const fn mid64(&self) -> u64 {
((self.data[2] as u64) << 32) | (self.data[1] as u64)
}
pub fn set_mid64(&mut self, value: u64) {
self.data[2] = (value >> 32) as u32;
self.data[1] = value as u32;
}
pub const fn high64(&self) -> u64 {
((self.data[3] as u64) << 32) | (self.data[2] as u64)
}
pub fn set_high64(&mut self, value: u64) {
self.data[3] = (value >> 32) as u32;
self.data[2] = value as u32;
}
}
#[derive(Debug)]
pub struct Buf24 {
pub data: [u32; 6],
}
impl Buf24 {
pub const fn zero() -> Self {
Buf24 {
data: [0, 0, 0, 0, 0, 0],
}
}
pub const fn low64(&self) -> u64 {
((self.data[1] as u64) << 32) | (self.data[0] as u64)
}
pub fn set_low64(&mut self, value: u64) {
self.data[1] = (value >> 32) as u32;
self.data[0] = value as u32;
}
#[allow(dead_code)]
pub const fn mid64(&self) -> u64 {
((self.data[3] as u64) << 32) | (self.data[2] as u64)
}
pub fn set_mid64(&mut self, value: u64) {
self.data[3] = (value >> 32) as u32;
self.data[2] = value as u32;
}
#[allow(dead_code)]
pub const fn high64(&self) -> u64 {
((self.data[5] as u64) << 32) | (self.data[4] as u64)
}
pub fn set_high64(&mut self, value: u64) {
self.data[5] = (value >> 32) as u32;
self.data[4] = value as u32;
}
pub const fn upper_word(&self) -> usize {
if self.data[5] > 0 {
return 5;
}
if self.data[4] > 0 {
return 4;
}
if self.data[3] > 0 {
return 3;
}
if self.data[2] > 0 {
return 2;
}
if self.data[1] > 0 {
return 1;
}
0
}
// Attempt to rescale the number into 96 bits. If successful, the scale is returned wrapped
// in an Option. If it failed due to overflow, we return None.
// * `upper` - Index of last non-zero value in self.
// * `scale` - Current scale factor for this value.
pub fn rescale(&mut self, upper: usize, scale: u32) -> Option<u32> {
let mut scale = scale as i32;
let mut upper = upper;
// Determine a rescale target to start with
let mut rescale_target = 0i32;
if upper > 2 {
rescale_target = upper as i32 * 32 - 64 - 1;
rescale_target -= self.data[upper].leading_zeros() as i32;
rescale_target = ((rescale_target * 77) >> 8) + 1;
if rescale_target > scale {
return None;
}
}
// Make sure we scale enough to bring it into a valid range
if rescale_target < scale - MAX_PRECISION_I32 {
rescale_target = scale - MAX_PRECISION_I32;
}
if rescale_target > 0 {
// We're going to keep reducing by powers of 10. So, start by reducing the scale by
// that amount.
scale -= rescale_target;
let mut sticky = 0;
let mut remainder = 0;
loop {
sticky |= remainder;
let mut power = if rescale_target > 8 {
POWERS_10[9]
} else {
POWERS_10[rescale_target as usize]
};
let high = self.data[upper];
let high_quotient = high / power;
remainder = high - high_quotient * power;
for item in self.data.iter_mut().rev().skip(6 - upper) {
let num = (*item as u64).wrapping_add((remainder as u64) << 32);
*item = (num / power as u64) as u32;
remainder = (num as u32).wrapping_sub(item.wrapping_mul(power));
}
self.data[upper] = high_quotient;
// If the high quotient was zero then decrease the upper bound
if high_quotient == 0 && upper > 0 {
upper -= 1;
}
if rescale_target > MAX_I32_SCALE {
// Scale some more
rescale_target -= MAX_I32_SCALE;
continue;
}
// If we fit into 96 bits then we've scaled enough. Otherwise, scale once more.
if upper > 2 {
if scale == 0 {
return None;
}
// Equivalent to scaling down by 10
rescale_target = 1;
scale -= 1;
continue;
}
// Round the final result.
power >>= 1;
let carried = if power <= remainder {
// If we're less than half then we're fine. Otherwise, we round if odd or if the
// sticky bit is set.
if power < remainder || ((self.data[0] & 1) | sticky) != 0 {
// Round up
self.data[0] = self.data[0].wrapping_add(1);
// Check if we carried
self.data[0] == 0
} else {
false
}
} else {
false
};
// If we carried then propagate through the portions
if carried {
let mut pos = 0;
for (index, value) in self.data.iter_mut().enumerate().skip(1) {
pos = index;
*value = value.wrapping_add(1);
if *value != 0 {
break;
}
}
// If we ended up rounding over the 96 bits then we'll try to rescale down (again)
if pos > 2 {
// Nothing to scale down from will cause overflow
if scale == 0 {
return None;
}
// Loop back around using scale of 10.
// Reset the sticky bit and remainder before looping.
upper = pos;
sticky = 0;
remainder = 0;
rescale_target = 1;
scale -= 1;
continue;
}
}
break;
}
}
Some(scale as u32)
}
}

658
third_party/rust/rust_decimal/src/ops/div.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,658 @@
use crate::constants::{MAX_PRECISION_I32, POWERS_10};
use crate::decimal::{CalculationResult, Decimal};
use crate::ops::common::{Buf12, Buf16, Dec64};
use core::cmp::Ordering;
use core::ops::BitXor;
impl Buf12 {
// Returns true if successful, else false for an overflow
fn add32(&mut self, value: u32) -> Result<(), DivError> {
let value = value as u64;
let new = self.low64().wrapping_add(value);
self.set_low64(new);
if new < value {
self.data[2] = self.data[2].wrapping_add(1);
if self.data[2] == 0 {
return Err(DivError::Overflow);
}
}
Ok(())
}
// Divide a Decimal union by a 32 bit divisor.
// Self is overwritten with the quotient.
// Return value is a 32 bit remainder.
fn div32(&mut self, divisor: u32) -> u32 {
let divisor64 = divisor as u64;
// See if we can get by using a simple u64 division
if self.data[2] != 0 {
let mut temp = self.high64();
let q64 = temp / divisor64;
self.set_high64(q64);
// Calculate the "remainder"
temp = ((temp - q64 * divisor64) << 32) | (self.data[0] as u64);
if temp == 0 {
return 0;
}
let q32 = (temp / divisor64) as u32;
self.data[0] = q32;
((temp as u32).wrapping_sub(q32.wrapping_mul(divisor))) as u32
} else {
// Super easy divisor
let low64 = self.low64();
if low64 == 0 {
// Nothing to do
return 0;
}
// Do the calc
let quotient = low64 / divisor64;
self.set_low64(quotient);
// Remainder is the leftover that wasn't used
(low64.wrapping_sub(quotient.wrapping_mul(divisor64))) as u32
}
}
// Divide the number by a power constant
// Returns true if division was successful
fn div32_const(&mut self, pow: u32) -> bool {
let pow64 = pow as u64;
let high64 = self.high64();
let lo = self.data[0] as u64;
let div64: u64 = high64 / pow64;
let div = ((((high64 - div64 * pow64) << 32) + lo) / pow64) as u32;
if self.data[0] == div.wrapping_mul(pow) {
self.set_high64(div64);
self.data[0] = div;
true
} else {
false
}
}
}
impl Buf16 {
// Does a partial divide with a 64 bit divisor. The divisor in this case must be 64 bits
// otherwise various assumptions fail (e.g. 32 bit quotient).
// To assist, the upper 64 bits must be greater than the divisor for this to succeed.
// Consequently, it will return the quotient as a 32 bit number and overwrite self with the
// 64 bit remainder.
pub(super) fn partial_divide_64(&mut self, divisor: u64) -> u32 {
// We make this assertion here, however below we pivot based on the data
debug_assert!(divisor > self.mid64());
// If we have an empty high bit, then divisor must be greater than the dividend due to
// the assumption that the divisor REQUIRES 64 bits.
if self.data[2] == 0 {
let low64 = self.low64();
if low64 < divisor {
// We can't divide at at all so result is 0. The dividend remains untouched since
// the full amount is the remainder.
return 0;
}
let quotient = low64 / divisor;
self.set_low64(low64 - (quotient * divisor));
return quotient as u32;
}
// Do a simple check to see if the hi portion of the dividend is greater than the hi
// portion of the divisor.
let divisor_hi32 = (divisor >> 32) as u32;
if self.data[2] >= divisor_hi32 {
// We know that the divisor goes into this at MOST u32::max times.
// So we kick things off, with that assumption
let mut low64 = self.low64();
low64 = low64.wrapping_sub(divisor << 32).wrapping_add(divisor);
let mut quotient = u32::MAX;
// If we went negative then keep adding it back in
loop {
if low64 < divisor {
break;
}
quotient = quotient.wrapping_sub(1);
low64 = low64.wrapping_add(divisor);
}
self.set_low64(low64);
return quotient;
}
let mid64 = self.mid64();
let divisor_hi32_64 = divisor_hi32 as u64;
if mid64 < divisor_hi32_64 as u64 {
// similar situation as above where we've got nothing left to divide
return 0;
}
let mut quotient = mid64 / divisor_hi32_64;
let mut remainder = self.data[0] as u64 | ((mid64 - quotient * divisor_hi32_64) << 32);
// Do quotient * lo divisor
let product = quotient * (divisor & 0xFFFF_FFFF);
remainder = remainder.wrapping_sub(product);
// Check if we've gone negative. If so, add it back
if remainder > product.bitxor(u64::MAX) {
loop {
quotient = quotient.wrapping_sub(1);
remainder = remainder.wrapping_add(divisor);
if remainder < divisor {
break;
}
}
}
self.set_low64(remainder);
quotient as u32
}
// Does a partial divide with a 96 bit divisor. The divisor in this case must require 96 bits
// otherwise various assumptions fail (e.g. 32 bit quotient).
pub(super) fn partial_divide_96(&mut self, divisor: &Buf12) -> u32 {
let dividend = self.high64();
let divisor_hi = divisor.data[2];
if dividend < divisor_hi as u64 {
// Dividend is too small - entire number is remainder
return 0;
}
let mut quo = (dividend / divisor_hi as u64) as u32;
let mut remainder = (dividend as u32).wrapping_sub(quo.wrapping_mul(divisor_hi));
// Compute full remainder
let mut prod1 = quo as u64 * divisor.data[0] as u64;
let mut prod2 = quo as u64 * divisor.data[1] as u64;
prod2 += prod1 >> 32;
prod1 = (prod1 & 0xFFFF_FFFF) | (prod2 << 32);
prod2 >>= 32;
let mut num = self.low64();
num = num.wrapping_sub(prod1);
remainder = remainder.wrapping_sub(prod2 as u32);
// If there are carries make sure they are propagated
if num > prod1.bitxor(u64::MAX) {
remainder = remainder.wrapping_sub(1);
if remainder < (prod2 as u32).bitxor(u32::MAX) {
self.set_low64(num);
self.data[2] = remainder;
return quo;
}
} else if remainder <= (prod2 as u32).bitxor(u32::MAX) {
self.set_low64(num);
self.data[2] = remainder;
return quo;
}
// Remainder went negative, add divisor back until it's positive
prod1 = divisor.low64();
loop {
quo = quo.wrapping_sub(1);
num = num.wrapping_add(prod1);
remainder = remainder.wrapping_add(divisor_hi);
if num < prod1 {
// Detected carry.
let tmp = remainder;
remainder = remainder.wrapping_add(1);
if tmp < divisor_hi {
break;
}
}
if remainder < divisor_hi {
break; // detected carry
}
}
self.set_low64(num);
self.data[2] = remainder;
quo
}
}
enum DivError {
Overflow,
}
pub(crate) fn div_impl(dividend: &Decimal, divisor: &Decimal) -> CalculationResult {
if divisor.is_zero() {
return CalculationResult::DivByZero;
}
if dividend.is_zero() {
return CalculationResult::Ok(Decimal::ZERO);
}
let dividend = Dec64::new(dividend);
let divisor = Dec64::new(divisor);
// Pre calculate the scale and the sign
let mut scale = (dividend.scale as i32) - (divisor.scale as i32);
let sign_negative = dividend.negative ^ divisor.negative;
// Set up some variables for modification throughout
let mut require_unscale = false;
let mut quotient = Buf12::from_dec64(&dividend);
let divisor = Buf12::from_dec64(&divisor);
// Branch depending on the complexity of the divisor
if divisor.data[2] | divisor.data[1] == 0 {
// We have a simple(r) divisor (32 bit)
let divisor32 = divisor.data[0];
// Remainder can only be 32 bits since the divisor is 32 bits.
let mut remainder = quotient.div32(divisor32);
let mut power_scale = 0;
// Figure out how to apply the remainder (i.e. we may have performed something like 10/3 or 8/5)
loop {
// Remainder is 0 so we have a simple situation
if remainder == 0 {
// If the scale is positive then we're actually done
if scale >= 0 {
break;
}
power_scale = 9usize.min((-scale) as usize);
} else {
// We may need to normalize later, so set the flag appropriately
require_unscale = true;
// We have a remainder so we effectively want to try to adjust the quotient and add
// the remainder into the quotient. We do this below, however first of all we want
// to try to avoid overflowing so we do that check first.
let will_overflow = if scale == MAX_PRECISION_I32 {
true
} else {
// Figure out how much we can scale by
if let Some(s) = quotient.find_scale(scale) {
power_scale = s;
} else {
return CalculationResult::Overflow;
}
// If it comes back as 0 (i.e. 10^0 = 1) then we're going to overflow since
// we're doing nothing.
power_scale == 0
};
if will_overflow {
// No more scaling can be done, but remainder is non-zero so we round if necessary.
let tmp = remainder << 1;
let round = if tmp < remainder {
// We round if we wrapped around
true
} else if tmp >= divisor32 {
// If we're greater than the divisor (i.e. underflow)
// or if there is a lo bit set, we round
tmp > divisor32 || (quotient.data[0] & 0x1) > 0
} else {
false
};
// If we need to round, try to do so.
if round {
if let Ok(new_scale) = round_up(&mut quotient, scale) {
scale = new_scale;
} else {
// Overflowed
return CalculationResult::Overflow;
}
}
break;
}
}
// Do some scaling
let power = POWERS_10[power_scale];
scale += power_scale as i32;
// Increase the quotient by the power that was looked up
let overflow = increase_scale(&mut quotient, power as u64);
if overflow > 0 {
return CalculationResult::Overflow;
}
let remainder_scaled = (remainder as u64) * (power as u64);
let remainder_quotient = (remainder_scaled / (divisor32 as u64)) as u32;
remainder = (remainder_scaled - remainder_quotient as u64 * divisor32 as u64) as u32;
if let Err(DivError::Overflow) = quotient.add32(remainder_quotient) {
if let Ok(adj) = unscale_from_overflow(&mut quotient, scale, remainder != 0) {
scale = adj;
} else {
// Still overflowing
return CalculationResult::Overflow;
}
break;
}
}
} else {
// We have a divisor greater than 32 bits. Both of these share some quick calculation wins
// so we'll do those before branching into separate logic.
// The win we can do is shifting the bits to the left as much as possible. We do this to both
// the dividend and the divisor to ensure the quotient is not changed.
// As a simple contrived example: if we have 4 / 2 then we could bit shift all the way to the
// left meaning that the lo portion would have nothing inside of it. Of course, shifting these
// left one has the same result (8/4) etc.
// The advantage is that we may be able to write off lower portions of the number making things
// easier.
let mut power_scale = if divisor.data[2] == 0 {
divisor.data[1].leading_zeros()
} else {
divisor.data[2].leading_zeros()
} as usize;
let mut remainder = Buf16::zero();
remainder.set_low64(quotient.low64() << power_scale);
let tmp_high = ((quotient.data[1] as u64) + ((quotient.data[2] as u64) << 32)) >> (32 - power_scale);
remainder.set_high64(tmp_high);
// Work out the divisor after it's shifted
let divisor64 = divisor.low64() << power_scale;
// Check if the divisor is 64 bit or the full 96 bits
if divisor.data[2] == 0 {
// It's 64 bits
quotient.data[2] = 0;
// Calc mid/lo by shifting accordingly
let rem_lo = remainder.data[0];
remainder.data[0] = remainder.data[1];
remainder.data[1] = remainder.data[2];
remainder.data[2] = remainder.data[3];
quotient.data[1] = remainder.partial_divide_64(divisor64);
remainder.data[2] = remainder.data[1];
remainder.data[1] = remainder.data[0];
remainder.data[0] = rem_lo;
quotient.data[0] = remainder.partial_divide_64(divisor64);
loop {
let rem_low64 = remainder.low64();
if rem_low64 == 0 {
// If the scale is positive then we're actually done
if scale >= 0 {
break;
}
power_scale = 9usize.min((-scale) as usize);
} else {
// We may need to normalize later, so set the flag appropriately
require_unscale = true;
// We have a remainder so we effectively want to try to adjust the quotient and add
// the remainder into the quotient. We do this below, however first of all we want
// to try to avoid overflowing so we do that check first.
let will_overflow = if scale == MAX_PRECISION_I32 {
true
} else {
// Figure out how much we can scale by
if let Some(s) = quotient.find_scale(scale) {
power_scale = s;
} else {
return CalculationResult::Overflow;
}
// If it comes back as 0 (i.e. 10^0 = 1) then we're going to overflow since
// we're doing nothing.
power_scale == 0
};
if will_overflow {
// No more scaling can be done, but remainder is non-zero so we round if necessary.
let mut tmp = remainder.low64();
let round = if (tmp as i64) < 0 {
// We round if we wrapped around
true
} else {
tmp <<= 1;
if tmp > divisor64 {
true
} else {
tmp == divisor64 && quotient.data[0] & 0x1 != 0
}
};
// If we need to round, try to do so.
if round {
if let Ok(new_scale) = round_up(&mut quotient, scale) {
scale = new_scale;
} else {
// Overflowed
return CalculationResult::Overflow;
}
}
break;
}
}
// Do some scaling
let power = POWERS_10[power_scale];
scale += power_scale as i32;
// Increase the quotient by the power that was looked up
let overflow = increase_scale(&mut quotient, power as u64);
if overflow > 0 {
return CalculationResult::Overflow;
}
increase_scale64(&mut remainder, power as u64);
let tmp = remainder.partial_divide_64(divisor64);
if let Err(DivError::Overflow) = quotient.add32(tmp) {
if let Ok(adj) = unscale_from_overflow(&mut quotient, scale, remainder.low64() != 0) {
scale = adj;
} else {
// Still overflowing
return CalculationResult::Overflow;
}
break;
}
}
} else {
// It's 96 bits
// Start by finishing the shift left
let divisor_mid = divisor.data[1];
let divisor_hi = divisor.data[2];
let mut divisor = divisor;
divisor.set_low64(divisor64);
divisor.data[2] = ((divisor_mid as u64 + ((divisor_hi as u64) << 32)) >> (32 - power_scale)) as u32;
let quo = remainder.partial_divide_96(&divisor);
quotient.set_low64(quo as u64);
quotient.data[2] = 0;
loop {
let mut rem_low64 = remainder.low64();
if rem_low64 == 0 && remainder.data[2] == 0 {
// If the scale is positive then we're actually done
if scale >= 0 {
break;
}
power_scale = 9usize.min((-scale) as usize);
} else {
// We may need to normalize later, so set the flag appropriately
require_unscale = true;
// We have a remainder so we effectively want to try to adjust the quotient and add
// the remainder into the quotient. We do this below, however first of all we want
// to try to avoid overflowing so we do that check first.
let will_overflow = if scale == MAX_PRECISION_I32 {
true
} else {
// Figure out how much we can scale by
if let Some(s) = quotient.find_scale(scale) {
power_scale = s;
} else {
return CalculationResult::Overflow;
}
// If it comes back as 0 (i.e. 10^0 = 1) then we're going to overflow since
// we're doing nothing.
power_scale == 0
};
if will_overflow {
// No more scaling can be done, but remainder is non-zero so we round if necessary.
let round = if (remainder.data[2] as i32) < 0 {
// We round if we wrapped around
true
} else {
let tmp = remainder.data[1] >> 31;
rem_low64 <<= 1;
remainder.set_low64(rem_low64);
remainder.data[2] = (&remainder.data[2] << 1) + tmp;
match remainder.data[2].cmp(&divisor.data[2]) {
Ordering::Less => false,
Ordering::Equal => {
let divisor_low64 = divisor.low64();
if rem_low64 > divisor_low64 {
true
} else {
rem_low64 == divisor_low64 && (quotient.data[0] & 1) != 0
}
}
Ordering::Greater => true,
}
};
// If we need to round, try to do so.
if round {
if let Ok(new_scale) = round_up(&mut quotient, scale) {
scale = new_scale;
} else {
// Overflowed
return CalculationResult::Overflow;
}
}
break;
}
}
// Do some scaling
let power = POWERS_10[power_scale];
scale += power_scale as i32;
// Increase the quotient by the power that was looked up
let overflow = increase_scale(&mut quotient, power as u64);
if overflow > 0 {
return CalculationResult::Overflow;
}
let mut tmp_remainder = Buf12 {
data: [remainder.data[0], remainder.data[1], remainder.data[2]],
};
let overflow = increase_scale(&mut tmp_remainder, power as u64);
remainder.data[0] = tmp_remainder.data[0];
remainder.data[1] = tmp_remainder.data[1];
remainder.data[2] = tmp_remainder.data[2];
remainder.data[3] = overflow;
let tmp = remainder.partial_divide_96(&divisor);
if let Err(DivError::Overflow) = quotient.add32(tmp) {
if let Ok(adj) =
unscale_from_overflow(&mut quotient, scale, (remainder.low64() | remainder.high64()) != 0)
{
scale = adj;
} else {
// Still overflowing
return CalculationResult::Overflow;
}
break;
}
}
}
}
if require_unscale {
scale = unscale(&mut quotient, scale);
}
CalculationResult::Ok(Decimal::from_parts(
quotient.data[0],
quotient.data[1],
quotient.data[2],
sign_negative,
scale as u32,
))
}
// Multiply num by power (multiple of 10). Power must be 32 bits.
// Returns the overflow, if any
fn increase_scale(num: &mut Buf12, power: u64) -> u32 {
let mut tmp = (num.data[0] as u64) * power;
num.data[0] = tmp as u32;
tmp >>= 32;
tmp += (num.data[1] as u64) * power;
num.data[1] = tmp as u32;
tmp >>= 32;
tmp += (num.data[2] as u64) * power;
num.data[2] = tmp as u32;
(tmp >> 32) as u32
}
// Multiply num by power (multiple of 10). Power must be 32 bits.
fn increase_scale64(num: &mut Buf16, power: u64) {
let mut tmp = (num.data[0] as u64) * power;
num.data[0] = tmp as u32;
tmp >>= 32;
tmp += (num.data[1] as u64) * power;
num.set_mid64(tmp)
}
// Adjust the number to deal with an overflow. This function follows being scaled up (i.e. multiplied
// by 10, so this effectively tries to reverse that by dividing by 10 then feeding in the high bit
// to undo the overflow and rounding instead.
// Returns the updated scale.
fn unscale_from_overflow(num: &mut Buf12, scale: i32, sticky: bool) -> Result<i32, DivError> {
let scale = scale - 1;
if scale < 0 {
return Err(DivError::Overflow);
}
// This function is called when the hi portion has "overflowed" upon adding one and has wrapped
// back around to 0. Consequently, we need to "feed" that back in, but also rescaling down
// to reverse out the overflow.
const HIGH_BIT: u64 = 0x1_0000_0000;
num.data[2] = (HIGH_BIT / 10) as u32;
// Calc the mid
let mut tmp = ((HIGH_BIT % 10) << 32) + (num.data[1] as u64);
let mut val = (tmp / 10) as u32;
num.data[1] = val;
// Calc the lo using a similar method
tmp = ((tmp - (val as u64) * 10) << 32) + (num.data[0] as u64);
val = (tmp / 10) as u32;
num.data[0] = val;
// Work out the remainder, and round if we have one (since it doesn't fit)
let remainder = (tmp - (val as u64) * 10) as u32;
if remainder > 5 || (remainder == 5 && (sticky || num.data[0] & 0x1 > 0)) {
let _ = num.add32(1);
}
Ok(scale)
}
#[inline]
fn round_up(num: &mut Buf12, scale: i32) -> Result<i32, DivError> {
let low64 = num.low64().wrapping_add(1);
num.set_low64(low64);
if low64 != 0 {
return Ok(scale);
}
let hi = num.data[2].wrapping_add(1);
num.data[2] = hi;
if hi != 0 {
return Ok(scale);
}
unscale_from_overflow(num, scale, true)
}
fn unscale(num: &mut Buf12, scale: i32) -> i32 {
// Since 10 = 2 * 5, there must be a factor of 2 for every power of 10 we can extract.
// We use this as a quick test on whether to try a given power.
let mut scale = scale;
while num.data[0] == 0 && scale >= 8 && num.div32_const(100000000) {
scale -= 8;
}
if (num.data[0] & 0xF) == 0 && scale >= 4 && num.div32_const(10000) {
scale -= 4;
}
if (num.data[0] & 0x3) == 0 && scale >= 2 && num.div32_const(100) {
scale -= 2;
}
if (num.data[0] & 0x1) == 0 && scale >= 1 && num.div32_const(10) {
scale -= 1;
}
scale
}

838
third_party/rust/rust_decimal/src/ops/legacy.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,838 @@
use crate::{
constants::{MAX_PRECISION, POWERS_10, U32_MASK},
decimal::{CalculationResult, Decimal},
ops::array::{
add_by_internal, cmp_internal, div_by_u32, is_all_zero, mul_by_u32, mul_part, rescale_internal, shl1_internal,
},
};
use core::cmp::Ordering;
use num_traits::Zero;
pub(crate) fn add_impl(d1: &Decimal, d2: &Decimal) -> CalculationResult {
// Convert to the same scale
let mut my = d1.mantissa_array3();
let mut my_scale = d1.scale();
let mut ot = d2.mantissa_array3();
let mut other_scale = d2.scale();
rescale_to_maximum_scale(&mut my, &mut my_scale, &mut ot, &mut other_scale);
let mut final_scale = my_scale.max(other_scale);
// Add the items together
let my_negative = d1.is_sign_negative();
let other_negative = d2.is_sign_negative();
let mut negative = false;
let carry;
if !(my_negative ^ other_negative) {
negative = my_negative;
carry = add_by_internal3(&mut my, &ot);
} else {
let cmp = cmp_internal(&my, &ot);
// -x + y
// if x > y then it's negative (i.e. -2 + 1)
match cmp {
Ordering::Less => {
negative = other_negative;
sub_by_internal3(&mut ot, &my);
my[0] = ot[0];
my[1] = ot[1];
my[2] = ot[2];
}
Ordering::Greater => {
negative = my_negative;
sub_by_internal3(&mut my, &ot);
}
Ordering::Equal => {
// -2 + 2
my[0] = 0;
my[1] = 0;
my[2] = 0;
}
}
carry = 0;
}
// If we have a carry we underflowed.
// We need to lose some significant digits (if possible)
if carry > 0 {
if final_scale == 0 {
return CalculationResult::Overflow;
}
// Copy it over to a temp array for modification
let mut temp = [my[0], my[1], my[2], carry];
while final_scale > 0 && temp[3] != 0 {
div_by_u32(&mut temp, 10);
final_scale -= 1;
}
// If we still have a carry bit then we overflowed
if temp[3] > 0 {
return CalculationResult::Overflow;
}
// Copy it back - we're done
my[0] = temp[0];
my[1] = temp[1];
my[2] = temp[2];
}
CalculationResult::Ok(Decimal::from_parts(my[0], my[1], my[2], negative, final_scale))
}
pub(crate) fn sub_impl(d1: &Decimal, d2: &Decimal) -> CalculationResult {
add_impl(d1, &(-*d2))
}
pub(crate) fn div_impl(d1: &Decimal, d2: &Decimal) -> CalculationResult {
if d2.is_zero() {
return CalculationResult::DivByZero;
}
if d1.is_zero() {
return CalculationResult::Ok(Decimal::zero());
}
let dividend = d1.mantissa_array3();
let divisor = d2.mantissa_array3();
let mut quotient = [0u32, 0u32, 0u32];
let mut quotient_scale: i32 = d1.scale() as i32 - d2.scale() as i32;
// We supply an extra overflow word for each of the dividend and the remainder
let mut working_quotient = [dividend[0], dividend[1], dividend[2], 0u32];
let mut working_remainder = [0u32, 0u32, 0u32, 0u32];
let mut working_scale = quotient_scale;
let mut remainder_scale = quotient_scale;
let mut underflow;
loop {
div_internal(&mut working_quotient, &mut working_remainder, &divisor);
underflow = add_with_scale_internal(
&mut quotient,
&mut quotient_scale,
&mut working_quotient,
&mut working_scale,
);
// Multiply the remainder by 10
let mut overflow = 0;
for part in working_remainder.iter_mut() {
let (lo, hi) = mul_part(*part, 10, overflow);
*part = lo;
overflow = hi;
}
// Copy temp remainder into the temp quotient section
working_quotient.copy_from_slice(&working_remainder);
remainder_scale += 1;
working_scale = remainder_scale;
if underflow || is_all_zero(&working_remainder) {
break;
}
}
// If we have a really big number try to adjust the scale to 0
while quotient_scale < 0 {
copy_array_diff_lengths(&mut working_quotient, &quotient);
working_quotient[3] = 0;
working_remainder.iter_mut().for_each(|x| *x = 0);
// Mul 10
let mut overflow = 0;
for part in &mut working_quotient {
let (lo, hi) = mul_part(*part, 10, overflow);
*part = lo;
overflow = hi;
}
for part in &mut working_remainder {
let (lo, hi) = mul_part(*part, 10, overflow);
*part = lo;
overflow = hi;
}
if working_quotient[3] == 0 && is_all_zero(&working_remainder) {
quotient_scale += 1;
quotient[0] = working_quotient[0];
quotient[1] = working_quotient[1];
quotient[2] = working_quotient[2];
} else {
// Overflow
return CalculationResult::Overflow;
}
}
if quotient_scale > 255 {
quotient[0] = 0;
quotient[1] = 0;
quotient[2] = 0;
quotient_scale = 0;
}
let mut quotient_negative = d1.is_sign_negative() ^ d2.is_sign_negative();
// Check for underflow
let mut final_scale: u32 = quotient_scale as u32;
if final_scale > MAX_PRECISION {
let mut remainder = 0;
// Division underflowed. We must remove some significant digits over using
// an invalid scale.
while final_scale > MAX_PRECISION && !is_all_zero(&quotient) {
remainder = div_by_u32(&mut quotient, 10);
final_scale -= 1;
}
if final_scale > MAX_PRECISION {
// Result underflowed so set to zero
final_scale = 0;
quotient_negative = false;
} else if remainder >= 5 {
for part in &mut quotient {
if remainder == 0 {
break;
}
let digit: u64 = u64::from(*part) + 1;
remainder = if digit > 0xFFFF_FFFF { 1 } else { 0 };
*part = (digit & 0xFFFF_FFFF) as u32;
}
}
}
CalculationResult::Ok(Decimal::from_parts(
quotient[0],
quotient[1],
quotient[2],
quotient_negative,
final_scale,
))
}
pub(crate) fn mul_impl(d1: &Decimal, d2: &Decimal) -> CalculationResult {
// Early exit if either is zero
if d1.is_zero() || d2.is_zero() {
return CalculationResult::Ok(Decimal::zero());
}
// We are only resulting in a negative if we have mismatched signs
let negative = d1.is_sign_negative() ^ d2.is_sign_negative();
// We get the scale of the result by adding the operands. This may be too big, however
// we'll correct later
let mut final_scale = d1.scale() + d2.scale();
// First of all, if ONLY the lo parts of both numbers is filled
// then we can simply do a standard 64 bit calculation. It's a minor
// optimization however prevents the need for long form multiplication
let my = d1.mantissa_array3();
let ot = d2.mantissa_array3();
if my[1] == 0 && my[2] == 0 && ot[1] == 0 && ot[2] == 0 {
// Simply multiplication
let mut u64_result = u64_to_array(u64::from(my[0]) * u64::from(ot[0]));
// If we're above max precision then this is a very small number
if final_scale > MAX_PRECISION {
final_scale -= MAX_PRECISION;
// If the number is above 19 then this will equate to zero.
// This is because the max value in 64 bits is 1.84E19
if final_scale > 19 {
return CalculationResult::Ok(Decimal::zero());
}
let mut rem_lo = 0;
let mut power;
if final_scale > 9 {
// Since 10^10 doesn't fit into u32, we divide by 10^10/4
// and multiply the next divisor by 4.
rem_lo = div_by_u32(&mut u64_result, 2_500_000_000);
power = POWERS_10[final_scale as usize - 10] << 2;
} else {
power = POWERS_10[final_scale as usize];
}
// Divide fits in 32 bits
let rem_hi = div_by_u32(&mut u64_result, power);
// Round the result. Since the divisor is a power of 10
// we check to see if the remainder is >= 1/2 divisor
power >>= 1;
if rem_hi >= power && (rem_hi > power || (rem_lo | (u64_result[0] & 0x1)) != 0) {
u64_result[0] += 1;
}
final_scale = MAX_PRECISION;
}
return CalculationResult::Ok(Decimal::from_parts(
u64_result[0],
u64_result[1],
0,
negative,
final_scale,
));
}
// We're using some of the high bits, so we essentially perform
// long form multiplication. We compute the 9 partial products
// into a 192 bit result array.
//
// [my-h][my-m][my-l]
// x [ot-h][ot-m][ot-l]
// --------------------------------------
// 1. [r-hi][r-lo] my-l * ot-l [0, 0]
// 2. [r-hi][r-lo] my-l * ot-m [0, 1]
// 3. [r-hi][r-lo] my-m * ot-l [1, 0]
// 4. [r-hi][r-lo] my-m * ot-m [1, 1]
// 5. [r-hi][r-lo] my-l * ot-h [0, 2]
// 6. [r-hi][r-lo] my-h * ot-l [2, 0]
// 7. [r-hi][r-lo] my-m * ot-h [1, 2]
// 8. [r-hi][r-lo] my-h * ot-m [2, 1]
// 9.[r-hi][r-lo] my-h * ot-h [2, 2]
let mut product = [0u32, 0u32, 0u32, 0u32, 0u32, 0u32];
// We can perform a minor short circuit here. If the
// high portions are both 0 then we can skip portions 5-9
let to = if my[2] == 0 && ot[2] == 0 { 2 } else { 3 };
for (my_index, my_item) in my.iter().enumerate().take(to) {
for (ot_index, ot_item) in ot.iter().enumerate().take(to) {
let (mut rlo, mut rhi) = mul_part(*my_item, *ot_item, 0);
// Get the index for the lo portion of the product
for prod in product.iter_mut().skip(my_index + ot_index) {
let (res, overflow) = add_part(rlo, *prod);
*prod = res;
// If we have something in rhi from before then promote that
if rhi > 0 {
// If we overflowed in the last add, add that with rhi
if overflow > 0 {
let (nlo, nhi) = add_part(rhi, overflow);
rlo = nlo;
rhi = nhi;
} else {
rlo = rhi;
rhi = 0;
}
} else if overflow > 0 {
rlo = overflow;
rhi = 0;
} else {
break;
}
// If nothing to do next round then break out
if rlo == 0 {
break;
}
}
}
}
// If our result has used up the high portion of the product
// then we either have an overflow or an underflow situation
// Overflow will occur if we can't scale it back, whereas underflow
// with kick in rounding
let mut remainder = 0;
while final_scale > 0 && (product[3] != 0 || product[4] != 0 || product[5] != 0) {
remainder = div_by_u32(&mut product, 10u32);
final_scale -= 1;
}
// Round up the carry if we need to
if remainder >= 5 {
for part in product.iter_mut() {
if remainder == 0 {
break;
}
let digit: u64 = u64::from(*part) + 1;
remainder = if digit > 0xFFFF_FFFF { 1 } else { 0 };
*part = (digit & 0xFFFF_FFFF) as u32;
}
}
// If we're still above max precision then we'll try again to
// reduce precision - we may be dealing with a limit of "0"
if final_scale > MAX_PRECISION {
// We're in an underflow situation
// The easiest way to remove precision is to divide off the result
while final_scale > MAX_PRECISION && !is_all_zero(&product) {
div_by_u32(&mut product, 10);
final_scale -= 1;
}
// If we're still at limit then we can't represent any
// significant decimal digits and will return an integer only
// Can also be invoked while representing 0.
if final_scale > MAX_PRECISION {
final_scale = 0;
}
} else if !(product[3] == 0 && product[4] == 0 && product[5] == 0) {
// We're in an overflow situation - we're within our precision bounds
// but still have bits in overflow
return CalculationResult::Overflow;
}
CalculationResult::Ok(Decimal::from_parts(
product[0],
product[1],
product[2],
negative,
final_scale,
))
}
pub(crate) fn rem_impl(d1: &Decimal, d2: &Decimal) -> CalculationResult {
if d2.is_zero() {
return CalculationResult::DivByZero;
}
if d1.is_zero() {
return CalculationResult::Ok(Decimal::zero());
}
// Rescale so comparable
let initial_scale = d1.scale();
let mut quotient = d1.mantissa_array3();
let mut quotient_scale = initial_scale;
let mut divisor = d2.mantissa_array3();
let mut divisor_scale = d2.scale();
rescale_to_maximum_scale(&mut quotient, &mut quotient_scale, &mut divisor, &mut divisor_scale);
// Working is the remainder + the quotient
// We use an aligned array since we'll be using it a lot.
let mut working_quotient = [quotient[0], quotient[1], quotient[2], 0u32];
let mut working_remainder = [0u32, 0u32, 0u32, 0u32];
div_internal(&mut working_quotient, &mut working_remainder, &divisor);
// Round if necessary. This is for semantic correctness, but could feasibly be removed for
// performance improvements.
if quotient_scale > initial_scale {
let mut working = [
working_remainder[0],
working_remainder[1],
working_remainder[2],
working_remainder[3],
];
while quotient_scale > initial_scale {
if div_by_u32(&mut working, 10) > 0 {
break;
}
quotient_scale -= 1;
working_remainder.copy_from_slice(&working);
}
}
CalculationResult::Ok(Decimal::from_parts(
working_remainder[0],
working_remainder[1],
working_remainder[2],
d1.is_sign_negative(),
quotient_scale,
))
}
pub(crate) fn cmp_impl(d1: &Decimal, d2: &Decimal) -> Ordering {
// Quick exit if major differences
if d1.is_zero() && d2.is_zero() {
return Ordering::Equal;
}
let self_negative = d1.is_sign_negative();
let other_negative = d2.is_sign_negative();
if self_negative && !other_negative {
return Ordering::Less;
} else if !self_negative && other_negative {
return Ordering::Greater;
}
// If we have 1.23 and 1.2345 then we have
// 123 scale 2 and 12345 scale 4
// We need to convert the first to
// 12300 scale 4 so we can compare equally
let left: &Decimal;
let right: &Decimal;
if self_negative && other_negative {
// Both are negative, so reverse cmp
left = d2;
right = d1;
} else {
left = d1;
right = d2;
}
let mut left_scale = left.scale();
let mut right_scale = right.scale();
let mut left_raw = left.mantissa_array3();
let mut right_raw = right.mantissa_array3();
if left_scale == right_scale {
// Fast path for same scale
if left_raw[2] != right_raw[2] {
return left_raw[2].cmp(&right_raw[2]);
}
if left_raw[1] != right_raw[1] {
return left_raw[1].cmp(&right_raw[1]);
}
return left_raw[0].cmp(&right_raw[0]);
}
// Rescale and compare
rescale_to_maximum_scale(&mut left_raw, &mut left_scale, &mut right_raw, &mut right_scale);
cmp_internal(&left_raw, &right_raw)
}
#[inline]
fn add_part(left: u32, right: u32) -> (u32, u32) {
let added = u64::from(left) + u64::from(right);
((added & U32_MASK) as u32, (added >> 32 & U32_MASK) as u32)
}
#[inline(always)]
fn sub_by_internal3(value: &mut [u32; 3], by: &[u32; 3]) {
let mut overflow = 0;
let vl = value.len();
for i in 0..vl {
let part = (0x1_0000_0000u64 + u64::from(value[i])) - (u64::from(by[i]) + overflow);
value[i] = part as u32;
overflow = 1 - (part >> 32);
}
}
fn div_internal(quotient: &mut [u32; 4], remainder: &mut [u32; 4], divisor: &[u32; 3]) {
// There are a couple of ways to do division on binary numbers:
// 1. Using long division
// 2. Using the complement method
// ref: http://paulmason.me/dividing-binary-numbers-part-2/
// The complement method basically keeps trying to subtract the
// divisor until it can't anymore and placing the rest in remainder.
let mut complement = [
divisor[0] ^ 0xFFFF_FFFF,
divisor[1] ^ 0xFFFF_FFFF,
divisor[2] ^ 0xFFFF_FFFF,
0xFFFF_FFFF,
];
// Add one onto the complement
add_one_internal4(&mut complement);
// Make sure the remainder is 0
remainder.iter_mut().for_each(|x| *x = 0);
// If we have nothing in our hi+ block then shift over till we do
let mut blocks_to_process = 0;
while blocks_to_process < 4 && quotient[3] == 0 {
// memcpy would be useful here
quotient[3] = quotient[2];
quotient[2] = quotient[1];
quotient[1] = quotient[0];
quotient[0] = 0;
// Increment the counter
blocks_to_process += 1;
}
// Let's try and do the addition...
let mut block = blocks_to_process << 5;
let mut working = [0u32, 0u32, 0u32, 0u32];
while block < 128 {
// << 1 for quotient AND remainder. Moving the carry from the quotient to the bottom of the
// remainder.
let carry = shl1_internal(quotient, 0);
shl1_internal(remainder, carry);
// Copy the remainder of working into sub
working.copy_from_slice(remainder);
// Add the remainder with the complement
add_by_internal(&mut working, &complement);
// Check for the significant bit - move over to the quotient
// as necessary
if (working[3] & 0x8000_0000) == 0 {
remainder.copy_from_slice(&working);
quotient[0] |= 1;
}
// Increment our pointer
block += 1;
}
}
#[inline]
fn copy_array_diff_lengths(into: &mut [u32], from: &[u32]) {
for i in 0..into.len() {
if i >= from.len() {
break;
}
into[i] = from[i];
}
}
#[inline]
fn add_one_internal4(value: &mut [u32; 4]) -> u32 {
let mut carry: u64 = 1; // Start with one, since adding one
let mut sum: u64;
for i in value.iter_mut() {
sum = (*i as u64) + carry;
*i = (sum & U32_MASK) as u32;
carry = sum >> 32;
}
carry as u32
}
#[inline]
fn add_by_internal3(value: &mut [u32; 3], by: &[u32; 3]) -> u32 {
let mut carry: u32 = 0;
let bl = by.len();
for i in 0..bl {
let res1 = value[i].overflowing_add(by[i]);
let res2 = res1.0.overflowing_add(carry);
value[i] = res2.0;
carry = (res1.1 | res2.1) as u32;
}
carry
}
#[inline]
const fn u64_to_array(value: u64) -> [u32; 2] {
[(value & U32_MASK) as u32, (value >> 32 & U32_MASK) as u32]
}
fn add_with_scale_internal(
quotient: &mut [u32; 3],
quotient_scale: &mut i32,
working_quotient: &mut [u32; 4],
working_scale: &mut i32,
) -> bool {
// Add quotient and the working (i.e. quotient = quotient + working)
if is_all_zero(quotient) {
// Quotient is zero so we can just copy the working quotient in directly
// First, make sure they are both 96 bit.
while working_quotient[3] != 0 {
div_by_u32(working_quotient, 10);
*working_scale -= 1;
}
copy_array_diff_lengths(quotient, working_quotient);
*quotient_scale = *working_scale;
return false;
}
if is_all_zero(working_quotient) {
return false;
}
// We have ensured that our working is not zero so we should do the addition
// If our two quotients are different then
// try to scale down the one with the bigger scale
let mut temp3 = [0u32, 0u32, 0u32];
let mut temp4 = [0u32, 0u32, 0u32, 0u32];
if *quotient_scale != *working_scale {
// TODO: Remove necessity for temp (without performance impact)
fn div_by_10(target: &mut [u32], temp: &mut [u32], scale: &mut i32, target_scale: i32) {
// Copy to the temp array
temp.copy_from_slice(target);
// divide by 10 until target scale is reached
while *scale > target_scale {
let remainder = div_by_u32(temp, 10);
if remainder == 0 {
*scale -= 1;
target.copy_from_slice(&temp);
} else {
break;
}
}
}
if *quotient_scale < *working_scale {
div_by_10(working_quotient, &mut temp4, working_scale, *quotient_scale);
} else {
div_by_10(quotient, &mut temp3, quotient_scale, *working_scale);
}
}
// If our two quotients are still different then
// try to scale up the smaller scale
if *quotient_scale != *working_scale {
// TODO: Remove necessity for temp (without performance impact)
fn mul_by_10(target: &mut [u32], temp: &mut [u32], scale: &mut i32, target_scale: i32) {
temp.copy_from_slice(target);
let mut overflow = 0;
// Multiply by 10 until target scale reached or overflow
while *scale < target_scale && overflow == 0 {
overflow = mul_by_u32(temp, 10);
if overflow == 0 {
// Still no overflow
*scale += 1;
target.copy_from_slice(&temp);
}
}
}
if *quotient_scale > *working_scale {
mul_by_10(working_quotient, &mut temp4, working_scale, *quotient_scale);
} else {
mul_by_10(quotient, &mut temp3, quotient_scale, *working_scale);
}
}
// If our two quotients are still different then
// try to scale down the one with the bigger scale
// (ultimately losing significant digits)
if *quotient_scale != *working_scale {
// TODO: Remove necessity for temp (without performance impact)
fn div_by_10_lossy(target: &mut [u32], temp: &mut [u32], scale: &mut i32, target_scale: i32) {
temp.copy_from_slice(target);
// divide by 10 until target scale is reached
while *scale > target_scale {
div_by_u32(temp, 10);
*scale -= 1;
target.copy_from_slice(&temp);
}
}
if *quotient_scale < *working_scale {
div_by_10_lossy(working_quotient, &mut temp4, working_scale, *quotient_scale);
} else {
div_by_10_lossy(quotient, &mut temp3, quotient_scale, *working_scale);
}
}
// If quotient or working are zero we have an underflow condition
if is_all_zero(quotient) || is_all_zero(working_quotient) {
// Underflow
return true;
} else {
// Both numbers have the same scale and can be added.
// We just need to know whether we can fit them in
let mut underflow = false;
let mut temp = [0u32, 0u32, 0u32];
while !underflow {
temp.copy_from_slice(quotient);
// Add the working quotient
let overflow = add_by_internal(&mut temp, working_quotient);
if overflow == 0 {
// addition was successful
quotient.copy_from_slice(&temp);
break;
} else {
// addition overflowed - remove significant digits and try again
div_by_u32(quotient, 10);
*quotient_scale -= 1;
div_by_u32(working_quotient, 10);
*working_scale -= 1;
// Check for underflow
underflow = is_all_zero(quotient) || is_all_zero(working_quotient);
}
}
if underflow {
return true;
}
}
false
}
/// Rescales the given decimals to equivalent scales.
/// It will firstly try to scale both the left and the right side to
/// the maximum scale of left/right. If it is unable to do that it
/// will try to reduce the accuracy of the other argument.
/// e.g. with 1.23 and 2.345 it'll rescale the first arg to 1.230
#[inline(always)]
fn rescale_to_maximum_scale(left: &mut [u32; 3], left_scale: &mut u32, right: &mut [u32; 3], right_scale: &mut u32) {
if left_scale == right_scale {
// Nothing to do
return;
}
if is_all_zero(left) {
*left_scale = *right_scale;
return;
} else if is_all_zero(right) {
*right_scale = *left_scale;
return;
}
if left_scale > right_scale {
rescale_internal(right, right_scale, *left_scale);
if right_scale != left_scale {
rescale_internal(left, left_scale, *right_scale);
}
} else {
rescale_internal(left, left_scale, *right_scale);
if right_scale != left_scale {
rescale_internal(right, right_scale, *left_scale);
}
}
}
#[cfg(test)]
mod test {
// Tests on private methods.
//
// All public tests should go under `tests/`.
use super::*;
use crate::prelude::*;
#[test]
fn it_can_rescale_to_maximum_scale() {
fn extract(value: &str) -> ([u32; 3], u32) {
let v = Decimal::from_str(value).unwrap();
(v.mantissa_array3(), v.scale())
}
let tests = &[
("1", "1", "1", "1"),
("1", "1.0", "1.0", "1.0"),
("1", "1.00000", "1.00000", "1.00000"),
("1", "1.0000000000", "1.0000000000", "1.0000000000"),
(
"1",
"1.00000000000000000000",
"1.00000000000000000000",
"1.00000000000000000000",
),
("1.1", "1.1", "1.1", "1.1"),
("1.1", "1.10000", "1.10000", "1.10000"),
("1.1", "1.1000000000", "1.1000000000", "1.1000000000"),
(
"1.1",
"1.10000000000000000000",
"1.10000000000000000000",
"1.10000000000000000000",
),
(
"0.6386554621848739495798319328",
"11.815126050420168067226890757",
"0.638655462184873949579831933",
"11.815126050420168067226890757",
),
(
"0.0872727272727272727272727272", // Scale 28
"843.65000000", // Scale 8
"0.0872727272727272727272727", // 25
"843.6500000000000000000000000", // 25
),
];
for &(left_raw, right_raw, expected_left, expected_right) in tests {
// Left = the value to rescale
// Right = the new scale we're scaling to
// Expected = the expected left value after rescale
let (expected_left, expected_lscale) = extract(expected_left);
let (expected_right, expected_rscale) = extract(expected_right);
let (mut left, mut left_scale) = extract(left_raw);
let (mut right, mut right_scale) = extract(right_raw);
rescale_to_maximum_scale(&mut left, &mut left_scale, &mut right, &mut right_scale);
assert_eq!(left, expected_left);
assert_eq!(left_scale, expected_lscale);
assert_eq!(right, expected_right);
assert_eq!(right_scale, expected_rscale);
// Also test the transitive case
let (mut left, mut left_scale) = extract(left_raw);
let (mut right, mut right_scale) = extract(right_raw);
rescale_to_maximum_scale(&mut right, &mut right_scale, &mut left, &mut left_scale);
assert_eq!(left, expected_left);
assert_eq!(left_scale, expected_lscale);
assert_eq!(right, expected_right);
assert_eq!(right_scale, expected_rscale);
}
}
}

168
third_party/rust/rust_decimal/src/ops/mul.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,168 @@
use crate::constants::{BIG_POWERS_10, MAX_I64_SCALE, MAX_PRECISION, U32_MAX};
use crate::decimal::{CalculationResult, Decimal};
use crate::ops::common::Buf24;
pub(crate) fn mul_impl(d1: &Decimal, d2: &Decimal) -> CalculationResult {
if d1.is_zero() || d2.is_zero() {
// We should think about this - does zero need to maintain precision? This treats it like
// an absolute which I think is ok, especially since we have is_zero() functions etc.
return CalculationResult::Ok(Decimal::ZERO);
}
let mut scale = d1.scale() + d2.scale();
let negative = d1.is_sign_negative() ^ d2.is_sign_negative();
let mut product = Buf24::zero();
// See if we can optimize this calculation depending on whether the hi bits are set
if d1.hi() | d1.mid() == 0 {
if d2.hi() | d2.mid() == 0 {
// We're multiplying two 32 bit integers, so we can take some liberties to optimize this.
let mut low64 = d1.lo() as u64 * d2.lo() as u64;
if scale > MAX_PRECISION {
// We've exceeded maximum scale so we need to start reducing the precision (aka
// rounding) until we have something that fits.
// If we're too big then we effectively round to zero.
if scale > MAX_PRECISION + MAX_I64_SCALE {
return CalculationResult::Ok(Decimal::ZERO);
}
scale -= MAX_PRECISION + 1;
let mut power = BIG_POWERS_10[scale as usize];
let tmp = low64 / power;
let remainder = low64 - tmp * power;
low64 = tmp;
// Round the result. Since the divisor was a power of 10, it's always even.
power >>= 1;
if remainder >= power && (remainder > power || (low64 as u32 & 1) > 0) {
low64 += 1;
}
scale = MAX_PRECISION;
}
// Early exit
return CalculationResult::Ok(Decimal::from_parts(
low64 as u32,
(low64 >> 32) as u32,
0,
negative,
scale,
));
}
// We know that the left hand side is just 32 bits but the right hand side is either
// 64 or 96 bits.
mul_by_32bit_lhs(d1.lo() as u64, &d2, &mut product);
} else if d2.mid() | d2.hi() == 0 {
// We know that the right hand side is just 32 bits.
mul_by_32bit_lhs(d2.lo() as u64, &d1, &mut product);
} else {
// We know we're not dealing with simple 32 bit operands on either side.
// We compute and accumulate the 9 partial products using long multiplication
// 1: ll * rl
let mut tmp = d1.lo() as u64 * d2.lo() as u64;
product.data[0] = tmp as u32;
// 2: ll * rm
let mut tmp2 = (d1.lo() as u64 * d2.mid() as u64).wrapping_add(tmp >> 32);
// 3: lm * rl
tmp = d1.mid() as u64 * d2.lo() as u64;
tmp = tmp.wrapping_add(tmp2);
product.data[1] = tmp as u32;
// Detect if carry happened from the wrapping add
if tmp < tmp2 {
tmp2 = (tmp >> 32) | (1u64 << 32);
} else {
tmp2 = tmp >> 32;
}
// 4: lm * rm
tmp = (d1.mid() as u64 * d2.mid() as u64) + tmp2;
// If the high bit isn't set then we can stop here. Otherwise, we need to continue calculating
// using the high bits.
if (d1.hi() | d2.hi()) > 0 {
// 5. ll * rh
tmp2 = d1.lo() as u64 * d2.hi() as u64;
tmp = tmp.wrapping_add(tmp2);
// Detect if we carried
let mut tmp3 = if tmp < tmp2 { 1 } else { 0 };
// 6. lh * rl
tmp2 = d1.hi() as u64 * d2.lo() as u64;
tmp = tmp.wrapping_add(tmp2);
product.data[2] = tmp as u32;
// Detect if we carried
if tmp < tmp2 {
tmp3 += 1;
}
tmp2 = (tmp3 << 32) | (tmp >> 32);
// 7. lm * rh
tmp = d1.mid() as u64 * d2.hi() as u64;
tmp = tmp.wrapping_add(tmp2);
// Check for carry
tmp3 = if tmp < tmp2 { 1 } else { 0 };
// 8. lh * rm
tmp2 = d1.hi() as u64 * d2.mid() as u64;
tmp = tmp.wrapping_add(tmp2);
product.data[3] = tmp as u32;
// Check for carry
if tmp < tmp2 {
tmp3 += 1;
}
tmp = (tmp3 << 32) | (tmp >> 32);
// 9. lh * rh
product.set_high64(d1.hi() as u64 * d2.hi() as u64 + tmp);
} else {
product.set_mid64(tmp);
}
}
// We may want to "rescale". This is the case if the mantissa is > 96 bits or if the scale
// exceeds the maximum precision.
let upper_word = product.upper_word();
if upper_word > 2 || scale > MAX_PRECISION {
scale = if let Some(new_scale) = product.rescale(upper_word, scale) {
new_scale
} else {
return CalculationResult::Overflow;
}
}
CalculationResult::Ok(Decimal::from_parts(
product.data[0],
product.data[1],
product.data[2],
negative,
scale,
))
}
#[inline(always)]
fn mul_by_32bit_lhs(d1: u64, d2: &Decimal, product: &mut Buf24) {
let mut tmp = d1 * d2.lo() as u64;
product.data[0] = tmp as u32;
tmp = (d1 * d2.mid() as u64).wrapping_add(tmp >> 32);
product.data[1] = tmp as u32;
tmp >>= 32;
// If we're multiplying by a 96 bit integer then continue the calculation
if d2.hi() > 0 {
tmp = tmp.wrapping_add(d1 * d2.hi() as u64);
if tmp > U32_MAX {
product.set_mid64(tmp);
} else {
product.data[2] = tmp as u32;
}
} else {
product.data[2] = tmp as u32;
}
}

287
third_party/rust/rust_decimal/src/ops/rem.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,287 @@
use crate::constants::{MAX_I32_SCALE, MAX_PRECISION_I32, POWERS_10};
use crate::decimal::{CalculationResult, Decimal};
use crate::ops::common::{Buf12, Buf16, Buf24, Dec64};
pub(crate) fn rem_impl(d1: &Decimal, d2: &Decimal) -> CalculationResult {
if d2.is_zero() {
return CalculationResult::DivByZero;
}
if d1.is_zero() {
return CalculationResult::Ok(Decimal::ZERO);
}
// We handle the structs a bit different here. Firstly, we ignore both the sign/scale of d2.
// This is because during a remainder operation we do not care about the sign of the divisor
// and only concern ourselves with that of the dividend.
let mut d1 = Dec64::new(d1);
let d2_scale = d2.scale();
let mut d2 = Buf12::from_decimal(d2);
let cmp = crate::ops::cmp::cmp_internal(
&d1,
&Dec64 {
negative: d1.negative,
scale: d2_scale,
hi: d2.hi(),
low64: d2.low64(),
},
);
match cmp {
core::cmp::Ordering::Equal => {
// Same numbers meaning that remainder is zero
return CalculationResult::Ok(Decimal::ZERO);
}
core::cmp::Ordering::Less => {
// d1 < d2, e.g. 1/2. This means that the result is the value of d1
return CalculationResult::Ok(d1.to_decimal());
}
core::cmp::Ordering::Greater => {}
}
// At this point we know that the dividend > divisor and that they are both non-zero.
let mut scale = d1.scale as i32 - d2_scale as i32;
if scale > 0 {
// Scale up the divisor
loop {
let power = if scale >= MAX_I32_SCALE {
POWERS_10[9]
} else {
POWERS_10[scale as usize]
} as u64;
let mut tmp = d2.lo() as u64 * power;
d2.set_lo(tmp as u32);
tmp >>= 32;
tmp = tmp.wrapping_add((d2.mid() as u64 + ((d2.hi() as u64) << 32)) * power);
d2.set_mid(tmp as u32);
d2.set_hi((tmp >> 32) as u32);
// Keep scaling if there is more to go
scale -= MAX_I32_SCALE;
if scale <= 0 {
break;
}
}
scale = 0;
}
loop {
// If the dividend is smaller than the divisor then try to scale that up first
if scale < 0 {
let mut quotient = Buf12 {
data: [d1.lo(), d1.mid(), d1.hi],
};
loop {
// Figure out how much we can scale by
let power_scale;
if let Some(u) = quotient.find_scale(MAX_PRECISION_I32 + scale) {
if u >= POWERS_10.len() {
power_scale = 9;
} else {
power_scale = u;
}
} else {
return CalculationResult::Overflow;
};
if power_scale == 0 {
break;
}
let power = POWERS_10[power_scale] as u64;
scale += power_scale as i32;
let mut tmp = quotient.data[0] as u64 * power;
quotient.data[0] = tmp as u32;
tmp >>= 32;
quotient.set_high64(tmp.wrapping_add(quotient.high64().wrapping_mul(power)));
if power_scale != 9 {
break;
}
if scale >= 0 {
break;
}
}
d1.low64 = quotient.low64();
d1.hi = quotient.data[2];
d1.scale = d2_scale;
}
// if the high portion is empty then return the modulus of the bottom portion
if d1.hi == 0 {
d1.low64 %= d2.low64();
return CalculationResult::Ok(d1.to_decimal());
} else if (d2.mid() | d2.hi()) == 0 {
let mut tmp = d1.high64();
tmp = ((tmp % d2.lo() as u64) << 32) | (d1.lo() as u64);
d1.low64 = tmp % d2.lo() as u64;
d1.hi = 0;
} else {
// Divisor is > 32 bits
return rem_full(&d1, &d2, scale);
}
if scale >= 0 {
break;
}
}
CalculationResult::Ok(d1.to_decimal())
}
fn rem_full(d1: &Dec64, d2: &Buf12, scale: i32) -> CalculationResult {
let mut scale = scale;
// First normalize the divisor
let shift = if d2.hi() == 0 {
d2.mid().leading_zeros()
} else {
d2.hi().leading_zeros()
};
let mut buffer = Buf24::zero();
let mut overflow = 0u32;
buffer.set_low64(d1.low64 << shift);
buffer.set_mid64(((d1.mid() as u64).wrapping_add((d1.hi as u64) << 32)) >> (32 - shift));
let mut upper = 3; // We start at 3 due to bit shifting
while scale < 0 {
let power = if -scale >= MAX_I32_SCALE {
POWERS_10[9]
} else {
POWERS_10[-scale as usize]
} as u64;
let mut tmp64 = buffer.data[0] as u64 * power;
buffer.data[0] = tmp64 as u32;
for (index, part) in buffer.data.iter_mut().enumerate().skip(1) {
if index > upper {
break;
}
tmp64 >>= 32;
tmp64 = tmp64.wrapping_add((*part as u64).wrapping_mul(power));
*part = tmp64 as u32;
}
// If we have overflow then also process that
if upper == 6 {
tmp64 >>= 32;
tmp64 = tmp64.wrapping_add((overflow as u64).wrapping_mul(power));
overflow = tmp64 as u32;
}
// Make sure the high bit is not set
if tmp64 > 0x7FFF_FFFF {
upper += 1;
if upper > 5 {
overflow = (tmp64 >> 32) as u32;
} else {
buffer.data[upper] = (tmp64 >> 32) as u32;
}
}
scale += MAX_I32_SCALE;
}
// TODO: Optimize slice logic
let mut tmp = Buf16::zero();
if d2.hi() == 0 {
// 64 bit divisor so we adjust accordingly
let divisor = d2.low64() << shift;
// Do some division
if upper == 6 {
upper -= 1;
tmp.data = [buffer.data[4], buffer.data[5], overflow, 0];
tmp.partial_divide_64(divisor);
buffer.data[4] = tmp.data[0];
buffer.data[5] = tmp.data[1];
}
if upper == 5 {
upper -= 1;
tmp.data = [buffer.data[3], buffer.data[4], buffer.data[5], 0];
tmp.partial_divide_64(divisor);
buffer.data[3] = tmp.data[0];
buffer.data[4] = tmp.data[1];
buffer.data[5] = tmp.data[2];
}
if upper == 4 {
tmp.data = [buffer.data[2], buffer.data[3], buffer.data[4], 0];
tmp.partial_divide_64(divisor);
buffer.data[2] = tmp.data[0];
buffer.data[3] = tmp.data[1];
buffer.data[4] = tmp.data[2];
}
tmp.data = [buffer.data[1], buffer.data[2], buffer.data[3], 0];
tmp.partial_divide_64(divisor);
buffer.data[1] = tmp.data[0];
buffer.data[2] = tmp.data[1];
buffer.data[3] = tmp.data[2];
tmp.data = [buffer.data[0], buffer.data[1], buffer.data[2], 0];
tmp.partial_divide_64(divisor);
buffer.data[0] = tmp.data[0];
buffer.data[1] = tmp.data[1];
buffer.data[2] = tmp.data[2];
let low64 = buffer.low64() >> shift;
CalculationResult::Ok(Decimal::from_parts(
low64 as u32,
(low64 >> 32) as u32,
0,
d1.negative,
d1.scale,
))
} else {
let divisor_low64 = d2.low64() << shift;
let divisor = Buf12 {
data: [
divisor_low64 as u32,
(divisor_low64 >> 32) as u32,
(((d2.mid() as u64) + ((d2.hi() as u64) << 32)) >> (32 - shift)) as u32,
],
};
// Do some division
if upper == 6 {
upper -= 1;
tmp.data = [buffer.data[3], buffer.data[4], buffer.data[5], overflow];
tmp.partial_divide_96(&divisor);
buffer.data[3] = tmp.data[0];
buffer.data[4] = tmp.data[1];
buffer.data[5] = tmp.data[2];
}
if upper == 5 {
upper -= 1;
tmp.data = [buffer.data[2], buffer.data[3], buffer.data[4], buffer.data[5]];
tmp.partial_divide_96(&divisor);
buffer.data[2] = tmp.data[0];
buffer.data[3] = tmp.data[1];
buffer.data[4] = tmp.data[2];
buffer.data[5] = tmp.data[3];
}
if upper == 4 {
tmp.data = [buffer.data[1], buffer.data[2], buffer.data[3], buffer.data[4]];
tmp.partial_divide_96(&divisor);
buffer.data[1] = tmp.data[0];
buffer.data[2] = tmp.data[1];
buffer.data[3] = tmp.data[2];
buffer.data[4] = tmp.data[3];
}
tmp.data = [buffer.data[0], buffer.data[1], buffer.data[2], buffer.data[3]];
tmp.partial_divide_96(&divisor);
buffer.data[0] = tmp.data[0];
buffer.data[1] = tmp.data[1];
buffer.data[2] = tmp.data[2];
buffer.data[3] = tmp.data[3];
let low64 = (buffer.low64() >> shift) + ((buffer.data[2] as u64) << (32 - shift) << 32);
CalculationResult::Ok(Decimal::from_parts(
low64 as u32,
(low64 >> 32) as u32,
buffer.data[2] >> shift,
d1.negative,
d1.scale,
))
}
}

Просмотреть файл

@ -1,12 +1,10 @@
use crate::Decimal;
use alloc::string::ToString;
use core::{fmt, str::FromStr};
use num_traits::FromPrimitive;
use serde::{self, de::Unexpected};
use std::{fmt, str::FromStr};
#[cfg(not(feature = "serde-bincode"))]
#[cfg(not(feature = "serde-str"))]
impl<'de> serde::Deserialize<'de> for Decimal {
fn deserialize<D>(deserializer: D) -> Result<Decimal, D::Error>
where
@ -16,7 +14,7 @@ impl<'de> serde::Deserialize<'de> for Decimal {
}
}
#[cfg(all(feature = "serde-bincode", not(feature = "serde-float")))]
#[cfg(all(feature = "serde-str", not(feature = "serde-float")))]
impl<'de> serde::Deserialize<'de> for Decimal {
fn deserialize<D>(deserializer: D) -> Result<Decimal, D::Error>
where
@ -26,7 +24,7 @@ impl<'de> serde::Deserialize<'de> for Decimal {
}
}
#[cfg(all(feature = "serde-bincode", feature = "serde-float"))]
#[cfg(all(feature = "serde-str", feature = "serde-float"))]
impl<'de> serde::Deserialize<'de> for Decimal {
fn deserialize<D>(deserializer: D) -> Result<Decimal, D::Error>
where
@ -36,6 +34,10 @@ impl<'de> serde::Deserialize<'de> for Decimal {
}
}
// It's a shame this needs to be redefined for this feature and not able to be referenced directly
#[cfg(feature = "serde-arbitrary-precision")]
const DECIMAL_KEY_TOKEN: &str = "$serde_json::private::Number";
struct DecimalVisitor;
impl<'de> serde::de::Visitor<'de> for DecimalVisitor {
@ -80,6 +82,90 @@ impl<'de> serde::de::Visitor<'de> for DecimalVisitor {
.or_else(|_| Decimal::from_scientific(value))
.map_err(|_| E::invalid_value(Unexpected::Str(value), &self))
}
#[cfg(feature = "serde-arbitrary-precision")]
fn visit_map<A>(self, map: A) -> Result<Decimal, A::Error>
where
A: serde::de::MapAccess<'de>,
{
let mut map = map;
let value = map.next_key::<DecimalKey>()?;
if value.is_none() {
return Err(serde::de::Error::invalid_type(Unexpected::Map, &self));
}
let v: DecimalFromString = map.next_value()?;
Ok(v.value)
}
}
#[cfg(feature = "serde-arbitrary-precision")]
struct DecimalKey;
#[cfg(feature = "serde-arbitrary-precision")]
impl<'de> serde::de::Deserialize<'de> for DecimalKey {
fn deserialize<D>(deserializer: D) -> Result<DecimalKey, D::Error>
where
D: serde::de::Deserializer<'de>,
{
struct FieldVisitor;
impl<'de> serde::de::Visitor<'de> for FieldVisitor {
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a valid decimal field")
}
fn visit_str<E>(self, s: &str) -> Result<(), E>
where
E: serde::de::Error,
{
if s == DECIMAL_KEY_TOKEN {
Ok(())
} else {
Err(serde::de::Error::custom("expected field with custom name"))
}
}
}
deserializer.deserialize_identifier(FieldVisitor)?;
Ok(DecimalKey)
}
}
#[cfg(feature = "serde-arbitrary-precision")]
pub struct DecimalFromString {
pub value: Decimal,
}
#[cfg(feature = "serde-arbitrary-precision")]
impl<'de> serde::de::Deserialize<'de> for DecimalFromString {
fn deserialize<D>(deserializer: D) -> Result<DecimalFromString, D::Error>
where
D: serde::de::Deserializer<'de>,
{
struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = DecimalFromString;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("string containing a decimal")
}
fn visit_str<E>(self, value: &str) -> Result<DecimalFromString, E>
where
E: serde::de::Error,
{
let d = Decimal::from_str(value)
.or_else(|_| Decimal::from_scientific(value))
.map_err(serde::de::Error::custom)?;
Ok(DecimalFromString { value: d })
}
}
deserializer.deserialize_str(Visitor)
}
}
#[cfg(not(feature = "serde-float"))]
@ -88,7 +174,7 @@ impl serde::Serialize for Decimal {
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_string())
serializer.serialize_str(crate::str::to_str_internal(self, true, None).as_ref())
}
}
@ -105,9 +191,7 @@ impl serde::Serialize for Decimal {
#[cfg(test)]
mod test {
use super::*;
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
@ -116,7 +200,7 @@ mod test {
}
#[test]
#[cfg(not(feature = "serde-bincode"))]
#[cfg(not(feature = "serde-str"))]
fn deserialize_valid_decimal() {
let data = [
("{\"amount\":\"1.234\"}", "1.234"),
@ -129,7 +213,7 @@ mod test {
assert_eq!(
true,
result.is_ok(),
"expected successful deseralization for {}. Error: {:?}",
"expected successful deserialization for {}. Error: {:?}",
serialized,
result.err().unwrap()
);
@ -144,6 +228,14 @@ mod test {
}
}
#[test]
#[cfg(feature = "serde-arbitrary-precision")]
fn deserialize_basic_decimal() {
let d: Decimal = serde_json::from_str("1.1234127836128763").unwrap();
// Typically, this would not work without this feature enabled due to rounding
assert_eq!(d.to_string(), "1.1234127836128763");
}
#[test]
#[should_panic]
fn deserialize_invalid_decimal() {
@ -172,7 +264,7 @@ mod test {
}
#[test]
#[cfg(all(feature = "serde-bincode", not(feature = "serde-float")))]
#[cfg(all(feature = "serde-str", not(feature = "serde-float")))]
fn bincode_serialization() {
use bincode::{deserialize, serialize};
@ -183,6 +275,8 @@ mod test {
"-3.14159",
"1234567890123.4567890",
"-1234567890123.4567890",
"5233.9008808150288439427720175",
"-5233.9008808150288439427720175",
];
for &raw in data.iter() {
let value = Decimal::from_str(raw).unwrap();
@ -194,7 +288,7 @@ mod test {
}
#[test]
#[cfg(all(feature = "serde-bincode", feature = "serde-float"))]
#[cfg(all(feature = "serde-str", feature = "serde-float"))]
fn bincode_serialization() {
use bincode::{deserialize, serialize};
@ -215,4 +309,21 @@ mod test {
assert_eq!(8usize, encoded.len());
}
}
#[test]
#[cfg(all(feature = "serde-str", not(feature = "serde-float")))]
fn bincode_nested_serialization() {
// Issue #361
#[derive(Deserialize, Serialize, Debug)]
pub struct Foo {
value: Decimal,
}
let s = Foo {
value: Decimal::new(-1, 3).round_dp(0),
};
let ser = bincode::serialize(&s).unwrap();
let des: Foo = bincode::deserialize(&ser).unwrap();
assert_eq!(des.value, s.value);
}
}

529
third_party/rust/rust_decimal/src/str.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,529 @@
use crate::{
constants::MAX_STR_BUFFER_SIZE,
error::Error,
ops::array::{add_by_internal, add_one_internal, div_by_u32, is_all_zero, mul_by_10, mul_by_u32},
Decimal,
};
use arrayvec::{ArrayString, ArrayVec};
use alloc::{string::String, vec::Vec};
use core::fmt;
// impl that doesn't allocate for serialization purposes.
pub(crate) fn to_str_internal(
value: &Decimal,
append_sign: bool,
precision: Option<usize>,
) -> ArrayString<[u8; MAX_STR_BUFFER_SIZE]> {
// Get the scale - where we need to put the decimal point
let scale = value.scale() as usize;
// Convert to a string and manipulate that (neg at front, inject decimal)
let mut chars = ArrayVec::<[_; MAX_STR_BUFFER_SIZE]>::new();
let mut working = value.mantissa_array3();
while !is_all_zero(&working) {
let remainder = div_by_u32(&mut working, 10u32);
chars.push(char::from(b'0' + remainder as u8));
}
while scale > chars.len() {
chars.push('0');
}
let prec = match precision {
Some(prec) => prec,
None => scale,
};
let len = chars.len();
let whole_len = len - scale;
let mut rep = ArrayString::new();
if append_sign && value.is_sign_negative() {
rep.push('-');
}
for i in 0..whole_len + prec {
if i == len - scale {
if i == 0 {
rep.push('0');
}
rep.push('.');
}
if i >= len {
rep.push('0');
} else {
let c = chars[len - i - 1];
rep.push(c);
}
}
// corner case for when we truncated everything in a low fractional
if rep.is_empty() {
rep.push('0');
}
rep
}
pub(crate) fn fmt_scientific_notation(
value: &Decimal,
exponent_symbol: &str,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
#[cfg(not(feature = "std"))]
use alloc::string::ToString;
// Get the scale - this is the e value. With multiples of 10 this may get bigger.
let mut exponent = -(value.scale() as isize);
// Convert the integral to a string
let mut chars = Vec::new();
let mut working = value.mantissa_array3();
while !is_all_zero(&working) {
let remainder = div_by_u32(&mut working, 10u32);
chars.push(char::from(b'0' + remainder as u8));
}
// First of all, apply scientific notation rules. That is:
// 1. If non-zero digit comes first, move decimal point left so that e is a positive integer
// 2. If decimal point comes first, move decimal point right until after the first non-zero digit
// Since decimal notation naturally lends itself this way, we just need to inject the decimal
// point in the right place and adjust the exponent accordingly.
let len = chars.len();
let mut rep;
if len > 1 {
if chars.iter().take(len - 1).all(|c| *c == '0') {
// Chomp off the zero's.
rep = chars.iter().skip(len - 1).collect::<String>();
} else {
chars.insert(len - 1, '.');
rep = chars.iter().rev().collect::<String>();
}
exponent += (len - 1) as isize;
} else {
rep = chars.iter().collect::<String>();
}
rep.push_str(exponent_symbol);
rep.push_str(&exponent.to_string());
f.pad_integral(value.is_sign_positive(), "", &rep)
}
// dedicated implementation for the most common case.
pub(crate) fn parse_str_radix_10(str: &str) -> Result<Decimal, crate::Error> {
if str.is_empty() {
return Err(Error::from("Invalid decimal: empty"));
}
let mut offset = 0;
let mut len = str.len();
let bytes = str.as_bytes();
let mut negative = false; // assume positive
// handle the sign
if bytes[offset] == b'-' {
negative = true; // leading minus means negative
offset += 1;
len -= 1;
} else if bytes[offset] == b'+' {
// leading + allowed
offset += 1;
len -= 1;
}
// should now be at numeric part of the significand
let mut digits_before_dot: i32 = -1; // digits before '.', -1 if no '.'
let mut coeff = ArrayVec::<[_; MAX_STR_BUFFER_SIZE]>::new(); // integer significand array
let mut maybe_round = false;
while len > 0 {
let b = bytes[offset];
match b {
b'0'..=b'9' => {
coeff.push(u32::from(b - b'0'));
offset += 1;
len -= 1;
// If the coefficient is longer than the max, exit early
if coeff.len() as u32 > 28 {
maybe_round = true;
break;
}
}
b'.' => {
if digits_before_dot >= 0 {
return Err(Error::from("Invalid decimal: two decimal points"));
}
digits_before_dot = coeff.len() as i32;
offset += 1;
len -= 1;
}
b'_' => {
// Must start with a number...
if coeff.is_empty() {
return Err(Error::from("Invalid decimal: must start lead with a number"));
}
offset += 1;
len -= 1;
}
_ => return Err(Error::from("Invalid decimal: unknown character")),
}
}
// If we exited before the end of the string then do some rounding if necessary
if maybe_round && offset < bytes.len() {
let next_byte = bytes[offset];
let digit = match next_byte {
b'0'..=b'9' => u32::from(next_byte - b'0'),
b'_' => 0,
b'.' => {
// Still an error if we have a second dp
if digits_before_dot >= 0 {
return Err(Error::from("Invalid decimal: two decimal points"));
}
0
}
_ => return Err(Error::from("Invalid decimal: unknown character")),
};
// Round at midpoint
if digit >= 5 {
let mut index = coeff.len() - 1;
loop {
let new_digit = coeff[index] + 1;
if new_digit <= 9 {
coeff[index] = new_digit;
break;
} else {
coeff[index] = 0;
if index == 0 {
coeff.insert(0, 1u32);
digits_before_dot += 1;
coeff.pop();
break;
}
}
index -= 1;
}
}
}
// here when no characters left
if coeff.is_empty() {
return Err(Error::from("Invalid decimal: no digits found"));
}
let mut scale = if digits_before_dot >= 0 {
// we had a decimal place so set the scale
(coeff.len() as u32) - (digits_before_dot as u32)
} else {
0
};
let mut data = [0u32, 0u32, 0u32];
let mut tmp = [0u32, 0u32, 0u32];
let len = coeff.len();
for (i, digit) in coeff.iter().enumerate() {
// If the data is going to overflow then we should go into recovery mode
tmp[0] = data[0];
tmp[1] = data[1];
tmp[2] = data[2];
let overflow = mul_by_10(&mut tmp);
if overflow > 0 {
// This means that we have more data to process, that we're not sure what to do with.
// This may or may not be an issue - depending on whether we're past a decimal point
// or not.
if (i as i32) < digits_before_dot && i + 1 < len {
return Err(Error::from("Invalid decimal: overflow from too many digits"));
}
if *digit >= 5 {
let carry = add_one_internal(&mut data);
if carry > 0 {
// Highly unlikely scenario which is more indicative of a bug
return Err(Error::from("Invalid decimal: overflow when rounding"));
}
}
// We're also one less digit so reduce the scale
let diff = (len - i) as u32;
if diff > scale {
return Err(Error::from("Invalid decimal: overflow from scale mismatch"));
}
scale -= diff;
break;
} else {
data[0] = tmp[0];
data[1] = tmp[1];
data[2] = tmp[2];
let carry = add_by_internal(&mut data, &[*digit]);
if carry > 0 {
// Highly unlikely scenario which is more indicative of a bug
return Err(Error::from("Invalid decimal: overflow from carry"));
}
}
}
Ok(Decimal::from_parts(data[0], data[1], data[2], negative, scale))
}
pub(crate) fn parse_str_radix_n(str: &str, radix: u32) -> Result<Decimal, crate::Error> {
if str.is_empty() {
return Err(Error::from("Invalid decimal: empty"));
}
if radix < 2 {
return Err(Error::from("Unsupported radix < 2"));
}
if radix > 36 {
// As per trait documentation
return Err(Error::from("Unsupported radix > 36"));
}
let mut offset = 0;
let mut len = str.len();
let bytes = str.as_bytes();
let mut negative = false; // assume positive
// handle the sign
if bytes[offset] == b'-' {
negative = true; // leading minus means negative
offset += 1;
len -= 1;
} else if bytes[offset] == b'+' {
// leading + allowed
offset += 1;
len -= 1;
}
// should now be at numeric part of the significand
let mut digits_before_dot: i32 = -1; // digits before '.', -1 if no '.'
let mut coeff = ArrayVec::<[_; 96]>::new(); // integer significand array
// Supporting different radix
let (max_n, max_alpha_lower, max_alpha_upper) = if radix <= 10 {
(b'0' + (radix - 1) as u8, 0, 0)
} else {
let adj = (radix - 11) as u8;
(b'9', adj + b'a', adj + b'A')
};
// Estimate the max precision. All in all, it needs to fit into 96 bits.
// Rather than try to estimate, I've included the constants directly in here. We could,
// perhaps, replace this with a formula if it's faster - though it does appear to be log2.
let estimated_max_precision = match radix {
2 => 96,
3 => 61,
4 => 48,
5 => 42,
6 => 38,
7 => 35,
8 => 32,
9 => 31,
10 => 28,
11 => 28,
12 => 27,
13 => 26,
14 => 26,
15 => 25,
16 => 24,
17 => 24,
18 => 24,
19 => 23,
20 => 23,
21 => 22,
22 => 22,
23 => 22,
24 => 21,
25 => 21,
26 => 21,
27 => 21,
28 => 20,
29 => 20,
30 => 20,
31 => 20,
32 => 20,
33 => 20,
34 => 19,
35 => 19,
36 => 19,
_ => return Err(Error::from("Unsupported radix")),
};
let mut maybe_round = false;
while len > 0 {
let b = bytes[offset];
match b {
b'0'..=b'9' => {
if b > max_n {
return Err(Error::from("Invalid decimal: invalid character"));
}
coeff.push(u32::from(b - b'0'));
offset += 1;
len -= 1;
// If the coefficient is longer than the max, exit early
if coeff.len() as u32 > estimated_max_precision {
maybe_round = true;
break;
}
}
b'a'..=b'z' => {
if b > max_alpha_lower {
return Err(Error::from("Invalid decimal: invalid character"));
}
coeff.push(u32::from(b - b'a') + 10);
offset += 1;
len -= 1;
if coeff.len() as u32 > estimated_max_precision {
maybe_round = true;
break;
}
}
b'A'..=b'Z' => {
if b > max_alpha_upper {
return Err(Error::from("Invalid decimal: invalid character"));
}
coeff.push(u32::from(b - b'A') + 10);
offset += 1;
len -= 1;
if coeff.len() as u32 > estimated_max_precision {
maybe_round = true;
break;
}
}
b'.' => {
if digits_before_dot >= 0 {
return Err(Error::from("Invalid decimal: two decimal points"));
}
digits_before_dot = coeff.len() as i32;
offset += 1;
len -= 1;
}
b'_' => {
// Must start with a number...
if coeff.is_empty() {
return Err(Error::from("Invalid decimal: must start lead with a number"));
}
offset += 1;
len -= 1;
}
_ => return Err(Error::from("Invalid decimal: unknown character")),
}
}
// If we exited before the end of the string then do some rounding if necessary
if maybe_round && offset < bytes.len() {
let next_byte = bytes[offset];
let digit = match next_byte {
b'0'..=b'9' => {
if next_byte > max_n {
return Err(Error::from("Invalid decimal: invalid character"));
}
u32::from(next_byte - b'0')
}
b'a'..=b'z' => {
if next_byte > max_alpha_lower {
return Err(Error::from("Invalid decimal: invalid character"));
}
u32::from(next_byte - b'a') + 10
}
b'A'..=b'Z' => {
if next_byte > max_alpha_upper {
return Err(Error::from("Invalid decimal: invalid character"));
}
u32::from(next_byte - b'A') + 10
}
b'_' => 0,
b'.' => {
// Still an error if we have a second dp
if digits_before_dot >= 0 {
return Err(Error::from("Invalid decimal: two decimal points"));
}
0
}
_ => return Err(Error::from("Invalid decimal: unknown character")),
};
// Round at midpoint
let midpoint = if radix & 0x1 == 1 { radix / 2 } else { (radix + 1) / 2 };
if digit >= midpoint {
let mut index = coeff.len() - 1;
loop {
let new_digit = coeff[index] + 1;
if new_digit <= 9 {
coeff[index] = new_digit;
break;
} else {
coeff[index] = 0;
if index == 0 {
coeff.insert(0, 1u32);
digits_before_dot += 1;
coeff.pop();
break;
}
}
index -= 1;
}
}
}
// here when no characters left
if coeff.is_empty() {
return Err(Error::from("Invalid decimal: no digits found"));
}
let mut scale = if digits_before_dot >= 0 {
// we had a decimal place so set the scale
(coeff.len() as u32) - (digits_before_dot as u32)
} else {
0
};
// Parse this using specified radix
let mut data = [0u32, 0u32, 0u32];
let mut tmp = [0u32, 0u32, 0u32];
let len = coeff.len();
for (i, digit) in coeff.iter().enumerate() {
// If the data is going to overflow then we should go into recovery mode
tmp[0] = data[0];
tmp[1] = data[1];
tmp[2] = data[2];
let overflow = mul_by_u32(&mut tmp, radix);
if overflow > 0 {
// This means that we have more data to process, that we're not sure what to do with.
// This may or may not be an issue - depending on whether we're past a decimal point
// or not.
if (i as i32) < digits_before_dot && i + 1 < len {
return Err(Error::from("Invalid decimal: overflow from too many digits"));
}
if *digit >= 5 {
let carry = add_one_internal(&mut data);
if carry > 0 {
// Highly unlikely scenario which is more indicative of a bug
return Err(Error::from("Invalid decimal: overflow when rounding"));
}
}
// We're also one less digit so reduce the scale
let diff = (len - i) as u32;
if diff > scale {
return Err(Error::from("Invalid decimal: overflow from scale mismatch"));
}
scale -= diff;
break;
} else {
data[0] = tmp[0];
data[1] = tmp[1];
data[2] = tmp[2];
let carry = add_by_internal(&mut data, &[*digit]);
if carry > 0 {
// Highly unlikely scenario which is more indicative of a bug
return Err(Error::from("Invalid decimal: overflow from carry"));
}
}
}
Ok(Decimal::from_parts(data[0], data[1], data[2], negative, scale))
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу