parallel_factorial/
lib.rs

1use ibig::{UBig, ubig};
2use rayon::prelude::*;
3
4/// Calculate a factorial number from an integer.
5pub 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}