96个版本 (61个稳定版)
新 1.36.0 | 2024年8月19日 |
---|---|
1.35.0 | 2024年3月27日 |
1.34.3 | 2024年2月10日 |
1.33.1 | 2023年11月16日 |
0.1.0 | 2016年11月16日 |
在 数学 中排名 2
每月下载量 1,174,301
在 1,291 个crate中使用(576个直接使用)
385KB
8K SLoC
十进制
使用纯Rust编写的十进制数实现,适用于需要进行大量整数和小数位计算且无舍入误差的金融计算。
二进制表示由96位整数、用于指定小数分数的缩放因子和一个1位符号组成。由于这种表示方式,尾随零被保留,并且在字符串形式中可能会暴露。可以使用 normalize
或 round_dp
函数来截断这些零。
安装
$ cargo add rust_decimal
此外,如果您想使用优化的宏以便方便地创建十进制数
$ cargo add rust_decimal_macros
或者,您可以直接编辑您的 Cargo.toml
并运行 cargo update
[dependencies]
rust_decimal = "1.36"
rust_decimal_macros = "1.36"
用法
可以通过几种不同的方式创建十进制数。创建十进制数最简单和最有效的方法是使用可以使用 macros
功能启用的过程宏。
// Import the `rust_decimal_macros` crate and use the macro directly from there.
use rust_decimal_macros::dec;
let number = dec!(-1.23) + dec!(3.45);
assert_eq!(number, dec!(2.22));
assert_eq!(number.to_string(), "2.22");
另外,您也可以使用十进制数便捷函数之一(更多信息请参阅文档)
// 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 128 bit integer
let balance = Decimal::from_i128_with_scale(5_897_932_384_626_433_832, 2);
assert_eq!("58979323846264338.32", balance.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());
// From scientific notation
let sci = Decimal::from_scientific("9.7e-7").unwrap();
assert_eq!("0.00000097", sci.to_string());
// Using the `Into` trait
let my_int: Decimal = 3_i32.into();
assert_eq!("3", my_int.to_string());
// Using the raw decimal representation
let pi = Decimal::from_parts(1_102_470_952, 185_874_565, 1_703_060_790, false, 28);
assert_eq!("3.1415926535897932384626433832", pi.to_string());
一旦您实例化了您的 Decimal
数,您就可以像任何其他数字一样使用它进行计算
use rust_decimal::prelude::*;
use rust_decimal_macros::dec;
let amount = dec!(25.12);
let tax_percentage = dec!(0.085);
let total = amount + (amount * tax_percentage).round_dp(2);
assert_eq!(total, dec!(27.26));
功能
行为/功能
数据库
Serde
- serde-float
- serde-str
- serde-arbitrary-precision
- serde-with-float
- serde-with-str
- serde-with-arbitrary-precision
borsh
启用对 Decimal
的 Borsh 序列化。
c-repr
强制 Decimal
使用 [repr(C)]
。相应的目标布局是128位对齐。
db-postgres
启用 PostgreSQL 通信模块。它允许通过透明地序列化和反序列化到 PostgreSQL 中的 NUMERIC
数据类型来读取和写入 Decimal
类型。
db-tokio-postgres
启用 tokio postgres 模块,允许与 PostgreSQL 进行异步通信。
db-diesel-postgres
启用 diesel
PostgreSQL 支持。
db-diesel-mysql
启用 diesel
MySQL 支持。
legacy-ops
警告:这已被弃用,并将从未来的版本中删除。
从 1.10
开始,执行基本操作所使用的算法已更改,这带来了显著的性能改进。为了保持向后兼容性,可以通过启用 legacy-ops
功能来选择退出。
maths
启用 maths
功能可启用额外的复杂数学函数,如 pow
、ln
、enf
、exp
等。有关附加函数的详细信息,请参阅 MathematicalOps
特性。
请注意,ln
和 log10
在无效输入上会引发恐慌,而 checked_ln
和 checked_log10
是首选函数,以防止这种情况。当 maths
功能最初开发时,库会在无效输入上返回 0
。要重新启用此非恐慌行为,请使用功能: maths-nopanic
。
ndarray
启用使用 ndarray
在 Decimal
数组上执行算术运算。
proptest
启用一个 proptest
策略来生成 Rust Decimal 的值。
rand
实现了 rand::distributions::Distribution<Decimal>
以允许创建随机实例。
注意:当使用 rand::Rng
特性在两个其他十进制数之间生成一个十进制数时,随机生成的十进制数的刻度将与输入十进制数的刻度相同(或者,如果输入具有不同的刻度,则为较高的一个)。
rkyv
启用对 Decimal
的 rkyv 序列化。当启用 rkyv-safe
功能时,也支持 rkyv 的安全 API。
rocket-traits
通过实现 FromFormField
特性来启用对 Rocket 表单的支持。
rust-fuzz
通过实现 Arbitrary
特性来启用对 rust-fuzz
的支持。
serde-float
注意:此功能将浮点序列化/反序列化规则作为处理
Decimal
数字时的默认方法。有关更大灵活性,请参阅serde-with-*
功能。
启用此功能,以便将 Decimal
类型的 JSON 序列化发送为浮点数而不是字符串(默认)。
例如,启用此功能后,JSON 序列化将输出
{
"value": 1.234
}
serde-str
注意:此功能将字符串序列化/反序列化规则作为处理
Decimal
数字时的默认方法。有关更大灵活性,请参阅serde-with-*
功能。
这通常用于类似 bincode
或 csv
的实现。
由于 bincode
没有指定类型信息,我们需要确保提供类型提示,以便能够正确地进行反序列化。单独启用此功能将强制使用 deserialize_str
而不是 deserialize_any
进行反序列化。
如果出于某种原因您还启用了 serde-float
,则此功能将使用 deserialize_f64
作为类型提示。因为将转换为 f64
会丢失 精度,因此强烈建议您在处理 bincode
时不要启用此功能。尽管如此,这将仅使用 8 个字节的存储空间,因此在存储大小方面略微更有效率。
serde-arbitrary-precision
注意:此功能将任意序列化/反序列化规则作为处理
Decimal
数字时的默认方法。有关更大灵活性,请参阅serde-with-*
功能。
这主要用于与 serde_json
一起使用,因此将其作为“弱依赖项”添加。这支持 serde_json
中的 arbitrary_precision
功能,以便在解析十进制数时使用。
当解析类似“浮点数”的数据时,这建议使用,因为它可以防止数据丢失。
请注意,此功能默认以浮点数格式序列化数字,这可能会产生意外的后果。请使用 serde-with-arbitrary-precision
功能来获得对序列化格式的更大控制。
serde-with-float
启用此功能以访问将 Decimal
类型序列化为浮点数的模块。这可以在如下所示的 struct
定义中使用
#[derive(Serialize, Deserialize)]
pub struct FloatExample {
#[serde(with = "rust_decimal::serde::float")]
value: Decimal,
}
#[derive(Serialize, Deserialize)]
pub struct OptionFloatExample {
#[serde(with = "rust_decimal::serde::float_option")]
value: Option<Decimal>,
}
或者,如果您只想启用序列化功能(例如,在保持反序列化灵活性的同时)
#[derive(Serialize, Deserialize)]
pub struct FloatExample {
#[serde(serialize_with = "rust_decimal::serde::float::serialize")]
value: Decimal,
}
serde-with-str
启用此功能以访问将 Decimal
类型序列化为 String
的模块。这可以在如下所示的 struct
定义中使用
#[derive(Serialize, Deserialize)]
pub struct StrExample {
#[serde(with = "rust_decimal::serde::str")]
value: Decimal,
}
#[derive(Serialize, Deserialize)]
pub struct OptionStrExample {
#[serde(with = "rust_decimal::serde::str_option")]
value: Option<Decimal>,
}
尽管此功能通常不是必需的用于序列化,但它对于反序列化很有用,因为它不需要类型提示。因此,您可以通过以下方式强制仅用于反序列化
#[derive(Serialize, Deserialize)]
pub struct StrExample {
#[serde(deserialize_with = "rust_decimal::serde::str::deserialize")]
value: Decimal,
}
serde-with-arbitrary-precision
启用此功能以访问使用 serde_json/arbitrary_precision
功能反序列化 Decimal
类型的模块。这可以在如下所示的 struct
定义中使用
#[derive(Serialize, Deserialize)]
pub struct ArbitraryExample {
#[serde(with = "rust_decimal::serde::arbitrary_precision")]
value: Decimal,
}
#[derive(Serialize, Deserialize)]
pub struct OptionArbitraryExample {
#[serde(with = "rust_decimal::serde::arbitrary_precision_option")]
value: Option<Decimal>,
}
此功能的意外后果是它将被序列化为类似于浮点数的值。为了防止这种情况,您可以将结构体设置为仅使用 arbitrary_precision
功能进行反序列化。
#[derive(Serialize, Deserialize)]
pub struct ArbitraryExample {
#[serde(deserialize_with = "rust_decimal::serde::arbitrary_precision::deserialize")]
value: Decimal,
}
这将确保序列化仍然以字符串的形式进行。
有关 serde_json
场景的更多信息,请参阅 examples
目录。
std
启用 std
库支持。默认情况下,这将启用,但将来将需要选择启用。目前,为了支持 no_std
库,可以带 --no-default-features
选项编译此 crate。
构建
有关构建和测试 Rust Decimal 的更多信息,请参阅构建文档。
最低 Rust 编译器版本
当前 最低 编译器版本是 1.60.0
,该版本于 2022-04-07
发布。
此库支持距离当前稳定 Rust 编译器版本 4 个小版本之前的 Rust 编译器版本。例如,如果当前稳定编译器版本是 1.50.0
,则我们将保证支持到包括 1.46.0
。值得注意的是,只有当需要时,我们才会更新支持的最低版本。
与其他 Decimal 实现的比较
在开发此库的过程中,为了确保十进制计算快速、准确和高效,做出了各种设计决策。然而,一些决策限制了此库可以做什么以及它最终适合什么。其中一个决策是内部十进制表示的结构。
此库使用由三个 32 位无符号整数组成的 96 位尾数,以及一个用于表示比例/符号(类似于 C 和 .NET Decimal 实现)的第四个 32 位无符号整数。这种结构允许我们利用算法优化来执行基本算术;最终,这使我们能够挤出性能,使其成为最快的实现之一。然而,这种方法的缺点是,可以表示的最大有效数字大约为 28 位(在某些情况下为 29 位)。
虽然这个限制对许多应用程序(例如处理金钱)来说不是问题,但有些应用程序可能需要表示更多的有效数字。幸运的是,有一些替代实现值得调查,例如
依赖项
~0.3–34MB
~542K SLoC