Skip to content

Commit

Permalink
Merge pull request #38 from isaacholt100/v0.10.0
Browse files Browse the repository at this point in the history
v0.10.0
  • Loading branch information
isaacholt100 authored Nov 23, 2023
2 parents 6e26ddb + ef0634e commit f1520e5
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 163 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bnum"
version = "0.9.1"
version = "0.10.0"
authors = ["isaac-holt <[email protected]>"]
edition = "2021"
license = "MIT OR Apache-2.0"
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ This crate uses Rust's const generics to allow creation of integers of arbitrary
To install and use `bnum`, simply add the following line to your `Cargo.toml` file in the `[dependencies]` section:

```toml
bnum = "0.9.1"
bnum = "0.10.0"
```

Or, to enable various `bnum` features as well, add for example this line instead:

```toml
bnum = { version = "0.9.1", features = ["rand"] } # enables the "rand" feature
bnum = { version = "0.10.0", features = ["rand"] } # enables the "rand" feature
```

## Example Usage
Expand Down
153 changes: 77 additions & 76 deletions bench/benches/benchmark.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![feature(wrapping_next_power_of_two, int_roundings)]

use bnum::types::{U128 as BU128, U512};
use bnum::types::{U128, U512};
// use bnum::prelude::*;
use core::iter::Iterator;
use criterion::black_box;
Expand Down Expand Up @@ -34,17 +34,17 @@ macro_rules! unzip {
// unzip!(fn unzip3<T1, T2, T3>);
unzip!(fn unzip2<T1, T2>);

mod uuint {
uint::construct_uint! {
pub struct UU128(2);
}
// mod uuint {
// uint::construct_uint! {
// pub struct UU128(2);
// }

uint::construct_uint! {
pub struct UU512(8);
}
}
// uint::construct_uint! {
// pub struct UU512(8);
// }
// }

use uuint::*;
// use uuint::*;

macro_rules! bench_against_primitive {
{ $primitive: ty; $($method: ident ($($param: ident : $(ref $re: tt)? $ty: ty), *);) * } => {
Expand Down Expand Up @@ -75,7 +75,7 @@ macro_rules! bench_against_primitive {
group.bench_with_input(BenchmarkId::new("core", SIZE_ID), &prim_inputs, |b, inputs| {
b.iter(|| {
for ($($param), *, ()) in inputs.iter().cloned() {
let _ = [<U $primitive:upper>]::$method($($($re)? black_box($param)), *);
let _ = [<$primitive>]::$method($($($re)? black_box($param)), *);
}
})
});
Expand Down Expand Up @@ -106,66 +106,67 @@ trait Format {
fn lower_exp(self) -> String;
}

macro_rules! impl_format {
($($ty: ty), *) => {
$(
impl Format for $ty {
fn display(self) -> String {
format!("{}", self)
}
fn debug(self) -> String {
format!("{:?}", self)
}
fn binary(self) -> String {
format!("{:b}", self)
}
fn upper_hex(self) -> String {
format!("{:X}", self)
}
fn lower_hex(self) -> String {
format!("{:x}", self)
}
fn octal(self) -> String {
format!("{:o}", self)
}
fn upper_exp(self) -> String {
format!("{:E}", self)
}
fn lower_exp(self) -> String {
format!("{:e}", self)
}
}
)*
};
}

impl_format!(u128, BU128);

use core::cmp::{PartialEq, PartialOrd};
use core::ops::{BitAnd, BitOr, BitXor, Not};

// use num_traits::PrimInt;

trait BenchFrom<T> {
fn from(value: T) -> Self;
}

impl<'a> BenchFrom<&'a BU128> for &'a UU128 {
fn from(value: &'a BU128) -> Self {
unsafe {
&*(value as *const BU128 as *const UU128)
}
}
}

impl BenchFrom<u128> for UU128 {
fn from(value: u128) -> Self {
From::from(value)
}
}
// macro_rules! impl_format {
// ($($ty: ty), *) => {
// $(
// impl Format for $ty {
// fn display(self) -> String {
// format!("{}", self)
// }
// fn debug(self) -> String {
// format!("{:?}", self)
// }
// fn binary(self) -> String {
// format!("{:b}", self)
// }
// fn upper_hex(self) -> String {
// format!("{:X}", self)
// }
// fn lower_hex(self) -> String {
// format!("{:x}", self)
// }
// fn octal(self) -> String {
// format!("{:o}", self)
// }
// fn upper_exp(self) -> String {
// format!("{:E}", self)
// }
// fn lower_exp(self) -> String {
// format!("{:e}", self)
// }
// }
// )*
// };
// }

// impl_format!(u128, BU128);

// use core::cmp::{PartialEq, PartialOrd};
// use core::ops::{BitAnd, BitOr, BitXor, Not};

// // use num_traits::PrimInt;

// trait BenchFrom<T> {
// fn from(value: T) -> Self;
// }

// impl<'a> BenchFrom<&'a BU128> for &'a UU128 {
// fn from(value: &'a BU128) -> Self {
// unsafe {
// &*(value as *const BU128 as *const UU128)
// }
// }
// }

// impl BenchFrom<u128> for UU128 {
// fn from(value: u128) -> Self {
// From::from(value)
// }
// }

bench_against_primitive! {
u512;
u128;
from_be_bytes(a: [u8; 16]);
checked_add(a: u128, b: u128);
// checked_add_signed(a: u128, b: i128);
checked_sub(a: u128, b: u128);
Expand Down Expand Up @@ -241,13 +242,13 @@ bench_against_primitive! {
// reverse_bits(a: u128);
// is_power_of_two(a: u128);

bitand(a: u128, b: u128);
bitor(a: u128, b: u128);
bitxor(a: u128, b: u128);
not(a: u128);
// bitand(a: u128, b: u128);
// bitor(a: u128, b: u128);
// bitxor(a: u128, b: u128);
// not(a: u128);

eq(a: ref &u128, b: ref &u128);
partial_cmp(a: ref &u128, b: ref &u128);
// eq(a: ref &u128, b: ref &u128);
// partial_cmp(a: ref &u128, b: ref &u128);
}

criterion_main!(u512_benches);
criterion_main!(u128_benches);
5 changes: 3 additions & 2 deletions changes/prior-bugs.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
- `<= v0.1.0`: incorrect implementation of `from_be`, `to_be` on all integers.
- `<= v0.8.0`: `unchecked_shl`, `unchecked_shr` (only for `BUint` with `64` bit digits).
- `<= v0.8.0`: incorrect implementation of `unchecked_shl`, `unchecked_shr` for `BUint` with `64` bit digits.
- `<= v0.8.0`: incorrect implementation of `Add<$Digit>` for all `BUint`s (where `$Digit` is the underlying digit type).
- `<= v0.8.0`: `lcm` incorrectly panics when `self` is zero.
- `<= v0.8.0`: `lcm` incorrectly panics when `self` is zero.
- `v0.7.0 - v0.9.1`: the implementations of `shr, shl, wrapping_{shr, shl}, overflowing_{shr, shl}, checked_{shr, shl}, rotate_left, rotate_right, from_be_slice, from_le_slice` methods and any methods that involved left-shift or right-shift operations, contained undefined behaviour (this was due to a premature stabilisation of a feature in the Rust compiler - see <https://github.com/rust-lang/rust/pull/117905> and <https://github.com/isaacholt100/bnum/issues/36>). Note that all tests for these methods were still passing for each relevant version, so it is very likely that the code was still working correctly. However, as of the time of writing, the code that they relied on will soon be rejected by the compiler. They have now been replaced with safe implementations which are just as fast.
35 changes: 15 additions & 20 deletions src/bint/endian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,21 +77,16 @@ macro_rules! endian {
} else {
[0; N]
};
let slice_ptr = slice.as_ptr();
let mut i = 0;
let exact = len >> digit::$Digit::BYTE_SHIFT;
while i < exact {
let uninit = MaybeUninit::<[u8; digit::$Digit::BYTES as usize]>::uninit();
let ptr = uninit.as_ptr().cast_mut() as *mut u8;
let digit_bytes = unsafe {
slice_ptr
.add(
len - digit::$Digit::BYTES as usize
- (i << digit::$Digit::BYTE_SHIFT),
)
.copy_to_nonoverlapping(ptr, digit::$Digit::BYTES as usize);
uninit.assume_init()
};
let mut digit_bytes = [0u8; digit::$Digit::BYTES as usize];
let init_index = len - digit::$Digit::BYTES as usize;
let mut j = init_index;
while j < slice.len() {
digit_bytes[j - init_index] = slice[j - (i << digit::$Digit::BYTE_SHIFT)];
j += 1;
}
let digit = $Digit::from_be_bytes(digit_bytes);
set_digit!(out_digits, i, digit, is_negative, sign_bits);
i += 1;
Expand Down Expand Up @@ -140,14 +135,14 @@ macro_rules! endian {
let mut i = 0;
let exact = len >> digit::$Digit::BYTE_SHIFT;
while i < exact {
let uninit = MaybeUninit::<[u8; digit::$Digit::BYTES as usize]>::uninit();
let ptr = uninit.as_ptr().cast_mut() as *mut u8; // TODO: can change to as_mut_ptr() when const_mut_refs is stabilised
let digit_bytes = unsafe {
slice_ptr
.add(i << digit::$Digit::BYTE_SHIFT)
.copy_to_nonoverlapping(ptr, digit::$Digit::BYTES as usize);
uninit.assume_init()
};
let mut digit_bytes = [0u8; digit::$Digit::BYTES as usize];
let init_index = i << digit::$Digit::BYTE_SHIFT;
let mut j = init_index;
while j < init_index + digit::$Digit::BYTES as usize {
digit_bytes[j - init_index] = slice[j];
j += 1;
}

let digit = $Digit::from_le_bytes(digit_bytes);
set_digit!(out_digits, i, digit, is_negative, sign_bits);
i += 1;
Expand Down
26 changes: 13 additions & 13 deletions src/buint/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,26 +132,26 @@ macro_rules! cast {
crate::nightly::const_fn! {
#[inline]
const fn cast_up<const M: usize>(self, digit: $Digit) -> $BUint<M> {
let digits = [digit; M];
let digits_ptr = digits.as_ptr().cast_mut() as *mut $Digit; // TODO: can change to as_mut_ptr() when const_mut_refs is stabilised
let self_ptr = self.digits.as_ptr();
unsafe {
self_ptr.copy_to_nonoverlapping(digits_ptr, N);
$BUint::from_digits(digits)
let mut digits = [digit; M];
let mut i = M - N;
while i < M {
let index = i - (M - N);
digits[index] = self.digits[index];
i += 1;
}
$BUint::from_digits(digits)
}
}
crate::nightly::const_fn! {
#[inline]
const fn cast_down<const M: usize>(self) -> $BUint<M> {
let digits = MaybeUninit::<[$Digit; M]>::uninit();
let digits_ptr = digits.as_ptr().cast_mut() as *mut $Digit; // TODO: can change to as_mut_ptr() when const_mut_refs is stabilised
let self_ptr = self.digits.as_ptr();

unsafe {
self_ptr.copy_to_nonoverlapping(digits_ptr, M);
$BUint::from_digits(digits.assume_init())
let mut out = $BUint::ZERO;
let mut i = 0;
while i < M {
out.digits[i] = self.digits[i];
i += 1;
}
out
}
}
}
Expand Down
Loading

0 comments on commit f1520e5

Please sign in to comment.