1 #![feature(test)]
2 #![cfg(feature = "rand")]
3 
4 extern crate test;
5 
6 use num_bigint::{BigInt, BigUint, RandBigInt};
7 use num_traits::{FromPrimitive, Num, One, Zero};
8 use std::mem::replace;
9 use test::Bencher;
10 
11 mod rng;
12 use rng::get_rng;
13 
multiply_bench(b: &mut Bencher, xbits: u64, ybits: u64)14 fn multiply_bench(b: &mut Bencher, xbits: u64, ybits: u64) {
15     let mut rng = get_rng();
16     let x = rng.gen_bigint(xbits);
17     let y = rng.gen_bigint(ybits);
18 
19     b.iter(|| &x * &y);
20 }
21 
divide_bench(b: &mut Bencher, xbits: u64, ybits: u64)22 fn divide_bench(b: &mut Bencher, xbits: u64, ybits: u64) {
23     let mut rng = get_rng();
24     let x = rng.gen_bigint(xbits);
25     let y = rng.gen_bigint(ybits);
26 
27     b.iter(|| &x / &y);
28 }
29 
remainder_bench(b: &mut Bencher, xbits: u64, ybits: u64)30 fn remainder_bench(b: &mut Bencher, xbits: u64, ybits: u64) {
31     let mut rng = get_rng();
32     let x = rng.gen_bigint(xbits);
33     let y = rng.gen_bigint(ybits);
34 
35     b.iter(|| &x % &y);
36 }
37 
factorial(n: usize) -> BigUint38 fn factorial(n: usize) -> BigUint {
39     let mut f: BigUint = One::one();
40     for i in 1..=n {
41         let bu: BigUint = FromPrimitive::from_usize(i).unwrap();
42         f *= bu;
43     }
44     f
45 }
46 
47 /// Compute Fibonacci numbers
fib(n: usize) -> BigUint48 fn fib(n: usize) -> BigUint {
49     let mut f0: BigUint = Zero::zero();
50     let mut f1: BigUint = One::one();
51     for _ in 0..n {
52         let f2 = f0 + &f1;
53         f0 = replace(&mut f1, f2);
54     }
55     f0
56 }
57 
58 /// Compute Fibonacci numbers with two ops per iteration
59 /// (add and subtract, like issue #200)
fib2(n: usize) -> BigUint60 fn fib2(n: usize) -> BigUint {
61     let mut f0: BigUint = Zero::zero();
62     let mut f1: BigUint = One::one();
63     for _ in 0..n {
64         f1 += &f0;
65         f0 = &f1 - f0;
66     }
67     f0
68 }
69 
70 #[bench]
multiply_0(b: &mut Bencher)71 fn multiply_0(b: &mut Bencher) {
72     multiply_bench(b, 1 << 8, 1 << 8);
73 }
74 
75 #[bench]
multiply_1(b: &mut Bencher)76 fn multiply_1(b: &mut Bencher) {
77     multiply_bench(b, 1 << 8, 1 << 16);
78 }
79 
80 #[bench]
multiply_2(b: &mut Bencher)81 fn multiply_2(b: &mut Bencher) {
82     multiply_bench(b, 1 << 16, 1 << 16);
83 }
84 
85 #[bench]
multiply_3(b: &mut Bencher)86 fn multiply_3(b: &mut Bencher) {
87     multiply_bench(b, 1 << 16, 1 << 17);
88 }
89 
90 #[bench]
divide_0(b: &mut Bencher)91 fn divide_0(b: &mut Bencher) {
92     divide_bench(b, 1 << 8, 1 << 6);
93 }
94 
95 #[bench]
divide_1(b: &mut Bencher)96 fn divide_1(b: &mut Bencher) {
97     divide_bench(b, 1 << 12, 1 << 8);
98 }
99 
100 #[bench]
divide_2(b: &mut Bencher)101 fn divide_2(b: &mut Bencher) {
102     divide_bench(b, 1 << 16, 1 << 12);
103 }
104 
105 #[bench]
divide_big_little(b: &mut Bencher)106 fn divide_big_little(b: &mut Bencher) {
107     divide_bench(b, 1 << 16, 1 << 4);
108 }
109 
110 #[bench]
remainder_0(b: &mut Bencher)111 fn remainder_0(b: &mut Bencher) {
112     remainder_bench(b, 1 << 8, 1 << 6);
113 }
114 
115 #[bench]
remainder_1(b: &mut Bencher)116 fn remainder_1(b: &mut Bencher) {
117     remainder_bench(b, 1 << 12, 1 << 8);
118 }
119 
120 #[bench]
remainder_2(b: &mut Bencher)121 fn remainder_2(b: &mut Bencher) {
122     remainder_bench(b, 1 << 16, 1 << 12);
123 }
124 
125 #[bench]
remainder_big_little(b: &mut Bencher)126 fn remainder_big_little(b: &mut Bencher) {
127     remainder_bench(b, 1 << 16, 1 << 4);
128 }
129 
130 #[bench]
factorial_100(b: &mut Bencher)131 fn factorial_100(b: &mut Bencher) {
132     b.iter(|| factorial(100));
133 }
134 
135 #[bench]
fib_100(b: &mut Bencher)136 fn fib_100(b: &mut Bencher) {
137     b.iter(|| fib(100));
138 }
139 
140 #[bench]
fib_1000(b: &mut Bencher)141 fn fib_1000(b: &mut Bencher) {
142     b.iter(|| fib(1000));
143 }
144 
145 #[bench]
fib_10000(b: &mut Bencher)146 fn fib_10000(b: &mut Bencher) {
147     b.iter(|| fib(10000));
148 }
149 
150 #[bench]
fib2_100(b: &mut Bencher)151 fn fib2_100(b: &mut Bencher) {
152     b.iter(|| fib2(100));
153 }
154 
155 #[bench]
fib2_1000(b: &mut Bencher)156 fn fib2_1000(b: &mut Bencher) {
157     b.iter(|| fib2(1000));
158 }
159 
160 #[bench]
fib2_10000(b: &mut Bencher)161 fn fib2_10000(b: &mut Bencher) {
162     b.iter(|| fib2(10000));
163 }
164 
165 #[bench]
fac_to_string(b: &mut Bencher)166 fn fac_to_string(b: &mut Bencher) {
167     let fac = factorial(100);
168     b.iter(|| fac.to_string());
169 }
170 
171 #[bench]
fib_to_string(b: &mut Bencher)172 fn fib_to_string(b: &mut Bencher) {
173     let fib = fib(100);
174     b.iter(|| fib.to_string());
175 }
176 
to_str_radix_bench(b: &mut Bencher, radix: u32, bits: u64)177 fn to_str_radix_bench(b: &mut Bencher, radix: u32, bits: u64) {
178     let mut rng = get_rng();
179     let x = rng.gen_bigint(bits);
180     b.iter(|| x.to_str_radix(radix));
181 }
182 
183 #[bench]
to_str_radix_02(b: &mut Bencher)184 fn to_str_radix_02(b: &mut Bencher) {
185     to_str_radix_bench(b, 2, 1009);
186 }
187 
188 #[bench]
to_str_radix_08(b: &mut Bencher)189 fn to_str_radix_08(b: &mut Bencher) {
190     to_str_radix_bench(b, 8, 1009);
191 }
192 
193 #[bench]
to_str_radix_10(b: &mut Bencher)194 fn to_str_radix_10(b: &mut Bencher) {
195     to_str_radix_bench(b, 10, 1009);
196 }
197 
198 #[bench]
to_str_radix_10_2(b: &mut Bencher)199 fn to_str_radix_10_2(b: &mut Bencher) {
200     to_str_radix_bench(b, 10, 10009);
201 }
202 
203 #[bench]
to_str_radix_16(b: &mut Bencher)204 fn to_str_radix_16(b: &mut Bencher) {
205     to_str_radix_bench(b, 16, 1009);
206 }
207 
208 #[bench]
to_str_radix_36(b: &mut Bencher)209 fn to_str_radix_36(b: &mut Bencher) {
210     to_str_radix_bench(b, 36, 1009);
211 }
212 
from_str_radix_bench(b: &mut Bencher, radix: u32)213 fn from_str_radix_bench(b: &mut Bencher, radix: u32) {
214     let mut rng = get_rng();
215     let x = rng.gen_bigint(1009);
216     let s = x.to_str_radix(radix);
217     assert_eq!(x, BigInt::from_str_radix(&s, radix).unwrap());
218     b.iter(|| BigInt::from_str_radix(&s, radix));
219 }
220 
221 #[bench]
from_str_radix_02(b: &mut Bencher)222 fn from_str_radix_02(b: &mut Bencher) {
223     from_str_radix_bench(b, 2);
224 }
225 
226 #[bench]
from_str_radix_08(b: &mut Bencher)227 fn from_str_radix_08(b: &mut Bencher) {
228     from_str_radix_bench(b, 8);
229 }
230 
231 #[bench]
from_str_radix_10(b: &mut Bencher)232 fn from_str_radix_10(b: &mut Bencher) {
233     from_str_radix_bench(b, 10);
234 }
235 
236 #[bench]
from_str_radix_16(b: &mut Bencher)237 fn from_str_radix_16(b: &mut Bencher) {
238     from_str_radix_bench(b, 16);
239 }
240 
241 #[bench]
from_str_radix_36(b: &mut Bencher)242 fn from_str_radix_36(b: &mut Bencher) {
243     from_str_radix_bench(b, 36);
244 }
245 
rand_bench(b: &mut Bencher, bits: u64)246 fn rand_bench(b: &mut Bencher, bits: u64) {
247     let mut rng = get_rng();
248 
249     b.iter(|| rng.gen_bigint(bits));
250 }
251 
252 #[bench]
rand_64(b: &mut Bencher)253 fn rand_64(b: &mut Bencher) {
254     rand_bench(b, 1 << 6);
255 }
256 
257 #[bench]
rand_256(b: &mut Bencher)258 fn rand_256(b: &mut Bencher) {
259     rand_bench(b, 1 << 8);
260 }
261 
262 #[bench]
rand_1009(b: &mut Bencher)263 fn rand_1009(b: &mut Bencher) {
264     rand_bench(b, 1009);
265 }
266 
267 #[bench]
rand_2048(b: &mut Bencher)268 fn rand_2048(b: &mut Bencher) {
269     rand_bench(b, 1 << 11);
270 }
271 
272 #[bench]
rand_4096(b: &mut Bencher)273 fn rand_4096(b: &mut Bencher) {
274     rand_bench(b, 1 << 12);
275 }
276 
277 #[bench]
rand_8192(b: &mut Bencher)278 fn rand_8192(b: &mut Bencher) {
279     rand_bench(b, 1 << 13);
280 }
281 
282 #[bench]
rand_65536(b: &mut Bencher)283 fn rand_65536(b: &mut Bencher) {
284     rand_bench(b, 1 << 16);
285 }
286 
287 #[bench]
rand_131072(b: &mut Bencher)288 fn rand_131072(b: &mut Bencher) {
289     rand_bench(b, 1 << 17);
290 }
291 
292 #[bench]
shl(b: &mut Bencher)293 fn shl(b: &mut Bencher) {
294     let n = BigUint::one() << 1000u32;
295     let mut m = n.clone();
296     b.iter(|| {
297         m.clone_from(&n);
298         for i in 0..50 {
299             m <<= i;
300         }
301     })
302 }
303 
304 #[bench]
shr(b: &mut Bencher)305 fn shr(b: &mut Bencher) {
306     let n = BigUint::one() << 2000u32;
307     let mut m = n.clone();
308     b.iter(|| {
309         m.clone_from(&n);
310         for i in 0..50 {
311             m >>= i;
312         }
313     })
314 }
315 
316 #[bench]
hash(b: &mut Bencher)317 fn hash(b: &mut Bencher) {
318     use std::collections::HashSet;
319     let mut rng = get_rng();
320     let v: Vec<BigInt> = (1000..2000).map(|bits| rng.gen_bigint(bits)).collect();
321     b.iter(|| {
322         let h: HashSet<&BigInt> = v.iter().collect();
323         assert_eq!(h.len(), v.len());
324     });
325 }
326 
327 #[bench]
pow_bench(b: &mut Bencher)328 fn pow_bench(b: &mut Bencher) {
329     b.iter(|| {
330         let upper = 100_u32;
331         let mut i_big = BigUint::from(1u32);
332         for _i in 2..=upper {
333             i_big += 1u32;
334             for j in 2..=upper {
335                 i_big.pow(j);
336             }
337         }
338     });
339 }
340 
341 #[bench]
pow_bench_bigexp(b: &mut Bencher)342 fn pow_bench_bigexp(b: &mut Bencher) {
343     use num_traits::Pow;
344 
345     b.iter(|| {
346         let upper = 100_u32;
347         let mut i_big = BigUint::from(1u32);
348         for _i in 2..=upper {
349             i_big += 1u32;
350             let mut j_big = BigUint::from(1u32);
351             for _j in 2..=upper {
352                 j_big += 1u32;
353                 Pow::pow(&i_big, &j_big);
354             }
355         }
356     });
357 }
358 
359 #[bench]
pow_bench_1e1000(b: &mut Bencher)360 fn pow_bench_1e1000(b: &mut Bencher) {
361     b.iter(|| BigUint::from(10u32).pow(1_000));
362 }
363 
364 #[bench]
pow_bench_1e10000(b: &mut Bencher)365 fn pow_bench_1e10000(b: &mut Bencher) {
366     b.iter(|| BigUint::from(10u32).pow(10_000));
367 }
368 
369 #[bench]
pow_bench_1e100000(b: &mut Bencher)370 fn pow_bench_1e100000(b: &mut Bencher) {
371     b.iter(|| BigUint::from(10u32).pow(100_000));
372 }
373 
374 /// This modulus is the prime from the 2048-bit MODP DH group:
375 /// https://tools.ietf.org/html/rfc3526#section-3
376 const RFC3526_2048BIT_MODP_GROUP: &str = "\
377                                           FFFFFFFF_FFFFFFFF_C90FDAA2_2168C234_C4C6628B_80DC1CD1\
378                                           29024E08_8A67CC74_020BBEA6_3B139B22_514A0879_8E3404DD\
379                                           EF9519B3_CD3A431B_302B0A6D_F25F1437_4FE1356D_6D51C245\
380                                           E485B576_625E7EC6_F44C42E9_A637ED6B_0BFF5CB6_F406B7ED\
381                                           EE386BFB_5A899FA5_AE9F2411_7C4B1FE6_49286651_ECE45B3D\
382                                           C2007CB8_A163BF05_98DA4836_1C55D39A_69163FA8_FD24CF5F\
383                                           83655D23_DCA3AD96_1C62F356_208552BB_9ED52907_7096966D\
384                                           670C354E_4ABC9804_F1746C08_CA18217C_32905E46_2E36CE3B\
385                                           E39E772C_180E8603_9B2783A2_EC07A28F_B5C55DF0_6F4C52C9\
386                                           DE2BCBF6_95581718_3995497C_EA956AE5_15D22618_98FA0510\
387                                           15728E5A_8AACAA68_FFFFFFFF_FFFFFFFF";
388 
389 #[bench]
modpow(b: &mut Bencher)390 fn modpow(b: &mut Bencher) {
391     let mut rng = get_rng();
392     let base = rng.gen_biguint(2048);
393     let e = rng.gen_biguint(2048);
394     let m = BigUint::from_str_radix(RFC3526_2048BIT_MODP_GROUP, 16).unwrap();
395 
396     b.iter(|| base.modpow(&e, &m));
397 }
398 
399 #[bench]
modpow_even(b: &mut Bencher)400 fn modpow_even(b: &mut Bencher) {
401     let mut rng = get_rng();
402     let base = rng.gen_biguint(2048);
403     let e = rng.gen_biguint(2048);
404     // Make the modulus even, so monty (base-2^32) doesn't apply.
405     let m = BigUint::from_str_radix(RFC3526_2048BIT_MODP_GROUP, 16).unwrap() - 1u32;
406 
407     b.iter(|| base.modpow(&e, &m));
408 }
409 
410 #[bench]
to_u32_digits(b: &mut Bencher)411 fn to_u32_digits(b: &mut Bencher) {
412     let mut rng = get_rng();
413     let n = rng.gen_biguint(2048);
414 
415     b.iter(|| n.to_u32_digits());
416 }
417 
418 #[bench]
iter_u32_digits(b: &mut Bencher)419 fn iter_u32_digits(b: &mut Bencher) {
420     let mut rng = get_rng();
421     let n = rng.gen_biguint(2048);
422 
423     b.iter(|| n.iter_u32_digits().max());
424 }
425 
426 #[bench]
to_u64_digits(b: &mut Bencher)427 fn to_u64_digits(b: &mut Bencher) {
428     let mut rng = get_rng();
429     let n = rng.gen_biguint(2048);
430 
431     b.iter(|| n.to_u64_digits());
432 }
433 
434 #[bench]
iter_u64_digits(b: &mut Bencher)435 fn iter_u64_digits(b: &mut Bencher) {
436     let mut rng = get_rng();
437     let n = rng.gen_biguint(2048);
438 
439     b.iter(|| n.iter_u64_digits().max());
440 }
441