Skip to main content

malachite_float/float/arithmetic/
factorial.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MPFR Library.
4//
5//      Copyright © 1999-2025 Free Software Foundation, Inc.
6//
7// This file is part of Malachite.
8//
9// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
10// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
11// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
12
13use crate::Float;
14use core::cmp::Ordering::{self, Equal, Greater, Less};
15use malachite_base::num::arithmetic::traits::{
16    CeilingLogBase2, Factorial, FloorLogBase2, ShlRound,
17};
18use malachite_base::num::basic::traits::Infinity;
19use malachite_base::num::conversion::traits::ExactFrom;
20use malachite_base::rounding_modes::RoundingMode::{self, Down, Exact, Floor, Nearest, Up};
21use malachite_nz::natural::Natural;
22
23impl Float {
24    /// This is mpfr_fac_ui from factorial.c, MPFR 4.2.2, with the result's precision passed
25    /// explicitly. The factorial is accumulated at a working precision a little above the target,
26    /// with a directed rounding, and a Ziv loop retries at higher precision until the approximation
27    /// rounds unambiguously. Where MPFR runs the loop under an extended exponent range and resolves
28    /// overflow in a final mpfr_check_range, here the working value is kept scaled to a small
29    /// exponent with the accumulated power of 2 tracked separately, and the final exact shift
30    /// resolves overflow instead. The scale also gives an exact running lower bound on the result's
31    /// exponent, so a factorial too large for any `Float` is detected mid-loop without unbounded
32    /// growth.
33    ///
34    /// Computes the factorial of a `u64`, rounding the result to the specified precision and with
35    /// the specified rounding mode. An [`Ordering`] is also returned, indicating whether the
36    /// rounded factorial is less than, equal to, or greater than the exact factorial.
37    ///
38    /// The result is identical to `Float::from_natural_prec_round(Natural::factorial(n), prec,
39    /// rm)`, but the computation works at a precision a little above `prec` throughout, which is
40    /// far cheaper than computing every bit of the exact factorial when `n` is large and `prec` is
41    /// small. A factorial too large for the exponent range yields the usual overflow values:
42    /// infinity under `Nearest`, `Up`, and `Ceiling`, and the largest representable value under
43    /// `Down` and `Floor`.
44    ///
45    /// $$
46    /// f(n,p) = n!+\varepsilon.
47    /// $$
48    /// - If $n!$ is representable with $p$ bits, $\varepsilon$ is 0.
49    /// - Otherwise, $|\varepsilon| < 2^{\lfloor\log_2 n!\rfloor-p+1}$.
50    ///
51    /// If the output has a precision, it is `prec`.
52    ///
53    /// # Worst-case complexity
54    /// $T(n, p) = O(n (p + \log n) \log (p + \log n) \log\log (p + \log n))$
55    ///
56    /// $M(p) = O(p + \log n)$
57    ///
58    /// where $T$ is time, $M$ is additional memory, $n$ is `n`, and $p$ is `prec`.
59    ///
60    /// # Panics
61    /// Panics if `prec` is zero, or if `rm` is `Exact` and the factorial is not exactly
62    /// representable with `prec` bits.
63    ///
64    /// # Examples
65    /// ```
66    /// use core::cmp::Ordering::*;
67    /// use malachite_base::rounding_modes::RoundingMode::*;
68    /// use malachite_float::Float;
69    ///
70    /// let (f, o) = Float::factorial_prec_round(5, 4, Floor);
71    /// assert_eq!(f.to_string(), "120.0");
72    /// assert_eq!(o, Equal);
73    ///
74    /// let (f, o) = Float::factorial_prec_round(100, 10, Floor);
75    /// assert_eq!(f.to_string(), "9.3318e157");
76    /// assert_eq!(o, Less);
77    ///
78    /// let (f, o) = Float::factorial_prec_round(100, 10, Ceiling);
79    /// assert_eq!(f.to_string(), "9.3426e157");
80    /// assert_eq!(o, Greater);
81    /// ```
82    pub fn factorial_prec_round(n: u64, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
83        assert_ne!(prec, 0);
84        // 0! = 1! = 1
85        if n <= 1 {
86            return (Self::one_prec(prec), Equal);
87        }
88        if rm == Exact {
89            // with an inexact working value the loop cannot certify exactness, and Exact needs the
90            // full value anyway
91            return Self::from_natural_prec_round(Natural::factorial(n), prec, Exact);
92        }
93        // A cheap exact lower bound on log2(n!): the upper half of the factors alone is at least
94        // (n/2)^(n/2), so log2(n!) >= (n/2)*floor(log2(n/2)). When even this bound exceeds the
95        // exponent range, the factorial overflows with no computation at all; the in-loop exponent
96        // bound below catches the remaining overflow window.
97        let half = n >> 1;
98        if u128::from(half) * u128::from(half.floor_log_base_2())
99            > const { (Self::MAX_EXPONENT_I64 + 1) as u128 }
100        {
101            return match rm {
102                Floor | Down => (Self::max_finite_value_with_prec(prec), Less),
103                _ => (Self::INFINITY, Greater),
104            };
105        }
106        let mut wprec = prec + (n.ceiling_log_base_2() << 1) + 7;
107        // the working directed rounding; restarted with the symmetric direction if the two rounding
108        // stages disagree in sign
109        let mut rnd = Down;
110        loop {
111            // the value accumulated so far is t*2^k, with t's exponent held at 0
112            let mut t = Self::one_prec(wprec);
113            let mut k = 0i64;
114            let mut o1 = Equal;
115            let mut overflow = false;
116            for i in 2..=n {
117                let (t2, o) = t.mul_prec_round(Self::from(i), wprec, rnd);
118                t = t2;
119                // assume the first inexact product gives the sign of the difference
120                if o1 == Equal {
121                    o1 = o;
122                }
123                let e = i64::from(t.get_exponent().unwrap());
124                if e != 0 {
125                    k += e;
126                    t >>= e;
127                }
128                // the remaining factors only increase the value, so k + 1 is a lower bound on the
129                // result's exponent; once it exceeds the representable range the result is a
130                // definite overflow
131                if k > const { Self::MAX_EXPONENT_I64 + 1 } {
132                    overflow = true;
133                    break;
134                }
135            }
136            if overflow {
137                // as in mpfr_overflow: toward-zero modes give the largest finite value, and the
138                // other modes give infinity
139                return match rm {
140                    Floor | Down => (Self::max_finite_value_with_prec(prec), Less),
141                    _ => (Self::INFINITY, Greater),
142                };
143            }
144            // t is exact, or within one ulp of its (err)th bit in the direction of rnd; this is
145            // MPFR_CAN_ROUND's round_p test, whose first rounding mode is Nearest
146            let err = i64::exact_from(wprec - 1 - wprec.ceiling_log_base_2());
147            if o1 == Equal || t.can_round(err, Nearest, rm, prec) {
148                let (y, o2) = Self::from_float_prec_round(t, prec, rm);
149                let o = if o1 == Equal {
150                    // t is exactly n!/2^k, so the second rounding's comparison is the answer
151                    o2
152                } else if o2 == Equal || o2 == o1 {
153                    // y is on the same side of n!/2^k as t
154                    o1
155                } else {
156                    // the two stages have opposite signs, so y's relation to n!/2^k is unknown:
157                    // restart with the symmetric working rounding
158                    rnd = if rnd == Down { Up } else { Down };
159                    wprec += wprec >> 1;
160                    continue;
161                };
162                // scale back; the exact shift saturates per rm at the exponent limit, standing in
163                // for mpfr_check_range
164                let (result, o_shift) = y.shl_round(k, rm);
165                return if o_shift == Equal {
166                    (result, o)
167                } else {
168                    (result, o_shift)
169                };
170            }
171            wprec += wprec >> 1;
172        }
173    }
174
175    #[inline]
176    /// Computes the factorial of a `u64`, rounding the result to the nearest value of the specified
177    /// precision. An [`Ordering`] is also returned, indicating whether the rounded factorial is
178    /// less than, equal to, or greater than the exact factorial.
179    ///
180    /// If the factorial is equidistant from two [`Float`]s with the specified precision, the
181    /// [`Float`] with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a
182    /// description of the `Nearest` rounding mode.
183    ///
184    /// $$
185    /// f(n,p) = n!+\varepsilon.
186    /// $$
187    /// - If $n!$ is representable with $p$ bits, $\varepsilon$ is 0.
188    /// - Otherwise, $|\varepsilon| < 2^{\lfloor\log_2 n!\rfloor-p}$.
189    ///
190    /// If the output has a precision, it is `prec`.
191    ///
192    /// If you want to use a rounding mode other than `Nearest`, consider using
193    /// [`Float::factorial_prec_round`] instead.
194    ///
195    /// # Worst-case complexity
196    /// $T(n, p) = O(n (p + \log n) \log (p + \log n) \log\log (p + \log n))$
197    ///
198    /// $M(p) = O(p + \log n)$
199    ///
200    /// where $T$ is time, $M$ is additional memory, $n$ is `n`, and $p$ is `prec`.
201    ///
202    /// # Panics
203    /// Panics if `prec` is zero.
204    ///
205    /// # Examples
206    /// ```
207    /// use core::cmp::Ordering::*;
208    /// use malachite_float::Float;
209    ///
210    /// let (f, o) = Float::factorial_prec(10, 20);
211    /// assert_eq!(f.to_string(), "3628800.0");
212    /// assert_eq!(o, Equal);
213    ///
214    /// let (f, o) = Float::factorial_prec(20, 30);
215    /// assert_eq!(f.to_string(), "2.4329020103e18");
216    /// assert_eq!(o, Greater);
217    /// ```
218    pub fn factorial_prec(n: u64, prec: u64) -> (Self, Ordering) {
219        Self::factorial_prec_round(n, prec, Nearest)
220    }
221}