#primitive-integer #bignum #uint #maths #int #unsigned-integer #arbitrary

no-std bnum

任意精度、固定大小的数值类型,扩展了原生数值类型的功能

13 个版本 (破坏性)

0.11.0 2024年3月6日
0.10.0 2023年11月23日
0.9.1 2023年10月25日
0.8.0 2023年7月23日
0.1.0 2022年7月10日

#45 in 加密学

Download history 9461/week @ 2024-05-01 11886/week @ 2024-05-08 10596/week @ 2024-05-15 10196/week @ 2024-05-22 11026/week @ 2024-05-29 15110/week @ 2024-06-05 17201/week @ 2024-06-12 15800/week @ 2024-06-19 17063/week @ 2024-06-26 12299/week @ 2024-07-03 15782/week @ 2024-07-10 15959/week @ 2024-07-17 15110/week @ 2024-07-24 11656/week @ 2024-07-31 15710/week @ 2024-08-07 15444/week @ 2024-08-14

60,283 每月下载量
用于 646 个crate(直接使用4个)

MIT/Apache

440KB
10K SLoC

bnum

GitHub doc.rs Crates.io dependency status codecov license

Rust的任意精度、固定大小的有符号和无符号整数类型。

概述

此crate的目标是提供与Rust原生整数类型(如u8i8u16i16等)完全相同的整数类型:几乎所有在Rust的有符号和无符号原生整数上定义的方法都在bnum的有符号和无符号整数上定义。此外,还提供了一些其他有用的方法,大部分灵感来自BigIntBigUint类型,这些类型来自num_bigint crate。

此crate使用Rust的const generics来允许创建在编译时可以确定的任意大小的整数。无符号整数存储为长度为N的数字数组(原生无符号整数)。这意味着所有bnum整数都可以存储在栈上,因为它们是固定大小的。有符号整数简单地存储为二进制补码形式的无符号整数。

bnum 定义了 4 种无符号整数类型:每种类型使用不同的原始整数类型作为其数字类型。 BUint 使用 u64 作为其数字类型,BUintD32 使用 u32BUintD16 使用 u16,而 BUintD8 使用 u8。有符号整数类型 BIntBIntD32BIntD16BIntD8 分别由这些无符号整数表示。

BUintBInt 由于存储(并且因此操作)给定位数大小的最少数字,所以速度最快。然而,缺点是位数大小必须是 64 的倍数(bitsize = N * 64)。这就是为什么还提供了其他整数类型,因为它们允许位数大小是 32168 的倍数。在选择使用哪种类型时,确定 64, 32, 16, 8 中的哪一个是最大除数,并使用相应的类型。例如,如果您想有一个 96 位的无符号整数,32 是这些中 96 的最大除数,所以使用 BUintD32<3>。一个 40 位的有符号整数将是 BIntD8<5>

