Bug 1716518 - Upgrade num-bigint to v0.2.6 and num-integer to v0.1.44. r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D117749
This commit is contained in:
Mike Hommey 2021-06-15 20:39:43 +00:00
parent 7906527229
commit 436dcb8f9b
27 changed files with 977 additions and 83 deletions

12
Cargo.lock generated
View File

@ -3520,11 +3520,11 @@ dependencies = [
[[package]]
name = "num-bigint"
version = "0.2.3"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a"
checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
dependencies = [
"autocfg 0.1.6",
"autocfg 1.0.1",
"num-integer",
"num-traits",
]
@ -3542,11 +3542,11 @@ dependencies = [
[[package]]
name = "num-integer"
version = "0.1.41"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg 0.1.6",
"autocfg 1.0.1",
"num-traits",
]

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"ba1041ccca008388ab7d7432ae63b811d8e744c8fa9e50f371bfbeb78acd1995","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"25f684f15b0ed6ea216c3831e567a9b5dc02b78ff7e579e0d7323305db75218c","RELEASES.md":"5a3045437dc1850ae4e39acd14f2660ed7bace9b0c4d7dae3950f049dbfd4d65","benches/bigint.rs":"252c0dc1f220a6fbdc151e729069260c2f5909516467ceb873e412e5691d7042","benches/factorial.rs":"d536f5584987847f10321b94175a0d8fd2beb14b7c814ec28eef1f96ca081fbe","benches/gcd.rs":"7ec5ce7174e1d31bd08ccc5670f5a32a5c084f258d7980cd6d02e0a8bb5562c4","benches/roots.rs":"3f87db894c379122aee5cd8520c7c759c26d8a9649ac47f45d1bf4d560e1cb07","benches/shootout-pidigits.rs":"985b76d6dba05c396efe4da136c6a0bb2c02bcf5b05cbb346f0f802a891629bb","bors.toml":"1c81ede536a37edd30fe4e622ff0531b25372403ac9475a5d6c50f14156565a2","build.rs":"56d4fbb7a55750e61d2074df2735a31995c1decbd988c0e722926235e0fed487","ci/rustup.sh":"c976bb2756da3876363b01fdbf06c13de20df421e5add45e4017c4df42ed06a6","ci/test_full.sh":"a0ac26b85809eb43edd813c9dc88f34a1a8227b7618f4bede89c8f2ac9a4c05a","src/algorithms.rs":"8827c46df051214d1d0e7670680ca9f4834eae678ed340c86b5ea32fddbc7c3c","src/bigint.rs":"7f113fdc034c566bc8475ff0a7d136aa8250cae047b4356084e6797a15f968e1","src/bigrand.rs":"d2f72b8833f367dd8990b4b026f302d838144c5a4de942135d39a3a9932f137d","src/biguint.rs":"b95bfcf84e3f831fb07982aa4b058cd16a524eaa493946eed8e8c5fb8d65797a","src/lib.rs":"d5cc50306f73f07555e7d3413edd2ca5c7d54cbc80a2e83844d77fb8750ae314","src/macros.rs":"2e763517922d960c06e3ac4d319b1d81e66dffadfde8fdf300ff8b8bb95bd8cd","src/monty.rs":"6a867846b7f6af9115add2fd59fccd0651c71dd7f2316e8fb9c812ff3c27da12","tests/bigint.rs":"f7df454f085a862ad5a98e3a802303a3fdf06275a7a1b92074b40b76a715bed2","tests/bigint_bitwise.rs":"dc9436c8f200f2b0ac08cefb23bb8e39c4e688e9026a506a678416c3d573128b","tests/bigint_scalar.rs":"aa176ed102cafd425a215a93460806914d8f3ac288c98ec3e56772fa17379838","tests/biguint.rs":"9ae79f96d1a3beca5be95dffe9d79dc3436f886edc6cae51faf4203c3e0c4681","tests/biguint_scalar.rs":"9cc6f2bf2fe77f34b09eb2266c23aded3b27a60dc1859eb60d3013164292467e","tests/consts/mod.rs":"f9ea5f40733e2f5f432803d830be9db929d91e5e5efd8510b07c6ced2fe554be","tests/macros/mod.rs":"2789b680dd14a770d5ceef430018be0ada85098d69e218c61c17214084c4f763","tests/modpow.rs":"f14cdea11e355a371b314cc866dfa13281a3226706ab2cf01c1485273afde300","tests/quickcheck.rs":"6d6c1ec244b2384a8b34e989870aef8bcedccf6cc46e2626b29a032703bef03c","tests/rand.rs":"08370135bd78432660cfcd708a9ea852022d555bc92c1f3c482fabd17faa64a0","tests/roots.rs":"9ec1bdb0cd1c72402a41e5470325a5276af75979b7fc0f0b63e7bbbb9f3505b2","tests/serde.rs":"79d7a0347207b3a3666af67d2ed97fa34f2922732121a3cb8f5b9f990846acfa","tests/torture.rs":"9fe4897580c0ebe2b7062f5b0b890b4b03510daa45c9236f0edba7144f9eb6f8"},"package":"f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a"}
{"files":{"Cargo.toml":"e10df83bce937fc2d2ee258af173fee42891dc2d5bc3217955935669bdcc6dfb","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"00ff4891b409b25220a0f863c772a786c81cf291fab894963a2c8d7a251f67fd","RELEASES.md":"e712d5bdd58cc82a34f15f7926b4a7a65022ededc3069375fc54ab63eba2d133","benches/bigint.rs":"252c0dc1f220a6fbdc151e729069260c2f5909516467ceb873e412e5691d7042","benches/factorial.rs":"d536f5584987847f10321b94175a0d8fd2beb14b7c814ec28eef1f96ca081fbe","benches/gcd.rs":"7ec5ce7174e1d31bd08ccc5670f5a32a5c084f258d7980cd6d02e0a8bb5562c4","benches/roots.rs":"3f87db894c379122aee5cd8520c7c759c26d8a9649ac47f45d1bf4d560e1cb07","benches/shootout-pidigits.rs":"985b76d6dba05c396efe4da136c6a0bb2c02bcf5b05cbb346f0f802a891629bb","bors.toml":"1c81ede536a37edd30fe4e622ff0531b25372403ac9475a5d6c50f14156565a2","build.rs":"b4b2d0df90ca7570a339ca4d84a72e4ef00d9dced8927350424e666790c752d7","ci/rustup.sh":"c976bb2756da3876363b01fdbf06c13de20df421e5add45e4017c4df42ed06a6","ci/test_full.sh":"a0ac26b85809eb43edd813c9dc88f34a1a8227b7618f4bede89c8f2ac9a4c05a","src/algorithms.rs":"96220e32bd2496fbcba07ba35ef21e08e12a38d85d9724b33877c078040caf99","src/bigint.rs":"5d4888db1d8487a5c73bd4ee23967f4ba04f6f6edb4c3212902297e61f628141","src/bigrand.rs":"025b795928efa69592da2a7f54a60b0b72105ec6bae652f1f1b6402d6ca7bf3a","src/biguint.rs":"068abe461e9ba0582a2a18aede236ffdfe0cffc39fae9688f6a0873af6935b9b","src/lib.rs":"0f4280a9ffd3b8465ecaf9a7c99087bf18e5242b31d0311ac15bec4e995e5a41","src/macros.rs":"327691e39e31ac2d708e2bb02b50338d57cb0d3ca7107a30117df391bf781714","src/monty.rs":"ecdacb02e7d0a64b249a3395bf33c26f62b1ca05908f2eab0edd7f8f7a2ad7ae","tests/bigint.rs":"f7df454f085a862ad5a98e3a802303a3fdf06275a7a1b92074b40b76a715bed2","tests/bigint_bitwise.rs":"dc9436c8f200f2b0ac08cefb23bb8e39c4e688e9026a506a678416c3d573128b","tests/bigint_scalar.rs":"fddaa72911cd22cd34df130fee65dc1a1447ddbd9dfe5491b15e7a5868ee49e7","tests/biguint.rs":"9ae79f96d1a3beca5be95dffe9d79dc3436f886edc6cae51faf4203c3e0c4681","tests/biguint_scalar.rs":"4601e36b78bb177893f3abbd0a4050030eb8a65d3e57cdf005aea0a5b811adde","tests/consts/mod.rs":"f9ea5f40733e2f5f432803d830be9db929d91e5e5efd8510b07c6ced2fe554be","tests/macros/mod.rs":"5e73339e8baa9fc2c3f5b9097f9909091b5e4b47f905ffdf7da81d4647c6141c","tests/modpow.rs":"e21e46a97fc5da7eed1db5d6a52ac7ba50b78532f1a97aa46d41867d4848282c","tests/quickcheck.rs":"a3c68279b50cc35ec2856b74ac3f3265457dd788ed6138a14dd16a32868f22ba","tests/rand.rs":"08370135bd78432660cfcd708a9ea852022d555bc92c1f3c482fabd17faa64a0","tests/roots.rs":"9ec1bdb0cd1c72402a41e5470325a5276af75979b7fc0f0b63e7bbbb9f3505b2","tests/serde.rs":"79d7a0347207b3a3666af67d2ed97fa34f2922732121a3cb8f5b9f990846acfa","tests/torture.rs":"9fe4897580c0ebe2b7062f5b0b890b4b03510daa45c9236f0edba7144f9eb6f8"},"package":"090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"}

View File

@ -12,7 +12,7 @@
[package]
name = "num-bigint"
version = "0.2.3"
version = "0.2.6"
authors = ["The Rust Project Developers"]
build = "build.rs"
description = "Big integer implementation for Rust"
@ -42,11 +42,11 @@ name = "roots"
name = "shootout-pidigits"
harness = false
[dependencies.num-integer]
version = "0.1.39"
version = "0.1.42"
default-features = false
[dependencies.num-traits]
version = "0.2.7"
version = "0.2.11"
default-features = false
[dependencies.quickcheck]
@ -73,7 +73,7 @@ default-features = false
[dev-dependencies.serde_test]
version = "1.0"
[build-dependencies.autocfg]
version = "0.1.2"
version = "1"
[features]
default = ["std"]

View File

@ -33,6 +33,19 @@ Implementations for `i128` and `u128` are only available with Rust 1.26 and
later. The build script automatically detects this, but you can make it
mandatory by enabling the `i128` crate feature.
### Random Generation
`num-bigint` supports the generation of random big integers when the `rand`
feature is enabled. To enable it include rand as
```toml
rand = "0.5"
num-bigint = { version = "0.2", features = ["rand"] }
```
Note that you must use the version of `rand` that `num-bigint` is compatible
with: `0.5`.
## Releases
Release notes are available in [RELEASES.md](RELEASES.md).

View File

@ -1,3 +1,35 @@
# Release 0.2.6 (2020-01-27)
- [Fix the promotion of negative `isize` in `BigInt` assign-ops][133].
**Contributors**: @cuviper, @HactarCE
[133]: https://github.com/rust-num/num-bigint/pull/133
# Release 0.2.5 (2020-01-09)
- [Updated the `autocfg` build dependency to 1.0][126].
**Contributors**: @cuviper, @tspiteri
[126]: https://github.com/rust-num/num-bigint/pull/126
# Release 0.2.4 (2020-01-01)
- [The new `BigUint::to_u32_digits` method][104] returns the number as a
little-endian vector of base-2<sup>32</sup> digits. The same method on
`BigInt` also returns the sign.
- [`BigUint::modpow` now applies a modulus even for exponent 1][113], which
also affects `BigInt::modpow`.
- [`BigInt::modpow` now returns the correct sign for negative bases with even
exponents][114].
[104]: https://github.com/rust-num/num-bigint/pull/104
[113]: https://github.com/rust-num/num-bigint/pull/113
[114]: https://github.com/rust-num/num-bigint/pull/114
**Contributors**: @alex-ozdemir, @cuviper, @dingelish, @Speedy37, @youknowone
# Release 0.2.3 (2019-09-03)
- [`Pow` is now implemented for `BigUint` exponents][77].

View File

@ -10,5 +10,5 @@ fn main() {
panic!("i128 support was not detected!");
}
autocfg::rerun_path(file!());
autocfg::rerun_path("build.rs");
}

View File

@ -470,17 +470,17 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
let mut comp1: BigInt = (r1 - &r2) / 2;
let mut comp2: BigInt = r2 - &r0;
comp3 = (&comp2 - comp3) / 2 + &r4 * 2;
comp2 = comp2 + &comp1 - &r4;
comp1 = comp1 - &comp3;
comp2 += &comp1 - &r4;
comp1 -= &comp3;
// Recomposition. The coefficients of the polynomial are now known.
//
// Evaluate at w(t) where t is our given base to get the result.
let result = r0
+ (comp1 << 32 * i)
+ (comp2 << 2 * 32 * i)
+ (comp3 << 3 * 32 * i)
+ (r4 << 4 * 32 * i);
+ (comp1 << (32 * i))
+ (comp2 << (2 * 32 * i))
+ (comp3 << (3 * 32 * i))
+ (r4 << (4 * 32 * i));
let result_pos = result.to_biguint().unwrap();
add2(&mut acc[..], &result_pos.data);
}
@ -656,8 +656,8 @@ fn div_rem_core(mut a: BigUint, b: &BigUint) -> (BigUint, BigUint) {
while cmp_slice(&prod.data[..], &a.data[j..]) == Greater {
let one: BigUint = One::one();
q0 = q0 - one;
prod = prod - b;
q0 -= one;
prod -= b;
}
add2(&mut q.data[j..], &q0.data[..]);
@ -667,7 +667,7 @@ fn div_rem_core(mut a: BigUint, b: &BigUint) -> (BigUint, BigUint) {
tmp = q0;
}
debug_assert!(&a < b);
debug_assert!(a < *b);
(q.normalized(), a)
}
@ -759,7 +759,7 @@ pub fn cmp_slice(a: &[BigDigit], b: &[BigDigit]) -> Ordering {
return Greater;
}
}
return Equal;
Equal
}
#[cfg(test)]

