1mod approx_rational;
19mod exact;
20mod fixed;
21mod fixed_big;
22mod float64;
23#[cfg(test)]
24mod ratio_i64;
25
26pub use approx_rational::ApproxRational;
27pub use fixed::{FixedDecimal9, Integer64};
28pub use fixed_big::BigFixedDecimal9;
29
30use num::traits::{One, Zero};
31use std::fmt::{Debug, Display};
32use std::iter::{Product, Sum};
33use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
34
35pub trait Integer:
41 Clone
42 + Debug
43 + PartialEq
44 + PartialOrd
45 + Zero
46 + One
47 + Product
48 + Add<Output = Self>
49 + Sub<Output = Self>
50 + Mul<Output = Self>
51where
52 for<'a> &'a Self: IntegerRef<Self>,
53{
54 fn from_usize(i: usize) -> Self;
56
57 #[cfg(test)]
59 fn get_positive_test_values() -> Vec<Self>;
60}
61
62pub trait Rational<I>:
65 Clone
66 + Display
67 + Debug
68 + PartialEq
69 + PartialOrd
70 + Zero
71 + One
72 + AddAssign
73 + SubAssign
74 + MulAssign
75 + Sum
76 + Product
77 + Add<Output = Self>
78 + Sub<Output = Self>
79 + Mul<Output = Self>
80 + Mul<I, Output = Self>
81 + Div<I, Output = Self>
82 + for<'a> AddAssign<&'a Self>
83 + for<'a> SubAssign<&'a Self>
84 + for<'a> MulAssign<&'a Self>
85 + for<'a> DivAssign<&'a I>
86 + for<'a> Sum<&'a Self>
87 + for<'a> Add<&'a Self, Output = Self>
88 + for<'a> Sub<&'a Self, Output = Self>
89 + for<'a> Mul<&'a Self, Output = Self>
90where
91 I: Integer,
92 for<'a> &'a I: IntegerRef<I>,
93 for<'a> &'a Self: RationalRef<&'a I, Self>,
94{
95 fn from_int(i: I) -> Self;
97
98 fn from_usize(i: usize) -> Self {
100 Self::from_int(I::from_usize(i))
101 }
102
103 fn ratio_i(num: I, denom: I) -> Self;
106
107 fn ratio(num: usize, denom: usize) -> Self {
110 Self::ratio_i(I::from_usize(num), I::from_usize(denom))
111 }
112
113 fn to_f64(&self) -> f64;
116
117 #[track_caller]
119 fn assert_eq(a: Self, b: Self, msg: &str) {
120 assert_eq!(a, b, "{msg}");
121 }
122
123 fn epsilon() -> Self;
125
126 fn is_exact() -> bool;
129
130 fn description() -> &'static str;
133
134 fn mul_up(&self, rhs: &Self) -> Self {
137 self * rhs
138 }
139
140 fn div_up_as_keep_factor(&self, rhs: &Self) -> Self;
145
146 #[cfg(test)]
148 fn get_positive_test_values() -> Vec<Self>;
149}
150
151pub trait IntegerRef<Output>:
153 Sized + Add<Self, Output = Output> + Sub<Self, Output = Output> + Mul<Self, Output = Output>
154{
155}
156
157pub trait RationalRef<RefI, Output>:
159 Sized
160 + Add<Self, Output = Output>
161 + Sub<Self, Output = Output>
162 + Mul<Self, Output = Output>
163 + Mul<RefI, Output = Output>
164 + Div<RefI, Output = Output>
165{
166}
167
168#[cfg(test)]
169pub(crate) mod test {
170 use super::*;
171 use ::test::Bencher;
172 use rand::distributions::{Distribution, Uniform};
173 use rand::seq::SliceRandom;
174 use rand::thread_rng;
175 use std::hint::black_box;
176 use std::marker::PhantomData;
177
178 #[macro_export]
180 macro_rules! integer_tests {
181 ( $typei:ty, ) => {};
182 ( $typei:ty, $case:ident, $( $others:tt )* ) => {
183 #[test]
184 fn $case() {
185 $crate::arithmetic::test::IntegerTests::<$typei>::$case();
186 }
187
188 integer_tests!($typei, $($others)*);
189 };
190 ( $typei:ty, $case:ident => fail($msg:expr), $( $others:tt )* ) => {
191 #[test]
192 #[should_panic(expected = $msg)]
193 fn $case() {
194 $crate::arithmetic::test::IntegerTests::<$typei>::$case();
195 }
196
197 integer_tests!($typei, $($others)*);
198 };
199 }
200
201 #[macro_export]
203 macro_rules! big_integer_tests {
204 ( $typei:ty, $num_samples:expr, ) => {};
205 ( $typei:ty, $num_samples:expr, $case:ident, $( $others:tt )* ) => {
206 #[test]
207 fn $case() {
208 $crate::arithmetic::test::IntegerTests::<$typei>::$case($num_samples);
209 }
210
211 big_integer_tests!($typei, $num_samples, $($others)*);
212 };
213 ( $typei:ty, $num_samples:expr, $case:ident => fail($msg:expr), $( $others:tt )* ) => {
214 #[test]
215 #[should_panic(expected = $msg)]
216 fn $case() {
217 $crate::arithmetic::test::IntegerTests::<$typei>::$case($num_samples);
218 }
219
220 big_integer_tests!($typei, $num_samples, $($others)*);
221 };
222 }
223
224 #[macro_export]
227 macro_rules! numeric_tests {
228 ( $typei:ty, $typer:ty, ) => {};
229 ( $typei:ty, $typer:ty, $case:ident, $( $others:tt )* ) => {
230 #[test]
231 fn $case() {
232 $crate::arithmetic::test::NumericTests::<$typei, $typer>::$case();
233 }
234
235 numeric_tests!($typei, $typer, $($others)*);
236 };
237 ( $typei:ty, $typer:ty, $case:ident => fail($msg:expr), $( $others:tt )* ) => {
238 #[test]
239 #[should_panic(expected = $msg)]
240 fn $case() {
241 $crate::arithmetic::test::NumericTests::<$typei, $typer>::$case();
242 }
243
244 numeric_tests!($typei, $typer, $($others)*);
245 };
246 }
247
248 #[macro_export]
251 macro_rules! big_numeric_tests {
252 ( $typei:ty, $typer:ty, $num_samples:expr, ) => {};
253 ( $typei:ty, $typer:ty, $num_samples:expr, $case:ident, $( $others:tt )* ) => {
254 #[test]
255 fn $case() {
256 $crate::arithmetic::test::NumericTests::<$typei, $typer>::$case($num_samples);
257 }
258
259 big_numeric_tests!($typei, $typer, $num_samples, $($others)*);
260 };
261 ( $typei:ty, $typer:ty, $num_samples:expr, $case:ident => fail($msg:expr), $( $others:tt )* ) => {
262 #[test]
263 #[should_panic(expected = $msg)]
264 fn $case() {
265 $crate::arithmetic::test::NumericTests::<$typei, $typer>::$case($num_samples);
266 }
267
268 big_numeric_tests!($typei, $typer, $num_samples, $($others)*);
269 };
270 }
271
272 #[macro_export]
275 macro_rules! numeric_benchmarks {
276 ( $typei:ty, $typer:ty, ) => {};
277 ( $typei:ty, $typer:ty, $case:ident, $( $others:tt )* ) => {
278 #[bench]
279 fn $case(b: &mut ::test::Bencher) {
280 $crate::arithmetic::test::NumericTests::<$typei, $typer>::$case(b);
281 }
282
283 numeric_benchmarks!($typei, $typer, $($others)*);
284 };
285 }
286
287 pub struct IntegerTests<I> {
288 _phantomi: PhantomData<I>,
289 }
290
291 impl<I> IntegerTests<I>
292 where
293 I: Integer + Display,
294 for<'a> &'a I: IntegerRef<I>,
295 {
296 pub fn testi_values_are_positive() {
297 let test_values = I::get_positive_test_values();
298 Self::loopi_check1(&test_values, |a| {
299 assert!(*a > I::zero(), "{a} is not positive");
300 });
301 }
302
303 pub fn testi_is_zero() {
304 let test_values = I::get_positive_test_values();
305 assert!(I::zero().is_zero());
306 assert!(!I::one().is_zero());
307 Self::loopi_check1(&test_values, |a| {
308 assert!(!a.is_zero(), "{a} is zero");
309 });
310 }
311
312 pub fn testi_zero_is_add_neutral() {
313 let test_values = I::get_positive_test_values();
314 Self::loopi_check1(&test_values, |a| {
315 assert_eq!(a + &I::zero(), *a, "a + 0 != a for {a}");
316 assert_eq!(&I::zero() + a, *a, "0 + a != a for {a}");
317 assert_eq!(a - &I::zero(), *a, "a - 0 != a for {a}");
318 })
319 }
320
321 #[allow(clippy::eq_op)]
322 pub fn testi_add_is_commutative() {
323 let test_values = I::get_positive_test_values();
324 Self::loopi_check2(&test_values, |a, b| {
325 assert_eq!(a + b, b + a, "a + b != b + a for {a}, {b}");
326 })
327 }
328
329 pub fn testi_add_is_associative(num_samples: Option<usize>) {
330 let test_values = I::get_positive_test_values();
331 Self::loopi_check3(&test_values, num_samples, |a, b, c| {
332 assert_eq!(
333 &(a + b) + c,
334 a + &(b + c),
335 "(a + b) + c != a + (b + c) for {a}, {b}, {c}"
336 );
337 })
338 }
339
340 pub fn testi_opposite() {
341 let test_values = I::get_positive_test_values();
342 Self::loopi_check1(&test_values, |a| {
343 assert_eq!(
344 I::zero() - (I::zero() - a.clone()),
345 *a,
346 "-(-a) != a for {a}"
347 );
348 });
349 }
350
351 #[allow(clippy::eq_op)]
352 pub fn testi_sub_self() {
353 let test_values = I::get_positive_test_values();
354 Self::loopi_check1(&test_values, |a| {
355 assert_eq!(a - a, I::zero(), "a - a != 0 for {a}");
356 });
357 }
358
359 pub fn testi_add_sub() {
360 let test_values = I::get_positive_test_values();
361 Self::loopi_check2(&test_values, |a, b| {
362 assert_eq!(&(a + b) - b, *a, "(a + b) - b != a for {a}, {b}");
363 });
364 }
365
366 pub fn testi_sub_add() {
367 let test_values = I::get_positive_test_values();
368 Self::loopi_check2(&test_values, |a, b| {
369 assert_eq!(&(a - b) + b, *a, "(a - b) + b != a for {a}, {b}");
370 });
371 }
372
373 pub fn testi_one_is_mul_neutral() {
374 let test_values = I::get_positive_test_values();
375 Self::loopi_check1(&test_values, |a| {
376 assert_eq!(a * &I::one(), *a, "a * 1 != a for {a}");
377 assert_eq!(&I::one() * a, *a, "1 * a != a for {a}");
378 })
379 }
380
381 pub fn testi_mul_is_commutative() {
382 let test_values = I::get_positive_test_values();
383 Self::loopi_check2(&test_values, |a, b| {
384 assert_eq!(a * b, b * a, "a * b != b * a for {a}, {b}");
385 })
386 }
387
388 pub fn testi_mul_is_associative(num_samples: Option<usize>) {
389 let test_values = I::get_positive_test_values();
390 Self::loopi_check3(&test_values, num_samples, |a, b, c| {
391 assert_eq!(
392 &(a * b) * c,
393 a * &(b * c),
394 "(a * b) * c != a * (b * c) for {a}, {b}, {c}"
395 );
396 })
397 }
398
399 pub fn testi_mul_is_distributive(num_samples: Option<usize>) {
400 let test_values = I::get_positive_test_values();
401 Self::loopi_check3(&test_values, num_samples, |a, b, c| {
402 assert_eq!(
403 a * &(b + c),
404 &(a * b) + &(a * c),
405 "a * (b + c) != (a * b) + (a * c) for {a}, {b}, {c}"
406 );
407 })
408 }
409
410 pub fn testi_product(num_samples: Option<usize>) {
411 let test_values = I::get_positive_test_values();
412 Self::loopi_check3(&test_values, num_samples, |a, b, c| {
413 assert_eq!(
414 [a.clone(), b.clone(), c.clone()].into_iter().product::<I>(),
415 &(a * b) * c,
416 "[a, b, c].product() != a * b * c for {a}, {b}, {c}"
417 );
418 });
419 }
420
421 fn loopi_check1(test_values: &[I], f: impl Fn(&I)) {
422 for a in test_values {
423 f(a);
424 }
425 }
426
427 fn loopi_check2(test_values: &[I], f: impl Fn(&I, &I)) {
428 for a in test_values {
429 for b in test_values {
430 f(a, b);
431 }
432 }
433 }
434
435 fn loopi_check3(test_values: &[I], num_samples: Option<usize>, f: impl Fn(&I, &I, &I)) {
436 match num_samples {
437 None => {
438 for a in test_values {
440 for b in test_values {
441 for c in test_values {
442 f(a, b, c);
443 }
444 }
445 }
446 }
447 Some(n) => {
448 let mut rng = thread_rng();
451
452 for _ in 0..n {
453 let a = test_values.choose(&mut rng).unwrap();
454 let b = test_values.choose(&mut rng).unwrap();
455 let c = test_values.choose(&mut rng).unwrap();
456 f(a, b, c);
457 }
458 }
459 }
460 }
461 }
462
463 pub struct NumericTests<I, R> {
464 _phantomi: PhantomData<I>,
465 _phantomr: PhantomData<R>,
466 }
467
468 impl<I, R> NumericTests<I, R>
469 where
470 I: Integer + Display,
471 for<'a> &'a I: IntegerRef<I>,
472 R: Rational<I>,
473 for<'a> &'a R: RationalRef<&'a I, R>,
474 {
475 pub fn test_values_are_positive() {
476 let test_values = R::get_positive_test_values();
477 Self::loop_check1(&test_values, |a| {
478 assert!(*a > R::zero(), "{a} is not positive");
479 });
480 }
481
482 pub fn test_is_exact() {
483 assert!(
484 R::is_exact() == R::epsilon().is_zero(),
485 "epsilon is {} but is_exact() returns {}",
486 R::epsilon(),
487 R::is_exact()
488 );
489 }
490
491 pub fn test_ratio() {
492 Self::loop_check_i1(|a| {
493 assert_eq!(
494 R::ratio_i(a.clone(), I::from_usize(1)),
495 R::from_int(a.clone()),
496 "R::ratio(a, 1) != a for {a}"
497 );
498 });
499 }
500
501 pub fn test_ratio_invert() {
502 Self::loop_check_i1(|a| {
503 if !a.is_zero() {
504 assert_eq!(
505 R::ratio_i(I::from_usize(1), a.clone()) * R::from_int(a.clone()),
506 R::one(),
507 "R::ratio(1, a) * a != 1 for {a}"
508 );
509 }
510 });
511 }
512
513 pub fn test_is_zero() {
514 let test_values = R::get_positive_test_values();
515 assert!(R::zero().is_zero());
516 assert!(!R::one().is_zero());
517 Self::loop_check1(&test_values, |a| {
518 assert!(!a.is_zero(), "{a} is zero");
519 });
520 }
521
522 pub fn test_zero_is_add_neutral() {
523 let test_values = R::get_positive_test_values();
524 Self::loop_check1(&test_values, |a| {
525 assert_eq!(a + &R::zero(), *a, "a + 0 != a for {a}");
526 assert_eq!(&R::zero() + a, *a, "0 + a != a for {a}");
527 assert_eq!(a - &R::zero(), *a, "a - 0 != a for {a}");
528 })
529 }
530
531 #[allow(clippy::eq_op)]
532 pub fn test_add_is_commutative() {
533 let test_values = R::get_positive_test_values();
534 Self::loop_check2(&test_values, |a, b| {
535 assert_eq!(a + b, b + a, "a + b != b + a for {a}, {b}");
536 })
537 }
538
539 pub fn test_add_is_associative(num_samples: Option<usize>) {
540 let test_values = R::get_positive_test_values();
541 Self::loop_check3(&test_values, num_samples, |a, b, c| {
542 assert_eq!(
543 &(a + b) + c,
544 a + &(b + c),
545 "(a + b) + c != a + (b + c) for {a}, {b}, {c}"
546 );
547 })
548 }
549
550 pub fn test_opposite() {
551 let test_values = R::get_positive_test_values();
552 Self::loop_check1(&test_values, |a| {
553 assert_eq!(R::zero() - (R::zero() - a), *a, "-(-a) != a for {a}");
554 });
555 }
556
557 #[allow(clippy::eq_op)]
558 pub fn test_sub_self() {
559 let test_values = R::get_positive_test_values();
560 Self::loop_check1(&test_values, |a| {
561 assert_eq!(a - a, R::zero(), "a - a != 0 for {a}");
562 });
563 }
564
565 pub fn test_add_sub() {
566 let test_values = R::get_positive_test_values();
567 Self::loop_check2(&test_values, |a, b| {
568 assert_eq!(&(a + b) - b, *a, "(a + b) - b != a for {a}, {b}");
569 });
570 }
571
572 pub fn test_sub_add() {
573 let test_values = R::get_positive_test_values();
574 Self::loop_check2(&test_values, |a, b| {
575 assert_eq!(&(a - b) + b, *a, "(a - b) + b != a for {a}, {b}");
576 });
577 }
578
579 pub fn test_one_is_mul_neutral() {
580 let test_values = R::get_positive_test_values();
581 Self::loop_check1(&test_values, |a| {
582 assert_eq!(a * &R::one(), *a, "a * 1 != a for {a}");
583 assert_eq!(&R::one() * a, *a, "1 * a != a for {a}");
584 })
585 }
586
587 pub fn test_mul_is_commutative() {
588 let test_values = R::get_positive_test_values();
589 Self::loop_check2(&test_values, |a, b| {
590 assert_eq!(a * b, b * a, "a * b != b * a for {a}, {b}");
591 })
592 }
593
594 pub fn test_mul_is_associative(num_samples: Option<usize>) {
595 let test_values = R::get_positive_test_values();
596 Self::loop_check3(&test_values, num_samples, |a, b, c| {
597 assert_eq!(
598 &(a * b) * c,
599 a * &(b * c),
600 "(a * b) * c != a * (b * c) for {a}, {b}, {c}"
601 );
602 })
603 }
604
605 pub fn test_mul_is_distributive(num_samples: Option<usize>) {
606 let test_values = R::get_positive_test_values();
607 Self::loop_check3(&test_values, num_samples, |a, b, c| {
608 assert_eq!(
609 a * &(b + c),
610 &(a * b) + &(a * c),
611 "a * (b + c) != (a * b) + (a * c) for {a}, {b}, {c}"
612 );
613 })
614 }
615
616 pub fn test_mul_up_is_commutative() {
617 let test_values = R::get_positive_test_values();
618 Self::loop_check2(&test_values, |a, b| {
619 assert_eq!(
620 R::mul_up(a, b),
621 R::mul_up(b, a),
622 "mul_up(a, b) != mul_up(b, a) for {a}, {b}"
623 );
624 })
625 }
626
627 pub fn test_mul_up_integers() {
628 Self::loop_check_i2(|a, b| {
629 assert_eq!(
630 R::mul_up(&R::from_int(a.clone()), &R::from_int(b.clone())),
631 R::from_int(a.clone() * b.clone()),
632 "mul_up(a, b) != a * b for {a}, {b}"
633 );
634 })
635 }
636
637 pub fn test_mul_up_wrt_mul() {
638 let test_values = R::get_positive_test_values();
639 Self::loop_check2(&test_values, |a, b| {
640 let mul = a * b;
641 let mul_up = R::mul_up(a, b);
642 assert!(mul_up >= mul, "mul_up(a, b) < a * b for {a}, {b}");
643 assert!(
644 mul_up <= mul + R::epsilon(),
645 "mul_up(a, b) > a * b + epsilon for {a}, {b}"
646 );
647 })
648 }
649
650 pub fn test_one_is_div_up_neutral() {
651 let test_values = R::get_positive_test_values();
652 Self::loop_check1(&test_values, |a| {
653 assert_eq!(
654 R::div_up_as_keep_factor(a, &R::one()),
655 *a,
656 "div_up(a, 1) != a for {a}"
657 );
658 })
659 }
660
661 pub fn test_div_up_self() {
662 let test_values = R::get_positive_test_values();
663 Self::loop_check1(&test_values, |a| {
664 assert_eq!(
665 R::div_up_as_keep_factor(a, a),
666 R::one(),
667 "div_up(a, a) != 1 for {a}"
668 );
669 });
670 }
671
672 pub fn test_mul_div_up() {
673 let test_values = R::get_positive_test_values();
674 Self::loop_check2(&test_values, |a, b| {
675 assert_eq!(
676 R::div_up_as_keep_factor(&(a * b), b),
677 *a,
678 "div_up(a * b, b) != a for {a}, {b}"
679 );
680 });
681 }
682
683 pub fn test_mul_by_int() {
684 let test_values = R::get_positive_test_values();
685 Self::loop_check1_i1(&test_values, |a, b| {
686 assert_eq!(
687 a * &b,
688 a * &R::from_int(b.clone()),
689 "a * int(b) != a * b for {a}, {b}"
690 );
691 })
692 }
693
694 pub fn test_mul_div_by_int() {
695 let test_values = R::get_positive_test_values();
696 Self::loop_check1_i1(&test_values, |a, b| {
697 if !b.is_zero() {
698 assert_eq!(&(a * &b) / &b, *a, "a * int(b) / int(b) != a for {a}, {b}");
699 }
700 })
701 }
702
703 pub fn test_mul_by_int_is_associative(num_samples: Option<usize>) {
704 let test_values = R::get_positive_test_values();
705 Self::loop_check1_i2(&test_values, num_samples, |a, b, c| {
706 assert_eq!(
707 &(a * &b) * &c,
708 a * &(b.clone() * c.clone()),
709 "(a * b) * c != a * (b * c) for {a}, {b}, {c}"
710 );
711 })
712 }
713
714 pub fn test_mul_by_int_is_distributive(num_samples: Option<usize>) {
715 let test_values = R::get_positive_test_values();
716 Self::loop_check2_i1(&test_values, num_samples, |a: &R, b: &R, c: I| {
717 assert_eq!(
718 &(a + b) * &c,
719 &(a * &c) + &(b * &c),
720 "(a + b) * c != (a * c) + (b * c) for {a}, {b}, {c}"
721 );
722 })
723 }
724
725 pub fn test_div_by_int_is_associative(num_samples: Option<usize>) {
726 let test_values = R::get_positive_test_values();
727 Self::loop_check1_i2(&test_values, num_samples, |a, b, c| {
728 if !b.is_zero() && !c.is_zero() {
729 assert_eq!(
730 &(a / &b) / &c,
731 a / &(b.clone() * c.clone()),
732 "(a / b) / c != a / (b * c) for {a}, {b}, {c}"
733 );
734 }
735 })
736 }
737
738 pub fn test_div_by_int_is_distributive(num_samples: Option<usize>) {
739 let test_values = R::get_positive_test_values();
740 Self::loop_check2_i1(&test_values, num_samples, |a: &R, b: &R, c: I| {
741 if !c.is_zero() {
742 assert_eq!(
743 &(a + b) / &c,
744 &(a / &c) + &(b / &c),
745 "(a + b) / c != (a / c) + (b / c) for {a}, {b}, {c}"
746 );
747 }
748 })
749 }
750
751 pub fn test_references() {
752 let test_values = R::get_positive_test_values();
753
754 Self::loop_check2(&test_values, |a, b| {
755 assert_eq!(
756 a + b,
757 a.clone() + b.clone(),
758 "&a + &b != a + b for {a}, {b}"
759 );
760 assert_eq!(
761 a - b,
762 a.clone() - b.clone(),
763 "&a - &b != a - b for {a}, {b}"
764 );
765 assert_eq!(
766 a * b,
767 a.clone() * b.clone(),
768 "&a * &b != a * b for {a}, {b}"
769 );
770 assert_eq!(a + b, a.clone() + b, "&a + &b != a + &b for {a}, {b}");
771 assert_eq!(a - b, a.clone() - b, "&a - &b != a - &b for {a}, {b}");
772 assert_eq!(a * b, a.clone() * b, "&a * &b != a * &b for {a}, {b}");
773 });
774
775 Self::loop_check1_i1(&test_values, |a, b| {
776 if !b.is_zero() {
777 assert_eq!(
778 a * &b,
779 a.clone() * b.clone(),
780 "&a * &b != a * b for {a}, {b}"
781 );
782 assert_eq!(
783 a / &b,
784 a.clone() / b.clone(),
785 "&a / &b != a / b for {a}, {b}"
786 );
787 }
788 });
789 }
790
791 pub fn test_assign() {
792 let test_values = R::get_positive_test_values();
793
794 Self::loop_check2(&test_values, |a, b| {
795 let mut c = a.clone();
796 c += b.clone();
797 assert_eq!(c, a + b, "a += b != a + b for {a}, {b}");
798 let mut c = a.clone();
799 c -= b.clone();
800 assert_eq!(c, a - b, "a -= b != a - b for {a}, {b}");
801 let mut c = a.clone();
802 c *= b.clone();
803 assert_eq!(c, a * b, "a *= b != a * b for {a}, {b}");
804
805 let mut c = a.clone();
806 c += b;
807 assert_eq!(c, a + b, "a += &b != a + b for {a}, {b}");
808 let mut c = a.clone();
809 c -= b;
810 assert_eq!(c, a - b, "a -= &b != a - b for {a}, {b}");
811 let mut c = a.clone();
812 c *= b;
813 assert_eq!(c, a * b, "a *= &b != a * b for {a}, {b}");
814 });
815
816 Self::loop_check1_i1(&test_values, |a, b| {
817 if !b.is_zero() {
818 let mut c = a.clone();
819 c /= &b;
820 assert_eq!(c, a / &b, "a /= &b != a / &b for {a}, {b}");
821 }
822 });
823 }
824
825 pub fn test_sum(num_samples: Option<usize>) {
826 let test_values = R::get_positive_test_values();
827 Self::loop_check3(&test_values, num_samples, |a, b, c| {
828 assert_eq!(
829 [a.clone(), b.clone(), c.clone()].into_iter().sum::<R>(),
830 &(a + b) + c,
831 "[a, b, c].sum() != a + b + c for {a}, {b}, {c}"
832 );
833 assert_eq!(
834 [a, b, c].into_iter().sum::<R>(),
835 &(a + b) + c,
836 "[&a, &b, &c].sum() != a + b + c for {a}, {b}, {c}"
837 );
838 });
839 }
840
841 pub fn test_product(num_samples: Option<usize>) {
842 let test_values = R::get_positive_test_values();
843 Self::loop_check3(&test_values, num_samples, |a, b, c| {
844 assert_eq!(
845 [a.clone(), b.clone(), c.clone()].into_iter().product::<R>(),
846 &(a * b) * c,
847 "[a, b, c].product() != a * b * c for {a}, {b}, {c}"
848 );
849 });
850 }
851
852 pub fn bench_add(bencher: &mut Bencher) {
853 let a = R::zero();
854 let b = R::one();
855 bencher.iter(|| black_box(&a) + black_box(&b));
856 }
857
858 pub fn bench_sub(bencher: &mut Bencher) {
859 let a = R::zero();
860 let b = R::one();
861 bencher.iter(|| black_box(&a) - black_box(&b));
862 }
863
864 pub fn bench_mul(bencher: &mut Bencher) {
865 let a = R::zero();
866 let b = R::one();
867 bencher.iter(|| black_box(&a) * black_box(&b));
868 }
869
870 pub fn bench_div_up(bencher: &mut Bencher) {
871 let a = R::zero();
872 let b = R::one();
873 bencher.iter(|| R::div_up_as_keep_factor(black_box(&a), black_box(&b)));
874 }
875
876 fn loop_check1(test_values: &[R], f: impl Fn(&R)) {
877 for a in test_values {
878 f(a);
879 }
880 }
881
882 fn loop_check_i1(f: impl Fn(I)) {
883 for aa in 0..100 {
884 let a = I::from_usize(aa);
885 f(a);
886 }
887 }
888
889 fn loop_check2(test_values: &[R], f: impl Fn(&R, &R)) {
890 for a in test_values {
891 for b in test_values {
892 f(a, b);
893 }
894 }
895 }
896
897 fn loop_check1_i1(test_values: &[R], f: impl Fn(&R, I)) {
898 for a in test_values {
899 for bb in 0..100 {
900 let b = I::from_usize(bb);
901 f(a, b);
902 }
903 }
904 }
905
906 fn loop_check_i2(f: impl Fn(I, I)) {
907 for aa in 0..100 {
908 for bb in 0..100 {
909 let a = I::from_usize(aa);
910 let b = I::from_usize(bb);
911 f(a, b);
912 }
913 }
914 }
915
916 fn loop_check3(test_values: &[R], num_samples: Option<usize>, f: impl Fn(&R, &R, &R)) {
917 match num_samples {
918 None => {
919 for a in test_values {
921 for b in test_values {
922 for c in test_values {
923 f(a, b, c);
924 }
925 }
926 }
927 }
928 Some(n) => {
929 let mut rng = thread_rng();
932
933 for _ in 0..n {
934 let a = test_values.choose(&mut rng).unwrap();
935 let b = test_values.choose(&mut rng).unwrap();
936 let c = test_values.choose(&mut rng).unwrap();
937 f(a, b, c);
938 }
939 }
940 }
941 }
942
943 fn loop_check2_i1(test_values: &[R], num_samples: Option<usize>, f: impl Fn(&R, &R, I)) {
944 match num_samples {
945 None => {
946 for a in test_values {
948 for b in test_values {
949 for cc in 0..100 {
950 let c = I::from_usize(cc);
951 f(a, b, c);
952 }
953 }
954 }
955 }
956 Some(n) => {
957 let integer_distribution = Uniform::from(0..100);
960 let mut rng = thread_rng();
961
962 for _ in 0..n {
963 let a = test_values.choose(&mut rng).unwrap();
964 let b = test_values.choose(&mut rng).unwrap();
965 let c = I::from_usize(integer_distribution.sample(&mut rng));
966 f(a, b, c);
967 }
968 }
969 }
970 }
971
972 fn loop_check1_i2(test_values: &[R], num_samples: Option<usize>, f: impl Fn(&R, I, I)) {
973 match num_samples {
974 None => {
975 for a in test_values {
977 for bb in 0..100 {
978 for cc in 0..100 {
979 let b = I::from_usize(bb);
980 let c = I::from_usize(cc);
981 f(a, b, c);
982 }
983 }
984 }
985 }
986 Some(n) => {
987 let integer_distribution = Uniform::from(0..100);
990 let mut rng = thread_rng();
991
992 for _ in 0..n {
993 let a = test_values.choose(&mut rng).unwrap();
994 let b = I::from_usize(integer_distribution.sample(&mut rng));
995 let c = I::from_usize(integer_distribution.sample(&mut rng));
996 f(a, b, c);
997 }
998 }
999 }
1000 }
1001 }
1002}