#bit-vector #bit #arithmetic #binary #arithmetic-operations #vector #fixed-size

bva

bva是一个Rust crate,用于操作和进行固定但任意大小的位向量算术

5个版本 (3个重大更新)

0.4.0 2024年8月17日
0.3.0 2024年7月7日
0.2.0 2023年7月4日
0.1.1 2020年12月27日
0.1.0 2020年12月20日

#63 in 数学

每月30次下载

MIT许可证

270KB
7K SLoC

bva

crates.io Version Rayon documentation Build Status codecov Minimum Rust 1.61 LICENSE

此crate用于操作和进行固定但任意大小的位向量算术。它们旨在像CPU硬件寄存器一样工作,在溢出时自动回绕。

此crate提供多种实现,这些实现依赖于不同的内存管理策略。

  • Bvf实现使用无符号整数静态数组作为存储,因此具有固定容量但不需要动态内存分配。
  • Bvd实现使用动态分配的整数数组作为存储,因此具有动态容量并支持调整大小操作。
  • Bv实现能够在运行时在BvfBvd实现之间切换,以尽可能减少动态内存分配。

所有这些实现都实现了BitVector特质,可以自由混合并通过泛型特质进行抽象。

不同的位向量类型表示一个位向量,其中索引0的位是最不重要的位,而索引.len() - 1是最重要的位。对于位向量本身没有字节序的概念,字节序仅在从内存读取或写入位向量时涉及。

可以将算术运算应用于不同类型和不同长度的位向量。结果将始终具有左侧操作数的类型和长度。如果需要,右侧操作数将被零扩展。在溢出时操作将回绕。这应与CPU寄存器上的无符号整数算术行为相匹配。

示例

位向量提供了与Rust std::collections::Vec 相似的API

use bva::{Bit, BitVector, Bvd};

let mut bv = Bvd::with_capacity(128);
assert_eq!(bv.capacity(), 128);
bv.push(Bit::One);
bv.push(Bit::One);
bv.resize(16, Bit::Zero);
assert_eq!(bv.len(), 16);
assert_eq!(bv.first(), Some(Bit::One));
assert_eq!(bv.last(), Some(Bit::Zero));
let pop_count = bv.iter().fold(0u32, |acc, b| acc + u32::from(b));
assert_eq!(pop_count, 2);

此外,还提供了针对位向量的特定操作

use bva::{Bit, BitVector, Bv32};

// While Bv32 has a capacity of 32 bits, it inherits the length of the u8.
let mut a = Bv32::try_from(0b111u8).unwrap();
a.rotr(2);
assert_eq!(a, Bv32::try_from(0b11000001u8).unwrap());
assert_eq!(a.get(7), Bit::One);
a.set(1, Bit::One);
assert_eq!(a, Bv32::try_from(0b11000011u8).unwrap());
assert_eq!(a.copy_range(1..7), Bv32::try_from(0b100001u8).unwrap());

位向量在溢出时表现得像无符号整数,具有环绕行为

use bva::{Bit, BitVector, Bv32};

// Bv32 is a type alias for a Bvf with 32 bits of capacity.
let a = Bv32::ones(32);
let b = Bv32::try_from(1u32).unwrap();
assert_eq!(b.leading_zeros(), 31);
let c = a + b;
assert_eq!(c, Bv32::zeros(32));

可以使用泛型特质来抽象不同的位向量实现

use core::ops::AddAssign;
use bva::{Bit, BitVector, Bv, Bvd, Bvf};

fn fibonnaci<B: BitVector + for<'a> AddAssign<&'a B>>(n: usize) -> B {
    let mut f0 = B::zeros(1);
    let mut f1 = B::ones(1);
    if n == 0 {
        return f0;
    }

    for _ in 1..n {
        // Avoid overflow
        f0.resize(f1.significant_bits() + 1, Bit::Zero);
        // Addition is done in place
        f0 += &f1;
        // Swap f0 and f1
        std::mem::swap(&mut f0, &mut f1);
    }
    return f1;
}

assert_eq!(fibonnaci::<Bvf<u8, 2>>(15), Bvf::<u8, 2>::try_from(610u16).unwrap());
assert_eq!(fibonnaci::<Bvd>(18), Bvd::from(2584u32));
assert_eq!(fibonnaci::<Bv>(19), Bv::from(4181u32));

更新日志

  • 2024/08/18 - 0.4.0
    • 100% 函数测试覆盖率,98% 行测试覆盖率
      • 在此过程中修复了一些错误
    • 更好的API和适当的文档
    • extend、append、prepend、repeat、first、last 和 sign_extend 函数
    • 从整数数组构造位向量
    • 使用无符号整数作为右侧操作数进行操作
  • 2024/07/07 - 0.3.0
    • 乘法、除法和取模操作
    • 各种辅助函数
    • 更严格的测试,达到高代码覆盖率
  • 2023/07/04 - 0.2.0
    • 使用const generics进行主要重写
    • 迭代器支持
  • 2020/12/20 - 0.1.0
    • 具有固定、动态和自动实现的BitVector特质
    • 在所有实现之间进行转换
    • 不同实现之间的基本算术操作
    • 以各种格式读取和写入位向量

路线图

  • no-std 支持
  • 更多便利的BitVector函数
  • 支持有符号操作
  • 在位向量内部借用位和位切片
  • 数值算法,如gcd、模幂运算等

为什么

现有的所有crate都没有真正让我满意,我想要一个能够通过自动切换到固定存储来最小化动态内存分配的实现。我还想要一个能够对任意大小的位向量进行算术运算的crate,而不仅仅是2的幂。这对我来说也是练习Rust宏编写技能的好机会。

无运行时依赖