为什么是 bnum?

  • 默认无依赖:默认情况下,bnum 不依赖于任何其他 crate。可以通过 crate features 启用对 randserde 等crate 的支持。
  • no-std 兼容:如果未启用 arbitraryquickcheck 功能,则 bnum 可以在 no_std 环境中使用。
  • 编译时整数解析:在 bnum 整数上的 from_str_radixparse_str_radix 方法是 const,这使得可以在编译时解析来自字符串切片的整数。请注意,这比编译时解析整数文字更强大。这是因为它允许解析从 236 的所有基数(包括 281016)。此外,要解析的字符串不一定是文字:例如,它可以通过 include_str!env!` 获取。
  • const评估:bnum整数上定义的几乎所有方法都是const,这允许复杂的编译时计算。

安装

要安装和使用bnum,只需将以下行添加到您的Cargo.toml文件中的[dependencies]部分

bnum = "0.11.0"

或者,为了启用bnum的各种功能,例如,添加以下行代替

bnum = { version = "0.11.0", features = ["rand"] } # enables the "rand" feature

示例用法

注意:文档中的示例使用特定的类型别名(例如U256U512I256I512)来给出大多数方法的正确使用示例。这些类型并没有什么特殊之处:所有使用这些类型展示的方法都为任何值N的所有无符号/有符号bnum整数实现了。

// As of version 0.6.0, you can parse integers from string slices at compile time with the const methods `from_str_radix` or `parse_str_radix`:
use bnum::types::{U256, I256};
use bnum::errors::ParseIntError;

// `parse_str_radix` returns an integer, and panics if the string fails to parse
const UINT_FROM_DECIMAL_STR: U256 = U256::parse_str_radix("12345678901234567890", 10);

// If you are not sure that the string will successfully parse, you can use `from_str_radix` which returns a `Result`
const RESULT_INT_FROM_HEXA_STR: Result<I256, ParseIntError> = I256::from_str_radix("-1234567890abcdef", 16);

assert_eq!(format!("{}", UINT_FROM_DECIMAL_STR), "12345678901234567890");
assert_eq!(format!("{:x}", RESULT_INT_FROM_HEXA_STR.unwrap().abs()), "1234567890abcdef");
// Calculate the `n`th Fibonacci number, using the type alias `U512`.

use bnum::types::U512; // `U512` is a type alias for a `BUint` which contains 8 `u64` digits

// Calculate the nth Fibonacci number
fn fibonacci(n: usize) -> U512 {
    let mut f_n: U512 = U512::ZERO; // or `U512::from(0u8)`
    let mut f_n_next: U512 = U512::ONE; // or `U512::from(1u8)`

    for _ in 0..n {
        let temp = f_n_next;
        f_n_next += f_n;
        f_n = temp;
    }

    f_n
}

let n = 100;
let f_n = fibonacci(n);

println!("The {}th Fibonacci number is {}", n, f_n);
// Prints "The 100th Fibonacci number is 354224848179261915075"

assert_eq!(f_n, U512::from_str_radix("354224848179261915075", 10).unwrap());
// Construct an 80-bit signed integer
// Out of [64, 32, 16, 8], 16 is the largest divisor of 80, so use `BIntD16`
use bnum::BIntD16;

type I80 = BIntD16<5>; // 80 / 16 = 5

let neg_one = I80::NEG_ONE; // -1
assert_eq!(neg_one.count_ones(), 80); // signed integers are stored in two's complement so `-1` is represented as `111111...`

功能

模糊测试

arbitrary功能从arbitrary存储库中推导出Arbitrary特质。**注意:目前,此功能无法与no_std一起使用(请参阅https://github.com/rust-fuzz/arbitrary/issues/38)**。

随机数生成

rand功能允许通过rand存储库创建随机bnum整数。

序列化和反序列化

serde功能通过serdeserde_big_array存储库启用bnum整数的序列化和反序列化。

num_traitsnum_integer特质实现

numtraits功能包括来自num_traitsnum_integer存储库的特质的实现,例如AsPrimitiveSignedIntegerRoots

Quickcheck

quickcheck功能启用quickcheck存储库中的Arbitrary特质。**注意:目前,此功能无法与no_std一起使用**。

Zeroize

zeroize功能启用zeroize存储库中的Zeroize特质。

Valuable

valuable功能启用valuable存储库中的Valuable特质。

夜间功能

激活 nightly 功能将启用 from_be_bytesfrom_le_bytesfrom_ne_bytesto_be_bytesto_le_bytesto_ne_bytes 方法,这些方法作用于 bnum 的无符号和有符号整数,并将 unchecked_... 方法标记为 const。但这样做代价是只能编译在 nightly 版本上。这个功能使用的 nightly 特性包括:generic_const_exprsconst_trait_implconst_option_ext

测试

此软件包使用 quickcheck 软件包以及特定的边缘情况进行测试。将方法输出与原始整数的等效方法输出进行比较,以确保行为相同。

最低支持的 Rust 版本

当前最低支持的 Rust 版本 (MSRV) 为 1.65.0

文档

如果一个方法没有明确文档,它将链接到原始 Rust 整数上定义的等效方法(因为它们具有相同的功能)。

注意:bnum 目前处于预 1.0.0 阶段。根据 语义版本控制指南,在此阶段,公共 API 可能包含破坏性更改。然而,由于 API 设计尽可能类似于 Rust 原始整数的 API,因此不太可能出现大量的破坏性更改。

已知问题

目前,对于 bnum 整数实现了 From 特性,从所有 Rust 原始整数。然而,这种行为并不完全正确。例如,如果创建了一个 24 位宽的无符号整数(BUintD8<3>),则不应实现 From<u32> 等,而应实现 TryFrom<u32>。为确保正确的行为,可以使用来自 num_traits 软件包的 FromPrimitive 特性,因为这总会返回一个 Option 而不是整数本身。

num_traits::NumCast 特性为 bnum 整数实现了,但如果调用其方法 from,则会故意触发 panic,因为这无法保证正确的转换,因为 NumCast 特性强制执行了约束。因此,不应在 bnum 整数上使用此特性。此实现的唯一目的是允许实现 num_traits::PrimInt 特性。

以前的错误

以前版本中的错误列表可以在 changes/prior-bugs.md 找到。

未来工作

此库旨在提供 Rust 的 3 种内置数字类型的任意精度和固定精度等效项:有符号整数、无符号整数和浮点数。有符号和无符号整数已实现并经过全面测试,并力求与 Rust 的整数接口保持同步。(例如,当在 Rust 原始整数上实现新方法时,此库将努力同步,包括该方法。这包括仅限夜间的功能。)

目前,正在开发任意精度固定大小浮点数,但尚不完整。大多数基本方法,如算术和分类,已实现,但截至目前,尚未实现如 sinexplog 等超越浮点数方法。

此外,还将在某个时候开发用于解析数字值的 proc 模块。

许可

bnum 许可证为 MIT 许可证或 Apache 许可证 2.0。

依赖项

~0–500KB