Skip to content

Commit

Permalink
mark where can use u128 digits
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacholt100 committed Feb 16, 2025
1 parent 1bc0860 commit 129e310
Show file tree
Hide file tree
Showing 15 changed files with 135 additions and 142 deletions.
1 change: 1 addition & 0 deletions bench/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ num-traits = "0.2"
uint = "0.9"
rand = { version = "0.8", features = ["std", "std_rng"] }
paste = "1.0"
bnum-old = { package = "bnum", version = "0.12.0", features = ["rand"]}

[[bench]]
name = "float"
Expand Down
23 changes: 16 additions & 7 deletions bench/benches/float.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
use rand::prelude::*;
use bnum::cast::CastFrom;

mod unzip;

const SAMPLE_SIZE: usize = 10000;

use bnum::{BIntD8, BUintD8};
use bnum::Float;

type F256 = Float<32, 236>;
Expand All @@ -14,6 +16,7 @@ type F32 = Float<4, 23>;

type U256 = bnum::BUintD8<32>;
type U1024 = bnum::BUintD8<128>;
type I1024 = bnum::BIntD8<128>;


fn bench_fibs(c: &mut Criterion) {
Expand Down Expand Up @@ -49,21 +52,27 @@ fn bench_fibs(c: &mut Criterion) {
fn bench_add(c: &mut Criterion) {
let mut group = c.benchmark_group("round");
let mut rng = rand::rngs::StdRng::seed_from_u64(0);
const N: usize = 18;
let big_inputs = (0..SAMPLE_SIZE)
.map(|_| rng.gen::<(U1024, u32)>());
// .map(|(a, b)| (
// (F64::from_bits((a >> 1)), F64::from_bits((b >> 1)))
// ));
let big_inputs: Vec<_> = big_inputs.collect();
.map(|_| rng.gen::<(BUintD8<{N*8}>, BUintD8<{N*8}>)>())
.map(|(a, b)| (
((a, b), (unsafe { core::mem::transmute::<_, bnum_old::BUint<N>>(a) }, unsafe { core::mem::transmute::<_, bnum_old::BUint<N>>(b) }))
));
let (inputs1, inputs2) = unzip::unzip2(big_inputs);

// group.bench_with_input(BenchmarkId::new("Recursive", "new"), &big_inputs, |b, inputs| b.iter(|| {
// for a in inputs.iter().cloned() {
// let _ = black_box(a).floor();
// }
// }));
group.bench_with_input(BenchmarkId::new("Iterative", "d64"), &big_inputs, |b, inputs| b.iter(|| {
group.bench_with_input(BenchmarkId::new("Iterative", "d8"), &inputs1, |b, inputs| b.iter(|| {
inputs.iter().cloned().for_each(|(a, b)| {
let _ = black_box(a & b);
})
}));
group.bench_with_input(BenchmarkId::new("Iterative", "d64"), &inputs2, |b, inputs| b.iter(|| {
inputs.iter().cloned().for_each(|(a, b)| {
let _ = black_box((a).trailing_ones());
let _ = black_box(a & b);
})
}));
group.finish();
Expand Down
6 changes: 5 additions & 1 deletion src/bint/overflowing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ impl<const N: usize> BIntD8<N> {
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
// TODO: can use u128
let mut out = Self::ZERO;
let mut carry = false;

Expand Down Expand Up @@ -47,6 +48,7 @@ impl<const N: usize> BIntD8<N> {
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
// TODO: can use u128
let mut out = Self::ZERO;
let mut borrow = false;

Expand Down Expand Up @@ -198,6 +200,8 @@ impl<const N: usize> BIntD8<N> {
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn overflowing_neg(mut self) -> (Self, bool) {
// TODO: can use u128
// this is faster than self.not().overflowing_add(Self::ONE);
let mut i = 0;
while i < N - 1 {
let (s, o) = (!self.bits.digits[i]).overflowing_add(1); // TODO: use overflowing add on signed integer digit instead
Expand All @@ -212,7 +216,7 @@ impl<const N: usize> BIntD8<N> {
}
i += 1;
}
let (s, o) = (!self.bits.digits[i] as digit::SignedDigit).overflowing_add(1);
let (s, o) = (self.bits.digits[i] as digit::SignedDigit).overflowing_neg();
self.bits.digits[i] = s as Digit;
(self, o)
}
Expand Down
1 change: 1 addition & 0 deletions src/buint/bigint_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ impl<const N: usize> BUintD8<N> {
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn widening_mul(self, rhs: Self) -> (Self, Self) {
// TODO: can use u128
let mut low = Self::ZERO;
let mut high = Self::ZERO;
let mut carry: Digit;
Expand Down
68 changes: 9 additions & 59 deletions src/buint/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ macro_rules! buint_as_int {
#[must_use = doc::must_use_op!()]
#[inline]
fn cast_from(from: BUintD8<N>) -> Self {
const BYTES: usize = <$int>::BITS as usize / 8;
// let low_digits: [u8; BYTES] = unsafe { *(from.digits.as_ptr() as *const _) };
let mut bytes = [0u8; BYTES];
let mut i = 0;
while i < BYTES && i < N {
bytes[i] = from.digits[i];
i += 1;
}
return Self::from_le_bytes(bytes);
let mut out = 0;
let mut i = 0;
while i << crate::digit::BIT_SHIFT < <$int>::BITS as usize && i < N {
Expand Down Expand Up @@ -225,62 +234,3 @@ mod tests {

crate::int::cast::tests!(utest);
}

macro_rules! buint_as_different_digit_bigint {
(BUintD8: ident, BIntD8: ident, Digit: ident; $(($OtherBUint: ident, $OtherDigit: ident)), *) => {
$(
impl<const N: usize, const M: usize> crate::cast::CastFrom<$OtherBUint<M>> for BUintD8<N> {
#[must_use = doc::must_use_op!()]
#[inline]
fn cast_from(from: $OtherBUint<M>) -> Self {
let mut out = Self::ZERO;
if Digit::BITS < $OtherDigit::BITS {
const DIVIDE_COUNT: usize = ($OtherDigit::BITS / Digit::BITS) as usize;
let stop_index: usize = if <$OtherBUint<M>>::BITS > <BUintD8<N>>::BITS {
N
} else {
M * DIVIDE_COUNT
};
let mut i = 0;
while i < stop_index {
let wider_digit = from.digits[i / DIVIDE_COUNT];
let mini_shift = i % DIVIDE_COUNT;
let digit = (wider_digit >> (mini_shift << digit::BIT_SHIFT)) as Digit;
out.digits[i] = digit;
i += 1;
}
} else {
const DIVIDE_COUNT: usize = (Digit::BITS / $OtherDigit::BITS) as usize;
let stop_index: usize = if <$OtherBUint<M>>::BITS > <BUintD8<N>>::BITS {
N * DIVIDE_COUNT
} else {
M
};
let mut current_digit: Digit = 0;
let mut i = 0;
while i < stop_index {
let mini_shift = i % DIVIDE_COUNT;
current_digit |= (from.digits[i] as Digit) << (mini_shift << digit::$OtherDigit::BIT_SHIFT);
if mini_shift == DIVIDE_COUNT - 1 || i == stop_index - 1 {
out.digits[i / DIVIDE_COUNT] = current_digit;
current_digit = 0;
}
i += 1;
}
}
out
}
}

impl<const N: usize, const M: usize> crate::cast::CastFrom<$OtherBUint<M>> for BIntD8<N> {
#[must_use = doc::must_use_op!()]
#[inline]
fn cast_from(from: $OtherBUint<M>) -> Self {
Self::from_bits(BUintD8::cast_from(from))
}
}
)*
}
}

pub(crate) use buint_as_different_digit_bigint;
1 change: 1 addition & 0 deletions src/buint/checked.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ impl<const N: usize> BUintD8<N> {
}

pub(crate) const fn div_rem_digit(self, rhs: Digit) -> (Self, Digit) {
// TODO: can use u128
let mut out = Self::ZERO;
let mut rem: Digit = 0;
let mut i = N;
Expand Down
19 changes: 19 additions & 0 deletions src/buint/const_trait_fillers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,32 @@ use core::cmp::Ordering;
impl<const N: usize> BUintD8<N> {
#[inline]
pub const fn bitand(self, rhs: Self) -> Self {
// TODO: can use u128
let mut out = Self::ZERO;
let mut i = 0;
while i < N {
out.digits[i] = self.digits[i] & rhs.digits[i];
i += 1;
}
return out;
while i < N {
let u128_a = super::u128_from_digits(&self.digits, i);
let u128_b = super::u128_from_digits(&rhs.digits, i);
let u128_out = u128_a & u128_b;
let out_bytes = u128_out.to_le_bytes();
let mut j = 0;
while j < 16 {
out.digits[i + j] = out_bytes[j];
j += 1;
}
i += 16;
}
out
}

#[inline]
pub const fn bitor(self, rhs: Self) -> Self {
// TODO: can use u128
let mut out = Self::ZERO;
let mut i = 0;
while i < N {
Expand All @@ -30,6 +45,7 @@ impl<const N: usize> BUintD8<N> {

#[inline]
pub const fn bitxor(self, rhs: Self) -> Self {
// TODO: can use u128
let mut out = Self::ZERO;
let mut i = 0;
while i < N {
Expand All @@ -41,6 +57,7 @@ impl<const N: usize> BUintD8<N> {

#[inline]
pub const fn not(self) -> Self {
// TODO: can use u128
let mut out = Self::ZERO;
let mut i = 0;
while i < N {
Expand All @@ -52,6 +69,7 @@ impl<const N: usize> BUintD8<N> {

#[inline]
pub const fn eq(&self, other: &Self) -> bool {
// TODO: can use u128
let mut i = 0;
while i < N {
if self.digits[i] != other.digits[i] {
Expand All @@ -69,6 +87,7 @@ impl<const N: usize> BUintD8<N> {

#[inline]
pub const fn cmp(&self, other: &Self) -> Ordering {
// TODO: can use u128
let mut i = N;
while i > 0 {
i -= 1;
Expand Down
3 changes: 3 additions & 0 deletions src/buint/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,7 @@ impl<const N: usize> BUintD8<N> {
pub const ZERO: Self = Self::MIN;

pos_const!(ONE 1, TWO 2, THREE 3, FOUR 4, FIVE 5, SIX 6, SEVEN 7, EIGHT 8, NINE 9, TEN 10);

pub(crate) const U128_DIGITS: usize = Self::BITS as usize / 128;
pub(crate) const U128_DIGIT_REMAINDER: usize = Self::BITS as usize % 128;
}
1 change: 1 addition & 0 deletions src/buint/div.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::{digit, Digit};

impl<const N: usize> BUintD8<N> {
pub(crate) const fn basecase_div_rem(self, mut v: Self, n: usize) -> (Self, Self) {
// TODO: can use u128
// The Art of Computer Programming Volume 2 by Donald Knuth, Section 4.3.1, Algorithm D

let mut q = Self::ZERO;
Expand Down
Loading

0 comments on commit 129e310

Please sign in to comment.