parallel_factorial/
lib.rs1use ibig::{UBig, ubig};
2use rayon::prelude::*;
3
4pub fn factorial(n: u64) -> String {
6 let offset = n as usize / rayon::current_num_threads();
7 let vec = (1..=n).collect::<Vec<_>>();
8
9 if n < rayon::current_num_threads() as u64 {
10 return single_threaded_factorial(n);
11 }
12
13 let mut result: Vec<UBig> = vec
14 .chunks(offset)
15 .par_bridge()
16 .into_par_iter()
17 .map(|range| {
18 let mut acc = ubig!(1);
19 for &number in range {
20 acc *= number;
21 }
22 acc
23 })
24 .collect::<Vec<UBig>>();
25
26 let mut acc = result.pop().unwrap();
27
28 for number in result {
29 acc *= number;
30 }
31
32 acc.to_string()
33}
34
35fn single_threaded_factorial(n: u64) -> String {
36 let mut acc = UBig::from(n);
37 for index in 1..n {
38 acc *= index;
39 }
40 acc.to_string()
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46
47 #[test]
48 fn factorial_should_be_correct_for_small_integer() {
49 let result = single_threaded_factorial(3);
50 assert_eq!(String::from("6"), result);
51 }
52
53 #[test]
54 fn factorial_should_be_correct_for_large_integer() {
55 let expected = "89461821307829752868514417153983165206980821677\
56 9571907213868063227837990693501860533361810841010176000000000000000000";
57 let actual = single_threaded_factorial(79);
58 assert_eq!(expected, &actual);
59 }
60
61 #[test]
62 fn parallel_factorial_should_be_correct_for_small_integer() {
63 let actual = factorial(3);
64 assert_eq!("6", &actual);
65 }
66
67 #[test]
68 fn parallel_factorial_should_be_correct_for_large_integer() {
69 let expected = "89461821307829752868514417153983165206980821677\
70 9571907213868063227837990693501860533361810841010176000000000000000000";
71 let actual = factorial(79);
72 assert_eq!(expected, &actual);
73 }
74}