View File

@ -2097,21 +2097,21 @@ impl<'a> Neg for &'a BigInt {
impl CheckedAdd for BigInt {
#[inline]
fn checked_add(&self, v: &BigInt) -> Option<BigInt> {
return Some(self.add(v));
Some(self.add(v))
}
}
impl CheckedSub for BigInt {
#[inline]
fn checked_sub(&self, v: &BigInt) -> Option<BigInt> {
return Some(self.sub(v));
Some(self.sub(v))
}
}
impl CheckedMul for BigInt {
#[inline]
fn checked_mul(&self, v: &BigInt) -> Option<BigInt> {
return Some(self.mul(v));
Some(self.mul(v))
}
}
@ -2121,7 +2121,7 @@ impl CheckedDiv for BigInt {
if v.is_zero() {
return None;
}
return Some(self.div(v));
Some(self.div(v))
}
}
@ -2195,7 +2195,7 @@ impl Integer for BigInt {
/// Deprecated, use `is_multiple_of` instead.
#[inline]
fn divides(&self, other: &BigInt) -> bool {
return self.is_multiple_of(other);
self.is_multiple_of(other)
}
/// Returns `true` if the number is a multiple of `other`.
@ -2572,7 +2572,7 @@ impl_to_bigint!(f64, FromPrimitive::from_f64);
impl BigInt {
/// Creates and initializes a BigInt.
///
/// The digits are in little-endian base 2<sup>32</sup>.
/// The base 2<sup>32</sup> digits are ordered least significant digit first.
#[inline]
pub fn new(sign: Sign, digits: Vec<u32>) -> BigInt {
BigInt::from_biguint(sign, BigUint::new(digits))
@ -2580,7 +2580,7 @@ impl BigInt {
/// Creates and initializes a `BigInt`.
///
/// The digits are in little-endian base 2<sup>32</sup>.
/// The base 2<sup>32</sup> digits are ordered least significant digit first.
#[inline]
pub fn from_biguint(mut sign: Sign, mut data: BigUint) -> BigInt {
if sign == NoSign {
@ -2596,12 +2596,16 @@ impl BigInt {
}
/// Creates and initializes a `BigInt`.
///
/// The base 2<sup>32</sup> digits are ordered least significant digit first.
#[inline]
pub fn from_slice(sign: Sign, slice: &[u32]) -> BigInt {
BigInt::from_biguint(sign, BigUint::from_slice(slice))
}
/// Reinitializes a `BigInt`.
///
/// The base 2<sup>32</sup> digits are ordered least significant digit first.
#[inline]
pub fn assign_from_slice(&mut self, sign: Sign, slice: &[u32]) {
if sign == NoSign {
@ -2778,7 +2782,26 @@ impl BigInt {
(self.sign, self.data.to_bytes_le())
}
/// Returns the two's complement byte representation of the `BigInt` in big-endian byte order.
/// Returns the sign and the `u32` digits representation of the `BigInt` ordered least
/// significant digit first.
///
/// # Examples
///
/// ```
/// use num_bigint::{BigInt, Sign};
///
/// assert_eq!(BigInt::from(-1125).to_u32_digits(), (Sign::Minus, vec![1125]));
/// assert_eq!(BigInt::from(4294967295u32).to_u32_digits(), (Sign::Plus, vec![4294967295]));
/// assert_eq!(BigInt::from(4294967296u64).to_u32_digits(), (Sign::Plus, vec![0, 1]));
/// assert_eq!(BigInt::from(-112500000000i64).to_u32_digits(), (Sign::Minus, vec![830850304, 26]));
/// assert_eq!(BigInt::from(112500000000i64).to_u32_digits(), (Sign::Plus, vec![830850304, 26]));
/// ```
#[inline]
pub fn to_u32_digits(&self) -> (Sign, Vec<u32>) {
(self.sign, self.data.to_u32_digits())
}
/// Returns the two's-complement byte representation of the `BigInt` in big-endian byte order.
///
/// # Examples
///
@ -2791,7 +2814,7 @@ impl BigInt {
#[inline]
pub fn to_signed_bytes_be(&self) -> Vec<u8> {
let mut bytes = self.data.to_bytes_be();
let first_byte = bytes.first().map(|v| *v).unwrap_or(0);
let first_byte = bytes.first().cloned().unwrap_or(0);
if first_byte > 0x7f
&& !(first_byte == 0x80
&& bytes.iter().skip(1).all(Zero::is_zero)
@ -2806,7 +2829,7 @@ impl BigInt {
bytes
}
/// Returns the two's complement byte representation of the `BigInt` in little-endian byte order.
/// Returns the two's-complement byte representation of the `BigInt` in little-endian byte order.
///
/// # Examples
///
@ -2819,7 +2842,7 @@ impl BigInt {
#[inline]
pub fn to_signed_bytes_le(&self) -> Vec<u8> {
let mut bytes = self.data.to_bytes_le();
let last_byte = bytes.last().map(|v| *v).unwrap_or(0);
let last_byte = bytes.last().cloned().unwrap_or(0);
if last_byte > 0x7f
&& !(last_byte == 0x80
&& bytes.iter().rev().skip(1).all(Zero::is_zero)
@ -2930,17 +2953,17 @@ impl BigInt {
#[inline]
pub fn checked_add(&self, v: &BigInt) -> Option<BigInt> {
return Some(self.add(v));
Some(self.add(v))
}
#[inline]
pub fn checked_sub(&self, v: &BigInt) -> Option<BigInt> {
return Some(self.sub(v));
Some(self.sub(v))
}
#[inline]
pub fn checked_mul(&self, v: &BigInt) -> Option<BigInt> {
return Some(self.mul(v));
Some(self.mul(v))
}
#[inline]
@ -2948,7 +2971,7 @@ impl BigInt {
if v.is_zero() {
return None;
}
return Some(self.div(v));
Some(self.div(v))
}
/// Returns `(self ^ exponent) mod modulus`
@ -2972,7 +2995,10 @@ impl BigInt {
}
// The sign of the result follows the modulus, like `mod_floor`.
let (sign, mag) = match (self.is_negative(), modulus.is_negative()) {
let (sign, mag) = match (
self.is_negative() && exponent.is_odd(),
modulus.is_negative(),
) {
(false, false) => (Plus, result),
(true, false) => (Plus, &modulus.data - result),
(false, true) => (Minus, &modulus.data - result),

View File

@ -14,6 +14,9 @@ use bigint::{into_magnitude, magnitude};
use integer::Integer;
use traits::Zero;
/// A trait for sampling random big integers.
///
/// The `rand` feature must be enabled to use this. See crate-level documentation for details.
pub trait RandBigInt {
/// Generate a random `BigUint` of the given bit size.
fn gen_biguint(&mut self, bit_size: usize) -> BigUint;
@ -191,6 +194,8 @@ impl SampleUniform for BigInt {
}
/// A random distribution for `BigUint` and `BigInt` values of a particular bit size.
///
/// The `rand` feature must be enabled to use this. See crate-level documentation for details.
#[derive(Clone, Copy, Debug)]
pub struct RandomBits {
bits: usize,

View File

@ -61,7 +61,7 @@ impl Arbitrary for BigUint {
#[allow(bare_trait_objects)] // `dyn` needs Rust 1.27 to parse, even when cfg-disabled
fn shrink(&self) -> Box<Iterator<Item = Self>> {
// Use shrinker from Vec
Box::new(self.data.shrink().map(|x| BigUint::new(x)))
Box::new(self.data.shrink().map(BigUint::new))
}
}
@ -600,7 +600,7 @@ impl AddAssign<u32> for BigUint {
#[inline]
fn add_assign(&mut self, other: u32) {
if other != 0 {
if self.data.len() == 0 {
if self.data.is_empty() {
self.data.push(0);
}
@ -745,7 +745,7 @@ impl Sub<BigUint> for u32 {
#[inline]
fn sub(self, mut other: BigUint) -> BigUint {
if other.data.len() == 0 {
if other.data.is_empty() {
other.data.push(self as BigDigit);
} else {
sub2rev(&[self as BigDigit], &mut other.data[..]);
@ -1225,7 +1225,7 @@ impl<'a> Neg for &'a BigUint {
impl CheckedAdd for BigUint {
#[inline]
fn checked_add(&self, v: &BigUint) -> Option<BigUint> {
return Some(self.add(v));
Some(self.add(v))
}
}
@ -1243,7 +1243,7 @@ impl CheckedSub for BigUint {
impl CheckedMul for BigUint {
#[inline]
fn checked_mul(&self, v: &BigUint) -> Option<BigUint> {
return Some(self.mul(v));
Some(self.mul(v))
}
}
@ -1253,7 +1253,7 @@ impl CheckedDiv for BigUint {
if v.is_zero() {
return None;
}
return Some(self.div(v));
Some(self.div(v))
}
}
@ -1678,9 +1678,9 @@ impl FromPrimitive for BigUint {
let mut ret = BigUint::from(mantissa);
if exponent > 0 {
ret = ret << exponent as usize;
ret <<= exponent as usize;
} else if exponent < 0 {
ret = ret >> (-exponent) as usize;
ret >>= (-exponent) as usize;
}
Some(ret)
}
@ -1915,7 +1915,7 @@ pub fn to_str_radix_reversed(u: &BigUint, radix: u32) -> Vec<u8> {
impl BigUint {
/// Creates and initializes a `BigUint`.
///
/// The digits are in little-endian base 2<sup>32</sup>.
/// The base 2<sup>32</sup> digits are ordered least significant digit first.
#[inline]
pub fn new(digits: Vec<u32>) -> BigUint {
BigUint { data: digits }.normalized()
@ -1923,7 +1923,7 @@ impl BigUint {
/// Creates and initializes a `BigUint`.
///
/// The digits are in little-endian base 2<sup>32</sup>.
/// The base 2<sup>32</sup> digits are ordered least significant digit first.
#[inline]
pub fn from_slice(slice: &[u32]) -> BigUint {
BigUint::new(slice.to_vec())
@ -1931,7 +1931,7 @@ impl BigUint {
/// Assign a value to a `BigUint`.
///
/// The digits are in little-endian base 2<sup>32</sup>.
/// The base 2<sup>32</sup> digits are ordered least significant digit first.
#[inline]
pub fn assign_from_slice(&mut self, slice: &[u32]) {
self.data.resize(slice.len(), 0);
@ -2125,6 +2125,24 @@ impl BigUint {
}
}
/// Returns the `u32` digits representation of the `BigUint` ordered least significant digit
/// first.
///
/// # Examples
///
/// ```
/// use num_bigint::BigUint;
///
/// assert_eq!(BigUint::from(1125u32).to_u32_digits(), vec![1125]);
/// assert_eq!(BigUint::from(4294967295u32).to_u32_digits(), vec![4294967295]);
/// assert_eq!(BigUint::from(4294967296u64).to_u32_digits(), vec![0, 1]);
/// assert_eq!(BigUint::from(112500000000u64).to_u32_digits(), vec![830850304, 26]);
/// ```
#[inline]
pub fn to_u32_digits(&self) -> Vec<u32> {
self.data.clone()
}
/// Returns the integer formatted as a string in the given radix.
/// `radix` must be in the range `2...36`.
///
@ -2190,7 +2208,7 @@ impl BigUint {
return 0;
}
let zeros = self.data.last().unwrap().leading_zeros();
return self.data.len() * big_digit::BITS - zeros as usize;
self.data.len() * big_digit::BITS - zeros as usize
}
/// Strips off trailing zero bigdigits - comparisons require the last element in the vector to
@ -2251,7 +2269,7 @@ fn plain_modpow(base: &BigUint, exp_data: &[BigDigit], modulus: &BigUint) -> Big
Some(i) => i,
};
let mut base = base.clone();
let mut base = base % modulus;
for _ in 0..i {
for _ in 0..big_digit::BITS {
base = &base * &base % modulus;

View File

@ -71,6 +71,33 @@
//! # }
//! ```
//!
//! See the "Features" section for instructions for enabling random number generation.
//!
//! ## Features
//!
//! The `std` crate feature is mandatory and enabled by default. If you depend on
//! `num-bigint` with `default-features = false`, you must manually enable the
//! `std` feature yourself. In the future, we hope to support `#![no_std]` with
//! the `alloc` crate when `std` is not enabled.
//!
//! Implementations for `i128` and `u128` are only available with Rust 1.26 and
//! later. The build script automatically detects this, but you can make it
//! mandatory by enabling the `i128` crate feature.
//!
//! ### Random Generation
//!
//! `num-bigint` supports the generation of random big integers when the `rand`
//! feature is enabled. To enable it include rand as
//!
//! ```toml
//! rand = "0.5"
//! num-bigint = { version = "0.2", features = ["rand"] }
//! ```
//!
//! Note that you must use the version of `rand` that `num-bigint` is compatible
//! with: `0.5`.
//!
//!
//! ## Compatibility
//!
//! The `num-bigint` crate is tested for rustc 1.15 and greater.

View File

@ -344,7 +344,7 @@ macro_rules! promote_signed_scalars {
macro_rules! promote_signed_scalars_assign {
(impl $imp:ident for $res:ty, $method:ident) => {
promote_scalars_assign!(impl $imp<i32> for $res, $method, i8, i16);
promote_scalars_assign!(impl $imp<UsizePromotion> for $res, $method, isize);
promote_scalars_assign!(impl $imp<IsizePromotion> for $res, $method, isize);
}
}

View File

@ -84,7 +84,7 @@ fn monty_redc(a: BigUint, mr: &MontyReducer) -> BigUint {
let ret = BigUint::new(c[n_size..].to_vec());
// 5: if R >= β^n then return R-N else return R.
if &ret < mr.n {
if ret < *mr.n {
ret
} else {
ret - mr.n
@ -121,7 +121,7 @@ pub fn monty_modpow(a: &BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint {
ans = monty_mult(ans, &apri, &mr);
}
apri = monty_sqr(apri, &mr);
e = e >> 1;
e >>= 1;
}
// Map the result back to the residues domain

View File

@ -18,6 +18,7 @@ fn test_scalar_add() {
fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
let (x, y, z) = (x.clone(), y.clone(), z.clone());
assert_signed_scalar_op!(x + y == z);
assert_signed_scalar_assign_op!(x += y == z);
}
for elm in SUM_TRIPLES.iter() {
@ -43,6 +44,7 @@ fn test_scalar_sub() {
fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
let (x, y, z) = (x.clone(), y.clone(), z.clone());
assert_signed_scalar_op!(x - y == z);
assert_signed_scalar_assign_op!(x -= y == z);
}
for elm in SUM_TRIPLES.iter() {
@ -68,6 +70,7 @@ fn test_scalar_mul() {
fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
let (x, y, z) = (x.clone(), y.clone(), z.clone());
assert_signed_scalar_op!(x * y == z);
assert_signed_scalar_assign_op!(x *= y == z);
}
for elm in MUL_TRIPLES.iter() {
@ -98,15 +101,18 @@ fn test_scalar_div_rem() {
assert!(q == *ans_q);
assert!(r == *ans_r);
let b = BigInt::from(b);
let (a, b, ans_q, ans_r) = (a.clone(), b.clone(), ans_q.clone(), ans_r.clone());
assert_op!(a / b == ans_q);
assert_op!(a % b == ans_r);
assert_signed_scalar_op!(a / b == ans_q);
assert_signed_scalar_op!(a % b == ans_r);
assert_signed_scalar_assign_op!(a /= b == ans_q);
assert_signed_scalar_assign_op!(a %= b == ans_r);
if b <= i32::max_value() as u32 {
let nb = -(b as i32);
assert_op!(a / nb == -ans_q.clone());
assert_op!(a % nb == ans_r);
}
let nb = -b;
assert_signed_scalar_op!(a / nb == -ans_q.clone());
assert_signed_scalar_op!(a % nb == ans_r);
assert_signed_scalar_assign_op!(a /= nb == -ans_q.clone());
assert_signed_scalar_assign_op!(a %= nb == ans_r);
}
fn check(a: &BigInt, b: u32, q: &BigInt, r: &BigInt) {

View File

@ -15,6 +15,7 @@ fn test_scalar_add() {
fn check(x: &BigUint, y: &BigUint, z: &BigUint) {
let (x, y, z) = (x.clone(), y.clone(), z.clone());
assert_unsigned_scalar_op!(x + y == z);
assert_unsigned_scalar_assign_op!(x += y == z);
}
for elm in SUM_TRIPLES.iter() {
@ -33,6 +34,7 @@ fn test_scalar_sub() {
fn check(x: &BigUint, y: &BigUint, z: &BigUint) {
let (x, y, z) = (x.clone(), y.clone(), z.clone());
assert_unsigned_scalar_op!(x - y == z);
assert_unsigned_scalar_assign_op!(x -= y == z);
}
for elm in SUM_TRIPLES.iter() {
@ -51,6 +53,7 @@ fn test_scalar_mul() {
fn check(x: &BigUint, y: &BigUint, z: &BigUint) {
let (x, y, z) = (x.clone(), y.clone(), z.clone());
assert_unsigned_scalar_op!(x * y == z);
assert_unsigned_scalar_assign_op!(x *= y == z);
}
for elm in MUL_TRIPLES.iter() {
@ -76,6 +79,8 @@ fn test_scalar_div_rem() {
let (x, y, z, r) = (x.clone(), y.clone(), z.clone(), r.clone());
assert_unsigned_scalar_op!(x / y == z);
assert_unsigned_scalar_op!(x % y == r);
assert_unsigned_scalar_assign_op!(x /= y == z);
assert_unsigned_scalar_assign_op!(x %= y == r);
}
for elm in MUL_TRIPLES.iter() {
@ -104,6 +109,8 @@ fn test_scalar_div_rem() {
check(&a, &b, &c, &d);
assert_unsigned_scalar_op!(a / b == c);
assert_unsigned_scalar_op!(a % b == d);
assert_unsigned_scalar_assign_op!(a /= b == c);
assert_unsigned_scalar_assign_op!(a %= b == d);
}
}
}

View File

@ -68,3 +68,49 @@ macro_rules! assert_signed_scalar_op {
$left $op $right == $expected);
};
}
/// Assert that an op works for scalar right
macro_rules! assert_scalar_assign_op {
(($($to:ident),*) $left:ident $op:tt $right:ident == $expected:expr) => {
$(
if let Some(right) = $right.$to() {
let mut left = $left.clone();
assert_eq!({ left $op right; left}, $expected);
}
)*
};
}
#[cfg(not(has_i128))]
macro_rules! assert_unsigned_scalar_assign_op {
($left:ident $op:tt $right:ident == $expected:expr) => {
assert_scalar_assign_op!((to_u8, to_u16, to_u32, to_u64, to_usize)
$left $op $right == $expected);
};
}
#[cfg(has_i128)]
macro_rules! assert_unsigned_scalar_assign_op {
($left:ident $op:tt $right:ident == $expected:expr) => {
assert_scalar_assign_op!((to_u8, to_u16, to_u32, to_u64, to_usize, to_u128)
$left $op $right == $expected);
};
}
#[cfg(not(has_i128))]
macro_rules! assert_signed_scalar_assign_op {
($left:ident $op:tt $right:ident == $expected:expr) => {
assert_scalar_assign_op!((to_u8, to_u16, to_u32, to_u64, to_usize,
to_i8, to_i16, to_i32, to_i64, to_isize)
$left $op $right == $expected);
};
}
#[cfg(has_i128)]
macro_rules! assert_signed_scalar_assign_op {
($left:ident $op:tt $right:ident == $expected:expr) => {
assert_scalar_assign_op!((to_u8, to_u16, to_u32, to_u64, to_usize, to_u128,
to_i8, to_i16, to_i32, to_i64, to_isize, to_i128)
$left $op $right == $expected);
};
}

View File

@ -81,6 +81,19 @@ mod biguint {
check_modpow::<u32>(0, 15, 11, 0);
check_modpow::<u32>(3, 7, 11, 9);
check_modpow::<u32>(5, 117, 19, 1);
check_modpow::<u32>(20, 1, 2, 0);
check_modpow::<u32>(20, 1, 3, 2);
}
#[test]
fn test_modpow_small() {
for b in 0u64..11 {
for e in 0u64..11 {
for m in 1..11 {
check_modpow::<u64>(b, e, m, b.pow(e as u32) % m);
}
}
}
}
#[test]
@ -102,7 +115,7 @@ mod biguint {
mod bigint {
use num_bigint::BigInt;
use num_integer::Integer;
use num_traits::{Num, One, Signed, Zero};
use num_traits::{Num, One, Signed};
fn check_modpow<T: Into<BigInt>>(b: T, e: T, m: T, r: T) {
fn check(b: &BigInt, e: &BigInt, m: &BigInt, r: &BigInt) {
@ -122,12 +135,18 @@ mod bigint {
let m: BigInt = m.into();
let r: BigInt = r.into();
let neg_r = if r.is_zero() { BigInt::zero() } else { &m - &r };
let neg_b_r = if e.is_odd() {
(-&r).mod_floor(&m)
} else {
r.clone()
};
let neg_m_r = r.mod_floor(&-&m);
let neg_bm_r = neg_b_r.mod_floor(&-&m);
check(&b, &e, &m, &r);
check(&-&b, &e, &m, &neg_r);
check(&b, &e, &-&m, &-neg_r);
check(&-b, &e, &-m, &-r);
check(&-&b, &e, &m, &neg_b_r);
check(&b, &e, &-&m, &neg_m_r);
check(&-b, &e, &-&m, &neg_bm_r);
}
#[test]
@ -136,6 +155,22 @@ mod bigint {
check_modpow(0, 15, 11, 0);
check_modpow(3, 7, 11, 9);
check_modpow(5, 117, 19, 1);
check_modpow(-20, 1, 2, 0);
check_modpow(-20, 1, 3, 1);
}
#[test]
fn test_modpow_small() {
for b in -10i64..11 {
for e in 0i64..11 {
for m in -10..11 {
if m == 0 {
continue;
}
check_modpow(b, e, m, b.pow(e as u32).mod_floor(&m));
}
}
}
}
#[test]

View File

@ -10,7 +10,8 @@ extern crate quickcheck;
extern crate quickcheck_macros;
use num_bigint::{BigInt, BigUint};
use num_traits::{Num, One, Pow, Zero};
use num_integer::Integer;
use num_traits::{Num, One, Pow, Signed, Zero};
use quickcheck::{QuickCheck, StdThreadGen, TestResult};
#[quickcheck]
@ -315,3 +316,46 @@ fn quicktest_shift() {
qc.quickcheck(test_shl_unsigned as fn(u32, u8) -> TestResult);
qc.quickcheck(test_shl_signed as fn(i32, u8) -> TestResult);
}
#[test]
fn quickcheck_modpow() {
let gen = StdThreadGen::new(usize::max_value());
let mut qc = QuickCheck::with_gen(gen);
fn simple_modpow(base: &BigInt, exponent: &BigInt, modulus: &BigInt) -> BigInt {
assert!(!exponent.is_negative());
let mut result = BigInt::one().mod_floor(modulus);
let mut base = base.mod_floor(modulus);
let mut exponent = exponent.clone();
while !exponent.is_zero() {
if exponent.is_odd() {
result = (result * &base).mod_floor(modulus);
}
base = (&base * &base).mod_floor(modulus);
exponent >>= 1;
}
result
}
fn test_modpow(base: i128, exponent: u128, modulus: i128) -> TestResult {
if modulus.is_zero() {
TestResult::discard()
} else {
let base = BigInt::from(base);
let exponent = BigInt::from(exponent);
let modulus = BigInt::from(modulus);
let modpow = base.modpow(&exponent, &modulus);
let simple = simple_modpow(&base, &exponent, &modulus);
if modpow != simple {
eprintln!("{}.modpow({}, {})", base, exponent, modulus);
eprintln!(" expected {}", simple);
eprintln!(" actual {}", modpow);
TestResult::failed()
} else {
TestResult::passed()
}
}
}
qc.quickcheck(test_modpow as fn(i128, u128, i128) -> TestResult);
}

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"54f4df5d505f0f8581a9455d2ea52bc385f003f97116c3d13b0e8e0cc491903f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"7ad5fb625f7ef61595a2180f3b26715457552faa8bb08526c70b416da29b2533","RELEASES.md":"ea8b30468b1d1c16ebe9e148a62df378cb9d3198bb4095c889fe521245690f9d","benches/gcd.rs":"9b5c0ae8ccd6c7fc8f8384fb351d10cfdd0be5fbea9365f9ea925d8915b015bf","benches/roots.rs":"79b4ab2d8fe7bbf43fe65314d2e1bc206165bc4cb34b3ceaa899f9ea7af31c09","build.rs":"56d4fbb7a55750e61d2074df2735a31995c1decbd988c0e722926235e0fed487","src/lib.rs":"937d6a77d6542b47aafb872df7181dcafc1ab596df0e5d78b2e6577ae9463dd0","src/roots.rs":"2a9b908bd3666b5cffc58c1b37d329e46ed02f71ad6d5deea1e8440c10660e1a","tests/roots.rs":"a0caa4142899ec8cb806a7a0d3410c39d50de97cceadc4c2ceca707be91b1ddd"},"package":"b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"}
{"files":{"Cargo.toml":"bf0e4a51897e9586cffa4897f69bf7caee769cc9b0292f3dd7ebd4fd5ddcb8f3","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"68f533703554b9130ea902776bd9eb20d1a2d32b213ebadebcd49ed0f1ef9728","RELEASES.md":"658b382f2358d6f6733021ecfdcc1fc1faf89d7106e0f72d0f3b34d35442d71b","benches/average.rs":"2a30b4ccd8ece8663d17583ae2e3623e654b5f401babef90f1634722824e6c2b","benches/gcd.rs":"9b5c0ae8ccd6c7fc8f8384fb351d10cfdd0be5fbea9365f9ea925d8915b015bf","benches/roots.rs":"79b4ab2d8fe7bbf43fe65314d2e1bc206165bc4cb34b3ceaa899f9ea7af31c09","build.rs":"575b157527243fe355a7c8d7d874a1f790c3fb0177beba9032076a7803c5b9dd","src/average.rs":"a66cf6a49f893e60697c17b2540258e69daa15ab97d8d444c6f2e8cac2f01ae9","src/lib.rs":"bf0ce9a09f92f606ca038288cde7a29670ccca480d42ec97e88f3c56b117e33c","src/roots.rs":"2a9b908bd3666b5cffc58c1b37d329e46ed02f71ad6d5deea1e8440c10660e1a","tests/average.rs":"5f26a31be042626e9af66f7b751798621561fa090da48b1ec5ab63e388288a91","tests/roots.rs":"a0caa4142899ec8cb806a7a0d3410c39d50de97cceadc4c2ceca707be91b1ddd"},"package":"d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"}

View File

@ -12,25 +12,25 @@
[package]
name = "num-integer"
version = "0.1.41"
version = "0.1.44"
authors = ["The Rust Project Developers"]
build = "build.rs"
exclude = ["/ci/*", "/.travis.yml", "/bors.toml"]
exclude = ["/bors.toml", "/ci/*", "/.github/*"]
description = "Integer traits and functions"
homepage = "https://github.com/rust-num/num-integer"
documentation = "https://docs.rs/num-integer"
readme = "README.md"
keywords = ["mathematics", "numerics"]
categories = ["algorithms", "science", "no-std"]
license = "MIT/Apache-2.0"
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-num/num-integer"
[package.metadata.docs.rs]
features = ["std"]
[dependencies.num-traits]
version = "0.2.4"
version = "0.2.11"
default-features = false
[build-dependencies.autocfg]
version = "0.1.3"
version = "1"
[features]
default = ["std"]

View File

@ -2,8 +2,8 @@
[![crate](https://img.shields.io/crates/v/num-integer.svg)](https://crates.io/crates/num-integer)
[![documentation](https://docs.rs/num-integer/badge.svg)](https://docs.rs/num-integer)
![minimum rustc 1.8](https://img.shields.io/badge/rustc-1.8+-red.svg)
[![Travis status](https://travis-ci.org/rust-num/num-integer.svg?branch=master)](https://travis-ci.org/rust-num/num-integer)
[![minimum rustc 1.8](https://img.shields.io/badge/rustc-1.8+-red.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
[![build status](https://github.com/rust-num/num-integer/workflows/master/badge.svg)](https://github.com/rust-num/num-integer/actions)
`Integer` trait and functions for Rust.
@ -40,7 +40,6 @@ Implementations for `i128` and `u128` are only available with Rust 1.26 and
later. The build script automatically detects this, but you can make it
mandatory by enabling the `i128` crate feature.
## Releases
Release notes are available in [RELEASES.md](RELEASES.md).
@ -48,3 +47,18 @@ Release notes are available in [RELEASES.md](RELEASES.md).
## Compatibility
The `num-integer` crate is tested for rustc 1.8 and greater.
## License
Licensed under either of
* [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
* [MIT license](http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.

View File

@ -1,3 +1,30 @@
# Release 0.1.44 (2020-10-29)
- [The "i128" feature now bypasses compiler probing][35]. The build script
used to probe anyway and panic if requested support wasn't found, but
sometimes this ran into bad corner cases with `autocfg`.
**Contributors**: @cuviper
[35]: https://github.com/rust-num/num-integer/pull/35
# Release 0.1.43 (2020-06-11)
- [The new `Average` trait][31] computes fast integer averages, rounded up or
down, without any risk of overflow.
**Contributors**: @althonos, @cuviper
[31]: https://github.com/rust-num/num-integer/pull/31
# Release 0.1.42 (2020-01-09)
- [Updated the `autocfg` build dependency to 1.0][29].
**Contributors**: @cuviper, @dingelish
[29]: https://github.com/rust-num/num-integer/pull/29
# Release 0.1.41 (2019-05-21)
- [Fixed feature detection on `no_std` targets][25].

View File

@ -0,0 +1,414 @@
//! Benchmark sqrt and cbrt
#![feature(test)]
extern crate num_integer;
extern crate num_traits;
extern crate test;
use num_integer::Integer;
use num_traits::{AsPrimitive, PrimInt, WrappingAdd, WrappingMul};
use std::cmp::{max, min};
use std::fmt::Debug;
use test::{black_box, Bencher};
// --- Utilities for RNG ----------------------------------------------------
trait BenchInteger: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {}
impl<T> BenchInteger for T where T: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {}
// Simple PRNG so we don't have to worry about rand compatibility
fn lcg<T>(x: T) -> T
where
u32: AsPrimitive<T>,
T: BenchInteger,
{
// LCG parameters from Numerical Recipes
// (but we're applying it to arbitrary sizes)
const LCG_A: u32 = 1664525;
const LCG_C: u32 = 1013904223;
x.wrapping_mul(&LCG_A.as_()).wrapping_add(&LCG_C.as_())
}
// --- Alt. Implementations -------------------------------------------------
trait NaiveAverage {
fn naive_average_ceil(&self, other: &Self) -> Self;
fn naive_average_floor(&self, other: &Self) -> Self;
}
trait UncheckedAverage {
fn unchecked_average_ceil(&self, other: &Self) -> Self;
fn unchecked_average_floor(&self, other: &Self) -> Self;
}
trait ModuloAverage {
fn modulo_average_ceil(&self, other: &Self) -> Self;
fn modulo_average_floor(&self, other: &Self) -> Self;
}
macro_rules! naive_average {
($T:ident) => {
impl super::NaiveAverage for $T {
fn naive_average_floor(&self, other: &$T) -> $T {
match self.checked_add(*other) {
Some(z) => z.div_floor(&2),
None => {
if self > other {
let diff = self - other;
other + diff.div_floor(&2)
} else {
let diff = other - self;
self + diff.div_floor(&2)
}
}
}
}
fn naive_average_ceil(&self, other: &$T) -> $T {
match self.checked_add(*other) {
Some(z) => z.div_ceil(&2),
None => {
if self > other {
let diff = self - other;
self - diff.div_floor(&2)
} else {
let diff = other - self;
other - diff.div_floor(&2)
}
}
}
}
}
};
}
macro_rules! unchecked_average {
($T:ident) => {
impl super::UncheckedAverage for $T {
fn unchecked_average_floor(&self, other: &$T) -> $T {
self.wrapping_add(*other) / 2
}
fn unchecked_average_ceil(&self, other: &$T) -> $T {
(self.wrapping_add(*other) / 2).wrapping_add(1)
}
}
};
}
macro_rules! modulo_average {
($T:ident) => {
impl super::ModuloAverage for $T {
fn modulo_average_ceil(&self, other: &$T) -> $T {
let (q1, r1) = self.div_mod_floor(&2);
let (q2, r2) = other.div_mod_floor(&2);
q1 + q2 + (r1 | r2)
}
fn modulo_average_floor(&self, other: &$T) -> $T {
let (q1, r1) = self.div_mod_floor(&2);
let (q2, r2) = other.div_mod_floor(&2);
q1 + q2 + (r1 * r2)
}
}
};
}
// --- Bench functions ------------------------------------------------------
fn bench_unchecked<T, F>(b: &mut Bencher, v: &[(T, T)], f: F)
where
T: Integer + Debug + Copy,
F: Fn(&T, &T) -> T,
{
b.iter(|| {
for (x, y) in v {
black_box(f(x, y));
}
});
}
fn bench_ceil<T, F>(b: &mut Bencher, v: &[(T, T)], f: F)
where
T: Integer + Debug + Copy,
F: Fn(&T, &T) -> T,
{
for &(i, j) in v {
let rt = f(&i, &j);
let (a, b) = (min(i, j), max(i, j));
// if both number are the same sign, check rt is in the middle
if (a < T::zero()) == (b < T::zero()) {
if (b - a).is_even() {
assert_eq!(rt - a, b - rt);
} else {
assert_eq!(rt - a, b - rt + T::one());
}
// if both number have a different sign,
} else {
if (a + b).is_even() {
assert_eq!(rt, (a + b) / (T::one() + T::one()))
} else {
assert_eq!(rt, (a + b + T::one()) / (T::one() + T::one()))
}
}
}
bench_unchecked(b, v, f);
}
fn bench_floor<T, F>(b: &mut Bencher, v: &[(T, T)], f: F)
where
T: Integer + Debug + Copy,
F: Fn(&T, &T) -> T,
{
for &(i, j) in v {
let rt = f(&i, &j);
let (a, b) = (min(i, j), max(i, j));
// if both number are the same sign, check rt is in the middle
if (a < T::zero()) == (b < T::zero()) {
if (b - a).is_even() {
assert_eq!(rt - a, b - rt);
} else {
assert_eq!(rt - a + T::one(), b - rt);
}
// if both number have a different sign,
} else {
if (a + b).is_even() {
assert_eq!(rt, (a + b) / (T::one() + T::one()))
} else {
assert_eq!(rt, (a + b - T::one()) / (T::one() + T::one()))
}
}
}
bench_unchecked(b, v, f);
}
// --- Bench implementation -------------------------------------------------
macro_rules! bench_average {
($($T:ident),*) => {$(
mod $T {
use test::Bencher;
use num_integer::{Average, Integer};
use super::{UncheckedAverage, NaiveAverage, ModuloAverage};
use super::{bench_ceil, bench_floor, bench_unchecked};
naive_average!($T);
unchecked_average!($T);
modulo_average!($T);
const SIZE: $T = 30;
fn overflowing() -> Vec<($T, $T)> {
(($T::max_value()-SIZE)..$T::max_value())
.flat_map(|x| -> Vec<_> {
(($T::max_value()-100)..($T::max_value()-100+SIZE))
.map(|y| (x, y))
.collect()
})
.collect()
}
fn small() -> Vec<($T, $T)> {
(0..SIZE)
.flat_map(|x| -> Vec<_> {(0..SIZE).map(|y| (x, y)).collect()})
.collect()
}
fn rand() -> Vec<($T, $T)> {
small()
.into_iter()
.map(|(x, y)| (super::lcg(x), super::lcg(y)))
.collect()
}
mod ceil {
use super::*;
mod small {
use super::*;
#[bench]
fn optimized(b: &mut Bencher) {
let v = small();
bench_ceil(b, &v, |x: &$T, y: &$T| x.average_ceil(y));
}
#[bench]
fn naive(b: &mut Bencher) {
let v = small();
bench_ceil(b, &v, |x: &$T, y: &$T| x.naive_average_ceil(y));
}
#[bench]
fn unchecked(b: &mut Bencher) {
let v = small();
bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_ceil(y));
}
#[bench]
fn modulo(b: &mut Bencher) {
let v = small();
bench_ceil(b, &v, |x: &$T, y: &$T| x.modulo_average_ceil(y));
}
}
mod overflowing {
use super::*;
#[bench]
fn optimized(b: &mut Bencher) {
let v = overflowing();
bench_ceil(b, &v, |x: &$T, y: &$T| x.average_ceil(y));
}
#[bench]
fn naive(b: &mut Bencher) {
let v = overflowing();
bench_ceil(b, &v, |x: &$T, y: &$T| x.naive_average_ceil(y));
}
#[bench]
fn unchecked(b: &mut Bencher) {
let v = overflowing();
bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_ceil(y));
}
#[bench]
fn modulo(b: &mut Bencher) {
let v = overflowing();
bench_ceil(b, &v, |x: &$T, y: &$T| x.modulo_average_ceil(y));
}
}
mod rand {
use super::*;
#[bench]
fn optimized(b: &mut Bencher) {
let v = rand();
bench_ceil(b, &v, |x: &$T, y: &$T| x.average_ceil(y));
}
#[bench]
fn naive(b: &mut Bencher) {
let v = rand();
bench_ceil(b, &v, |x: &$T, y: &$T| x.naive_average_ceil(y));
}
#[bench]
fn unchecked(b: &mut Bencher) {
let v = rand();
bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_ceil(y));
}
#[bench]
fn modulo(b: &mut Bencher) {
let v = rand();
bench_ceil(b, &v, |x: &$T, y: &$T| x.modulo_average_ceil(y));
}
}
}
mod floor {
use super::*;
mod small {
use super::*;
#[bench]
fn optimized(b: &mut Bencher) {
let v = small();
bench_floor(b, &v, |x: &$T, y: &$T| x.average_floor(y));
}
#[bench]
fn naive(b: &mut Bencher) {
let v = small();
bench_floor(b, &v, |x: &$T, y: &$T| x.naive_average_floor(y));
}
#[bench]
fn unchecked(b: &mut Bencher) {
let v = small();
bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_floor(y));
}
#[bench]
fn modulo(b: &mut Bencher) {
let v = small();
bench_floor(b, &v, |x: &$T, y: &$T| x.modulo_average_floor(y));
}
}
mod overflowing {
use super::*;
#[bench]
fn optimized(b: &mut Bencher) {
let v = overflowing();
bench_floor(b, &v, |x: &$T, y: &$T| x.average_floor(y));
}
#[bench]
fn naive(b: &mut Bencher) {
let v = overflowing();
bench_floor(b, &v, |x: &$T, y: &$T| x.naive_average_floor(y));
}
#[bench]
fn unchecked(b: &mut Bencher) {
let v = overflowing();
bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_floor(y));
}
#[bench]
fn modulo(b: &mut Bencher) {
let v = overflowing();
bench_floor(b, &v, |x: &$T, y: &$T| x.modulo_average_floor(y));
}
}
mod rand {
use super::*;
#[bench]
fn optimized(b: &mut Bencher) {
let v = rand();
bench_floor(b, &v, |x: &$T, y: &$T| x.average_floor(y));
}
#[bench]
fn naive(b: &mut Bencher) {
let v = rand();
bench_floor(b, &v, |x: &$T, y: &$T| x.naive_average_floor(y));
}
#[bench]
fn unchecked(b: &mut Bencher) {
let v = rand();
bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_floor(y));
}
#[bench]
fn modulo(b: &mut Bencher) {
let v = rand();
bench_floor(b, &v, |x: &$T, y: &$T| x.modulo_average_floor(y));
}
}
}
}
)*}
}
bench_average!(i8, i16, i32, i64, i128, isize);
bench_average!(u8, u16, u32, u64, u128, usize);

View File

@ -3,12 +3,11 @@ extern crate autocfg;
use std::env;
fn main() {
let ac = autocfg::new();
if ac.probe_type("i128") {
println!("cargo:rustc-cfg=has_i128");
} else if env::var_os("CARGO_FEATURE_I128").is_some() {
panic!("i128 support was not detected!");
// If the "i128" feature is explicity requested, don't bother probing for it.
// It will still cause a build error if that was set improperly.
if env::var_os("CARGO_FEATURE_I128").is_some() || autocfg::new().probe_type("i128") {
autocfg::emit("has_i128");
}
autocfg::rerun_path(file!());
autocfg::rerun_path("build.rs");
}

View File

@ -0,0 +1,78 @@
use core::ops::{BitAnd, BitOr, BitXor, Shr};
use Integer;
/// Provides methods to compute the average of two integers, without overflows.
pub trait Average: Integer {
/// Returns the ceiling value of the average of `self` and `other`.
/// -- `⌈(self + other)/2⌉`
///
/// # Examples
///
/// ```
/// use num_integer::Average;
///
/// assert_eq!(( 3).average_ceil(&10), 7);
/// assert_eq!((-2).average_ceil(&-5), -3);
/// assert_eq!(( 4).average_ceil(& 4), 4);
///
/// assert_eq!(u8::max_value().average_ceil(&2), 129);
/// assert_eq!(i8::min_value().average_ceil(&-1), -64);
/// assert_eq!(i8::min_value().average_ceil(&i8::max_value()), 0);
/// ```
///
fn average_ceil(&self, other: &Self) -> Self;
/// Returns the floor value of the average of `self` and `other`.
/// -- `⌊(self + other)/2⌋`
///
/// # Examples
///
/// ```
/// use num_integer::Average;
///
/// assert_eq!(( 3).average_floor(&10), 6);
/// assert_eq!((-2).average_floor(&-5), -4);
/// assert_eq!(( 4).average_floor(& 4), 4);
///
/// assert_eq!(u8::max_value().average_floor(&2), 128);
/// assert_eq!(i8::min_value().average_floor(&-1), -65);
/// assert_eq!(i8::min_value().average_floor(&i8::max_value()), -1);
/// ```
///
fn average_floor(&self, other: &Self) -> Self;
}
impl<I> Average for I
where
I: Integer + Shr<usize, Output = I>,
for<'a, 'b> &'a I:
BitAnd<&'b I, Output = I> + BitOr<&'b I, Output = I> + BitXor<&'b I, Output = I>,
{
// The Henry Gordon Dietz implementation as shown in the Hacker's Delight,
// see http://aggregate.org/MAGIC/#Average%20of%20Integers
/// Returns the floor value of the average of `self` and `other`.
#[inline]
fn average_floor(&self, other: &I) -> I {
(self & other) + ((self ^ other) >> 1)
}
/// Returns the ceil value of the average of `self` and `other`.
#[inline]
fn average_ceil(&self, other: &I) -> I {
(self | other) - ((self ^ other) >> 1)
}
}
/// Returns the floor value of the average of `x` and `y` --
/// see [Average::average_floor](trait.Average.html#tymethod.average_floor).
#[inline]
pub fn average_floor<T: Average>(x: T, y: T) -> T {
x.average_floor(&y)
}
/// Returns the ceiling value of the average of `x` and `y` --
/// see [Average::average_ceil](trait.Average.html#tymethod.average_ceil).
#[inline]
pub fn average_ceil<T: Average>(x: T, y: T) -> T {
x.average_ceil(&y)
}

View File

@ -30,6 +30,10 @@ mod roots;
pub use roots::Roots;
pub use roots::{cbrt, nth_root, sqrt};
mod average;
pub use average::Average;
pub use average::{average_ceil, average_floor};
pub trait Integer: Sized + Num + PartialOrd + Ord + Eq {
/// Floored integer division.
///
@ -257,7 +261,6 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq {
/// assert_eq!((-1).div_rem( &2), ( 0, -1));
/// assert_eq!((-1).div_rem(&-2), ( 0, -1));
/// ~~~
#[inline]
fn div_rem(&self, other: &Self) -> (Self, Self);
/// Simultaneous floored integer division and modulus.

View File

@ -0,0 +1,100 @@
extern crate num_integer;
extern crate num_traits;
macro_rules! test_average {
($I:ident, $U:ident) => {
mod $I {
mod ceil {
use num_integer::Average;
#[test]
fn same_sign() {
assert_eq!((14 as $I).average_ceil(&16), 15 as $I);
assert_eq!((14 as $I).average_ceil(&17), 16 as $I);
let max = $crate::std::$I::MAX;
assert_eq!((max - 3).average_ceil(&(max - 1)), max - 2);
assert_eq!((max - 3).average_ceil(&(max - 2)), max - 2);
}
#[test]
fn different_sign() {
assert_eq!((14 as $I).average_ceil(&-4), 5 as $I);
assert_eq!((14 as $I).average_ceil(&-5), 5 as $I);
let min = $crate::std::$I::MIN;
let max = $crate::std::$I::MAX;
assert_eq!(min.average_ceil(&max), 0 as $I);
}
}
mod floor {
use num_integer::Average;
#[test]
fn same_sign() {
assert_eq!((14 as $I).average_floor(&16), 15 as $I);
assert_eq!((14 as $I).average_floor(&17), 15 as $I);
let max = $crate::std::$I::MAX;
assert_eq!((max - 3).average_floor(&(max - 1)), max - 2);
assert_eq!((max - 3).average_floor(&(max - 2)), max - 3);
}
#[test]
fn different_sign() {
assert_eq!((14 as $I).average_floor(&-4), 5 as $I);
assert_eq!((14 as $I).average_floor(&-5), 4 as $I);
let min = $crate::std::$I::MIN;
let max = $crate::std::$I::MAX;
assert_eq!(min.average_floor(&max), -1 as $I);
}
}
}
mod $U {
mod ceil {
use num_integer::Average;
#[test]
fn bounded() {
assert_eq!((14 as $U).average_ceil(&16), 15 as $U);
assert_eq!((14 as $U).average_ceil(&17), 16 as $U);
}
#[test]
fn overflow() {
let max = $crate::std::$U::MAX;
assert_eq!((max - 3).average_ceil(&(max - 1)), max - 2);
assert_eq!((max - 3).average_ceil(&(max - 2)), max - 2);
}
}
mod floor {
use num_integer::Average;
#[test]
fn bounded() {
assert_eq!((14 as $U).average_floor(&16), 15 as $U);
assert_eq!((14 as $U).average_floor(&17), 15 as $U);
}
#[test]
fn overflow() {
let max = $crate::std::$U::MAX;
assert_eq!((max - 3).average_floor(&(max - 1)), max - 2);
assert_eq!((max - 3).average_floor(&(max - 2)), max - 3);
}
}
}
};
}
test_average!(i8, u8);
test_average!(i16, u16);
test_average!(i32, u32);
test_average!(i64, u64);
#[cfg(has_i128)]
test_average!(i128, u128);
test_average!(isize, usize);