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}