Skip to content

Commit 97b2439

Browse files
bors[bot]cuviper
andcommitted
Merge #9
9: Add a trait Roots with sqrt, cbrt, and nth_root r=cuviper a=cuviper Co-authored-by: Josh Stone <[email protected]>
2 parents 1abec40 + f22a269 commit 97b2439

File tree

7 files changed

+848
-1
lines changed

7 files changed

+848
-1
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ categories = ["algorithms", "science", "no-std"]
88
license = "MIT/Apache-2.0"
99
repository = "https://github.com/rust-num/num-integer"
1010
name = "num-integer"
11-
version = "0.1.38"
11+
version = "0.1.39"
1212
readme = "README.md"
1313
build = "build.rs"
1414

RELEASES.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
# Release 0.1.39
2+
3+
- [The new `Roots` trait provides `sqrt`, `cbrt`, and `nth_root` methods][9],
4+
calculating an `Integer`'s principal roots rounded toward zero.
5+
6+
**Contributors**: @cuviper
7+
8+
[9]: https://github.com/rust-num/num-integer/pull/9
9+
110
# Release 0.1.38
211

312
- [Support for 128-bit integers is now automatically detected and enabled.][8]

benches/roots.rs

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
//! Benchmark sqrt and cbrt
2+
3+
#![feature(test)]
4+
5+
extern crate num_integer;
6+
extern crate num_traits;
7+
extern crate test;
8+
9+
use num_integer::Integer;
10+
use num_traits::checked_pow;
11+
use num_traits::{AsPrimitive, PrimInt, WrappingAdd, WrappingMul};
12+
use test::{black_box, Bencher};
13+
14+
trait BenchInteger: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {}
15+
16+
impl<T> BenchInteger for T
17+
where
18+
T: Integer + PrimInt + WrappingAdd + WrappingMul + 'static,
19+
{
20+
}
21+
22+
fn bench<T, F>(b: &mut Bencher, v: &[T], f: F, n: u32)
23+
where
24+
T: BenchInteger,
25+
F: Fn(&T) -> T,
26+
{
27+
// Pre-validate the results...
28+
for i in v {
29+
let rt = f(i);
30+
if *i >= T::zero() {
31+
let rt1 = rt + T::one();
32+
assert!(rt.pow(n) <= *i);
33+
if let Some(x) = checked_pow(rt1, n as usize) {
34+
assert!(*i < x);
35+
}
36+
} else {
37+
let rt1 = rt - T::one();
38+
assert!(rt < T::zero());
39+
assert!(*i <= rt.pow(n));
40+
if let Some(x) = checked_pow(rt1, n as usize) {
41+
assert!(x < *i);
42+
}
43+
};
44+
}
45+
46+
// Now just run as fast as we can!
47+
b.iter(|| {
48+
for i in v {
49+
black_box(f(i));
50+
}
51+
});
52+
}
53+
54+
// Simple PRNG so we don't have to worry about rand compatibility
55+
fn lcg<T>(x: T) -> T
56+
where
57+
u32: AsPrimitive<T>,
58+
T: BenchInteger,
59+
{
60+
// LCG parameters from Numerical Recipes
61+
// (but we're applying it to arbitrary sizes)
62+
const LCG_A: u32 = 1664525;
63+
const LCG_C: u32 = 1013904223;
64+
x.wrapping_mul(&LCG_A.as_()).wrapping_add(&LCG_C.as_())
65+
}
66+
67+
fn bench_rand<T, F>(b: &mut Bencher, f: F, n: u32)
68+
where
69+
u32: AsPrimitive<T>,
70+
T: BenchInteger,
71+
F: Fn(&T) -> T,
72+
{
73+
let mut x: T = 3u32.as_();
74+
let v: Vec<T> = (0..1000)
75+
.map(|_| {
76+
x = lcg(x);
77+
x
78+
})
79+
.collect();
80+
bench(b, &v, f, n);
81+
}
82+
83+
fn bench_rand_pos<T, F>(b: &mut Bencher, f: F, n: u32)
84+
where
85+
u32: AsPrimitive<T>,
86+
T: BenchInteger,
87+
F: Fn(&T) -> T,
88+
{
89+
let mut x: T = 3u32.as_();
90+
let v: Vec<T> = (0..1000)
91+
.map(|_| {
92+
x = lcg(x);
93+
while x < T::zero() {
94+
x = lcg(x);
95+
}
96+
x
97+
})
98+
.collect();
99+
bench(b, &v, f, n);
100+
}
101+
102+
fn bench_small<T, F>(b: &mut Bencher, f: F, n: u32)
103+
where
104+
u32: AsPrimitive<T>,
105+
T: BenchInteger,
106+
F: Fn(&T) -> T,
107+
{
108+
let v: Vec<T> = (0..1000).map(|i| i.as_()).collect();
109+
bench(b, &v, f, n);
110+
}
111+
112+
fn bench_small_pos<T, F>(b: &mut Bencher, f: F, n: u32)
113+
where
114+
u32: AsPrimitive<T>,
115+
T: BenchInteger,
116+
F: Fn(&T) -> T,
117+
{
118+
let v: Vec<T> = (0..1000)
119+
.map(|i| i.as_().mod_floor(&T::max_value()))
120+
.collect();
121+
bench(b, &v, f, n);
122+
}
123+
124+
macro_rules! bench_roots {
125+
($($T:ident),*) => {$(
126+
mod $T {
127+
use test::Bencher;
128+
use num_integer::Roots;
129+
130+
#[bench]
131+
fn sqrt_rand(b: &mut Bencher) {
132+
::bench_rand_pos(b, $T::sqrt, 2);
133+
}
134+
135+
#[bench]
136+
fn sqrt_small(b: &mut Bencher) {
137+
::bench_small_pos(b, $T::sqrt, 2);
138+
}
139+
140+
#[bench]
141+
fn cbrt_rand(b: &mut Bencher) {
142+
::bench_rand(b, $T::cbrt, 3);
143+
}
144+
145+
#[bench]
146+
fn cbrt_small(b: &mut Bencher) {
147+
::bench_small(b, $T::cbrt, 3);
148+
}
149+
150+
#[bench]
151+
fn fourth_root_rand(b: &mut Bencher) {
152+
::bench_rand_pos(b, |x: &$T| x.nth_root(4), 4);
153+
}
154+
155+
#[bench]
156+
fn fourth_root_small(b: &mut Bencher) {
157+
::bench_small_pos(b, |x: &$T| x.nth_root(4), 4);
158+
}
159+
160+
#[bench]
161+
fn fifth_root_rand(b: &mut Bencher) {
162+
::bench_rand(b, |x: &$T| x.nth_root(5), 5);
163+
}
164+
165+
#[bench]
166+
fn fifth_root_small(b: &mut Bencher) {
167+
::bench_small(b, |x: &$T| x.nth_root(5), 5);
168+
}
169+
}
170+
)*}
171+
}
172+
173+
bench_roots!(i8, i16, i32, i64, i128);
174+
bench_roots!(u8, u16, u32, u64, u128);

ci/test_full.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,7 @@ if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable)$ ]]; then
1717
cargo build --verbose --features=i128
1818
cargo test --verbose --features=i128
1919
fi
20+
21+
if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then
22+
cargo test --verbose --all-features --benches
23+
fi

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ use core::mem;
2727

2828
use traits::{Num, Signed};
2929

30+
mod roots;
31+
pub use roots::Roots;
32+
pub use roots::{sqrt, cbrt, nth_root};
33+
3034
pub trait Integer: Sized + Num + PartialOrd + Ord + Eq {
3135
/// Floored integer division.
3236
///

0 commit comments

Comments
 (0)