Skip to main content

malachite_float/float/arithmetic/
product.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::InnerFloat::{Finite, Infinity, NaN, Zero};
10use crate::emulate_float_slice_to_float_fn;
11use crate::float::arithmetic::sum::max_prec;
12use crate::{
13    Float, float_infinity, float_nan, float_negative_infinity, float_negative_zero, float_zero,
14};
15use alloc::vec::Vec;
16use core::cmp::Ordering::{self, *};
17use core::iter::Product;
18use malachite_base::num::arithmetic::traits::{
19    CeilingLogBase2, NegAssign, PowerOf2, ShlRoundAssign, ShrRound,
20};
21use malachite_base::num::basic::floats::PrimitiveFloat;
22use malachite_base::num::basic::integers::PrimitiveInt;
23use malachite_base::num::conversion::traits::ExactFrom;
24use malachite_base::num::logic::traits::{NotAssign, SignificantBits};
25use malachite_base::rounding_modes::RoundingMode::{self, *};
26use malachite_nz::natural::Natural;
27use malachite_nz::natural::arithmetic::float::round::float_can_round;
28use malachite_nz::platform::Limb;
29
30// A shift so far out of range that `shl_round` saturates for any starting exponent, but which is
31// comfortably within `i64`.
32const SATURATING_SHIFT: i128 = 1 << 40;
33
34// Apply the accumulated exponent offset to a rounded Float, saturating on overflow or underflow in
35// the same round-then-check-range order as the rest of the library.
36fn apply_shift(f: &mut Float, shift: i128, rm: RoundingMode) -> Ordering {
37    let clamped = shift.clamp(const { -SATURATING_SHIFT }, SATURATING_SHIFT);
38    f.shl_round_assign(i64::exact_from(clamped), rm)
39}
40
41// Force the sign positive and the exponent to 1, absorbing the true exponent into `drift`.
42fn normalize(t: &mut Float, drift: &mut i128) {
43    let Float(Finite { sign, exponent, .. }) = t else {
44        unreachable!()
45    };
46    *sign = true;
47    *drift += i128::from(*exponent) - 1;
48    *exponent = 1;
49}
50
51// Truncate toward zero (which is sign-independent), then normalize.
52fn truncate(x: &Float, working_prec: u64, exact_all: &mut bool, drift: &mut i128) -> Float {
53    let (mut t, o) = Float::from_float_prec_round_ref(x, working_prec, Down);
54    if o != Equal {
55        *exact_all = false;
56    }
57    normalize(&mut t, drift);
58    t
59}
60
61// The product of at least 3 finite nonzero `Float`s, whose sign is `sign`, rounded to `prec` bits
62// with rounding mode `rm` (which must not be `Exact`; the caller handles that mode). Since a
63// product cannot cancel, the result is computed by a truncated Ziv iteration: multiply the
64// normalized significands at a working precision, rounding toward zero, and accept as soon as the
65// one-sided error interval is known not to straddle a rounding boundary. The exponents are
66// accumulated separately in an `i128` (the sum of up to `usize::MAX` exponents of absolute value at
67// most $2^{30}$ fits comfortably), so intermediate overflow and underflow are impossible; the final
68// exponent is applied with a single saturating shift.
69fn product_of_regulars(
70    xs: &[&Float],
71    sign: bool,
72    prec: u64,
73    rm: RoundingMode,
74) -> (Float, Ordering) {
75    let n = xs.len();
76    // Decompose each input as odd-significand times a power of 2, accumulating the powers of 2. The
77    // bit length of the product of the odd parts is at least b_min (an odd number times an odd
78    // number of bit lengths a and b has bit length at least a + b - 1).
79    let mut exp_offset = 0i128;
80    let mut b_min = 1u64;
81    let mut odd_bits = Vec::with_capacity(n);
82    for x in xs {
83        let Float(Finite {
84            exponent,
85            significand,
86            ..
87        }) = x
88        else {
89            unreachable!()
90        };
91        let tz = significand.trailing_zeros().unwrap();
92        let sig_len = significand.significant_bits();
93        exp_offset += i128::from(*exponent) - i128::from(sig_len) + i128::from(tz);
94        odd_bits.push((sig_len - tz, tz));
95        b_min += sig_len - tz - 1;
96    }
97    // Rounding the magnitude with the negated mode agrees with rounding the negated value with the
98    // original mode.
99    let rm_mag = if sign { rm } else { -rm };
100    if b_min <= prec + 1 {
101        // The exact product of the odd parts has at most b_min + n' bits, where n' counts the
102        // inputs with a nontrivial odd part, and n' <= b_min - 1; so the exact product is small and
103        // can be computed directly. This path covers every input set whose product could be exactly
104        // representable or exactly halfway between representable values.
105        let g = Natural::product(xs.iter().zip(odd_bits.iter()).filter_map(|(x, &(b, tz))| {
106            if b == 1 {
107                None
108            } else {
109                let Float(Finite { significand, .. }) = x else {
110                    unreachable!()
111                };
112                Some(significand >> tz)
113            }
114        }));
115        let g_len = g.significant_bits();
116        let (h, o_mag, h_shift) = if g_len > prec {
117            let (h, o) = g.shr_round(g_len - prec, rm_mag);
118            (h, o, i128::from(g_len - prec))
119        } else {
120            (g, Equal, 0)
121        };
122        // h has at most prec + 1 significant bits (prec plus a possible rounding carry), so this
123        // conversion is exact and its exponent is small.
124        let mut f = Float::from_natural_prec_round(h, prec, Exact).0;
125        let mut o = if sign {
126            o_mag
127        } else {
128            f.neg_assign();
129            o_mag.reverse()
130        };
131        let o_shift = apply_shift(&mut f, exp_offset + h_shift, rm);
132        if o_shift != Equal {
133            o = o_shift;
134        }
135        return (f, o);
136    }
137    // The product of the odd parts is an odd number with more than prec + 1 bits, so it cannot be
138    // exactly representable with prec bits, nor exactly halfway between two representable values. A
139    // truncated Ziv iteration therefore terminates.
140    let logn = u64::exact_from(n).ceiling_log_base_2();
141    let mut working_prec = prec + logn + 5;
142    let mut increment = Limb::WIDTH;
143    loop {
144        let mut drift = 0i128;
145        let mut exact_all = true;
146        let (first, rest) = xs.split_first().unwrap();
147        let mut acc = truncate(first, working_prec, &mut exact_all, &mut drift);
148        for x in rest {
149            let t = truncate(x, working_prec, &mut exact_all, &mut drift);
150            if acc.mul_prec_round_assign(t, working_prec, Down) != Equal {
151                exact_all = false;
152            }
153            normalize(&mut acc, &mut drift);
154        }
155        let finish = |mut acc: Float, inexact_guaranteed: bool| {
156            if !sign {
157                acc.neg_assign();
158            }
159            let (mut f, mut o) = Float::from_float_prec_round(acc, prec, rm);
160            if inexact_guaranteed {
161                assert_ne!(o, Equal);
162            }
163            let o_shift = apply_shift(&mut f, drift, rm);
164            if o_shift != Equal {
165                o = o_shift;
166            }
167            (f, o)
168        };
169        if exact_all
170            || float_can_round(
171                acc.significand_ref().unwrap(),
172                working_prec - (logn + 3),
173                prec,
174                rm_mag,
175            )
176        {
177            // float_can_round is conservative: it refuses any approximation that is exactly
178            // representable at the target precision (the ternary would be undecidable), so a
179            // successful can_round implies the final rounding is inexact.
180            return finish(acc, !exact_all);
181        }
182        if Float::from_float_prec_round_ref(&acc, prec, Floor).1 == Equal {
183            // The truncated accumulator is exactly representable at the target precision, so
184            // can_round can never succeed, no matter how large the working precision grows. But the
185            // error is one-sided — the true magnitude strictly exceeds the accumulator — and
186            // smaller than half an ulp of the target precision, so nudging the accumulator up by
187            // less than an ulp of the working precision and rounding that yields the correctly
188            // rounded value and ternary under every rounding mode.
189            let bump = Float::power_of_2(-i64::exact_from(working_prec) - 1);
190            acc.add_prec_round_assign(bump, working_prec + 2, Exact);
191            return finish(acc, true);
192        }
193        working_prec += increment;
194        increment = working_prec >> 1;
195    }
196}
197
198// The product of a slice of `Float`s, with correct rounding: only a single rounding is performed.
199// The `Exact` rounding mode is handled by computing with `Nearest` and panicking if the result is
200// inexact.
201fn product_prec_round_helper(xs: &[&Float], prec: u64, rm: RoundingMode) -> (Float, Ordering) {
202    assert_ne!(prec, 0);
203    let n = xs.len();
204    if n == 0 {
205        return (Float::one_prec(prec), Equal);
206    } else if n == 1 {
207        return Float::from_float_prec_round_ref(xs[0], prec, rm);
208    } else if n == 2 {
209        return xs[0].mul_prec_round_ref_ref(xs[1], prec, rm);
210    }
211    // Check for special inputs. The sign of any zero or infinite result, like the sign of a regular
212    // result, is the XOR of the signs of all the inputs.
213    let mut sign = true;
214    let mut any_zero = false;
215    let mut any_inf = false;
216    for x in xs {
217        match x {
218            float_nan!() => {
219                return (float_nan!(), Equal);
220            }
221            float_infinity!() => {
222                any_inf = true;
223            }
224            float_negative_infinity!() => {
225                any_inf = true;
226                sign.not_assign();
227            }
228            float_zero!() => {
229                any_zero = true;
230            }
231            float_negative_zero!() => {
232                any_zero = true;
233                sign.not_assign();
234            }
235            Float(Finite { sign: s, .. }) => {
236                if !s {
237                    sign.not_assign();
238                }
239            }
240        }
241    }
242    if any_inf {
243        // Any zero times any infinity is NaN.
244        return if any_zero {
245            (float_nan!(), Equal)
246        } else if sign {
247            (float_infinity!(), Equal)
248        } else {
249            (float_negative_infinity!(), Equal)
250        };
251    }
252    if any_zero {
253        return if sign {
254            (float_zero!(), Equal)
255        } else {
256            (float_negative_zero!(), Equal)
257        };
258    }
259    // At this point every input is finite and nonzero.
260    let (kernel_rm, exact) = if rm == Exact {
261        (Nearest, true)
262    } else {
263        (rm, false)
264    };
265    let (f, o) = product_of_regulars(xs, sign, prec, kernel_rm);
266    if exact {
267        assert_eq!(o, Equal, "Inexact Float product");
268    }
269    (f, o)
270}
271
272impl Float {
273    /// Computes the product of a slice of [`Float`]s, rounding the result to the specified
274    /// precision and with the specified rounding mode. An [`Ordering`] is also returned, indicating
275    /// whether the rounded product is less than, equal to, or greater than the exact product.
276    /// Although `NaN`s are not comparable to any [`Float`], whenever this function returns a `NaN`
277    /// it also returns `Equal`.
278    ///
279    /// Only a single rounding is performed, no matter how many inputs there are: the result is the
280    /// correctly-rounded exact product, with no intermediate rounding, overflow, or underflow. MPFR
281    /// has no equivalent of this function.
282    ///
283    /// See [`RoundingMode`] for a description of the possible rounding modes.
284    ///
285    /// $$
286    /// f((x_i)_ {i=0}^{n-1}, p, m) = \prod_ {i=0}^{n-1} x_i + \varepsilon.
287    /// $$
288    /// - If $\prod_ {i=0}^{n-1} x_i$ is infinite, zero, or `NaN`, $\varepsilon$ may be ignored or
289    ///   assumed to be 0.
290    /// - If $\prod_ {i=0}^{n-1} x_i$ is finite and nonzero, and $m$ is not `Nearest`, then
291    ///   $|\varepsilon| < 2^{\lfloor\log_2 |\prod_ {i=0}^{n-1} x_i|\rfloor-p+1}$.
292    /// - If $\prod_ {i=0}^{n-1} x_i$ is finite and nonzero, and $m$ is `Nearest`, then
293    ///   $|\varepsilon| \leq 2^{\lfloor\log_2 |\prod_ {i=0}^{n-1} x_i|\rfloor-p}$.
294    ///
295    /// The output has precision `prec`.
296    ///
297    /// Special cases:
298    /// - The product of no [`Float`]s is 1.
299    /// - If any input is `NaN`, or if the inputs include both a zero and an infinity, the product
300    ///   is `NaN`.
301    /// - Otherwise, if any input is infinite, the product is infinite; and if any input is a zero,
302    ///   the product is a zero. In both cases, as for a regular product, the sign is negative if
303    ///   and only if an odd number of the inputs are negative, negative zeros and negative
304    ///   infinities included.
305    ///
306    /// Overflow and underflow:
307    /// - If $f((x_i)_ {i=0}^{n-1},p,m)\geq 2^{2^{30}-1}$ and $m$ is `Ceiling`, `Up`, or `Nearest`,
308    ///   $\infty$ is returned instead.
309    /// - If $f((x_i)_ {i=0}^{n-1},p,m)\geq 2^{2^{30}-1}$ and $m$ is `Floor` or `Down`,
310    ///   $(1-(1/2)^p)2^{2^{30}-1}$ is returned instead.
311    /// - If $f((x_i)_ {i=0}^{n-1},p,m)\leq -2^{2^{30}-1}$ and $m$ is `Floor`, `Up`, or `Nearest`,
312    ///   $-\infty$ is returned instead.
313    /// - If $f((x_i)_ {i=0}^{n-1},p,m)\leq -2^{2^{30}-1}$ and $m$ is `Ceiling` or `Down`,
314    ///   $-(1-(1/2)^p)2^{2^{30}-1}$ is returned instead.
315    /// - If $0<f((x_i)_ {i=0}^{n-1},p,m)<2^{-2^{30}}$, and $m$ is `Floor` or `Down`, $0.0$ is
316    ///   returned instead.
317    /// - If $0<f((x_i)_ {i=0}^{n-1},p,m)<2^{-2^{30}}$, and $m$ is `Ceiling` or `Up`, $2^{-2^{30}}$
318    ///   is returned instead.
319    /// - If $0<f((x_i)_ {i=0}^{n-1},p,m)\leq2^{-2^{30}-1}$, and $m$ is `Nearest`, $0.0$ is returned
320    ///   instead.
321    /// - If $2^{-2^{30}-1}<f((x_i)_ {i=0}^{n-1},p,m)<2^{-2^{30}}$, and $m$ is `Nearest`,
322    ///   $2^{-2^{30}}$ is returned instead.
323    /// - If $-2^{-2^{30}}<f((x_i)_ {i=0}^{n-1},p,m)<0$, and $m$ is `Ceiling` or `Down`, $-0.0$ is
324    ///   returned instead.
325    /// - If $-2^{-2^{30}}<f((x_i)_ {i=0}^{n-1},p,m)<0$, and $m$ is `Floor` or `Up`, $-2^{-2^{30}}$
326    ///   is returned instead.
327    /// - If $-2^{-2^{30}-1}\leq f((x_i)_ {i=0}^{n-1},p,m)<0$, and $m$ is `Nearest`, $-0.0$ is
328    ///   returned instead.
329    /// - If $-2^{-2^{30}}<f((x_i)_ {i=0}^{n-1},p,m)<-2^{-2^{30}-1}$, and $m$ is `Nearest`,
330    ///   $-2^{-2^{30}}$ is returned instead.
331    ///
332    /// If you know you'll be using `Nearest`, consider using [`Float::product_prec`] instead. If
333    /// you know that your target precision is the maximum of the precisions of the inputs, consider
334    /// using [`Float::product_round`] instead. If both of these things are true, consider taking
335    /// the product of an iterator with [`Product`] instead.
336    ///
337    /// # Worst-case complexity
338    /// $T(n, m, p) = O(n (m + p) \log (m + p) \log\log (m + p) + p (\log p)^2 \log\log p)$
339    ///
340    /// $M(n, m, p) = O(n + (m + p) \log (m + p))$
341    ///
342    /// where $T$ is time, $M$ is additional memory, $n$ is `xs.len()`, $m$ is
343    /// `u64::sum(xs.map(Float::significant_bits))`, and $p$ is `prec`: the working precision starts
344    /// at $p + \log n$ and, for adversarially boundary-hugging products, grows geometrically until
345    /// the computation becomes exact at the total input size, with each round multiplying $n$
346    /// truncated factors at the working precision; products whose odd parts are small enough to be
347    /// exactly representable are instead computed exactly with a product tree.
348    ///
349    /// # Panics
350    /// Panics if `prec` is zero, or if `rm` is `Exact` and the exact product is not exactly
351    /// representable with `prec` bits.
352    ///
353    /// # Examples
354    /// ```
355    /// use malachite_base::rounding_modes::RoundingMode::*;
356    /// use malachite_float::Float;
357    /// use std::cmp::Ordering::*;
358    ///
359    /// let xs = [Float::from(3), Float::from(5), Float::from(7)];
360    ///
361    /// let (product, o) = Float::product_prec_round(&xs, 10, Floor);
362    /// assert_eq!(product.to_string(), "105.00");
363    /// assert_eq!(o, Equal);
364    ///
365    /// let (product, o) = Float::product_prec_round(&xs, 3, Floor);
366    /// assert_eq!(product.to_string(), "96.0");
367    /// assert_eq!(o, Less);
368    ///
369    /// let (product, o) = Float::product_prec_round(&xs, 3, Ceiling);
370    /// assert_eq!(product.to_string(), "1.1e2");
371    /// assert_eq!(o, Greater);
372    ///
373    /// let (product, o) = Float::product_prec_round(&xs, 3, Nearest);
374    /// assert_eq!(product.to_string(), "1.1e2");
375    /// assert_eq!(o, Greater);
376    /// ```
377    pub fn product_prec_round(xs: &[Self], prec: u64, rm: RoundingMode) -> (Self, Ordering) {
378        let refs: Vec<&Self> = xs.iter().collect();
379        product_prec_round_helper(&refs, prec, rm)
380    }
381
382    /// Computes the product of a slice of [`Float`]s, rounding the result to the nearest value of
383    /// the specified precision. An [`Ordering`] is also returned, indicating whether the rounded
384    /// product is less than, equal to, or greater than the exact product. Although `NaN`s are not
385    /// comparable to any [`Float`], whenever this function returns a `NaN` it also returns `Equal`.
386    ///
387    /// Only a single rounding is performed, no matter how many inputs there are: the result is the
388    /// correctly-rounded exact product, with no intermediate rounding, overflow, or underflow. MPFR
389    /// has no equivalent of this function.
390    ///
391    /// If the product is equidistant from two [`Float`]s with the specified precision, the
392    /// [`Float`] with fewer 1s in its binary expansion is chosen. See [`RoundingMode`] for a
393    /// description of the `Nearest` rounding mode.
394    ///
395    /// $$
396    /// f((x_i)_ {i=0}^{n-1}, p) = \prod_ {i=0}^{n-1} x_i + \varepsilon.
397    /// $$
398    /// - If $\prod_ {i=0}^{n-1} x_i$ is infinite, zero, or `NaN`, $\varepsilon$ may be ignored or
399    ///   assumed to be 0.
400    /// - If $\prod_ {i=0}^{n-1} x_i$ is finite and nonzero, then $|\varepsilon| \leq
401    ///   2^{\lfloor\log_2 |\prod_ {i=0}^{n-1} x_i|\rfloor-p}$.
402    ///
403    /// The output has precision `prec`.
404    ///
405    /// See [`Float::product_prec_round`] for a description of the special cases and of overflow and
406    /// underflow behavior.
407    ///
408    /// If you know that your target precision is the maximum of the precisions of the inputs,
409    /// consider taking the product of an iterator with [`Product`] instead.
410    ///
411    /// # Worst-case complexity
412    /// $T(n, m, p) = O(n (m + p) \log (m + p) \log\log (m + p) + p (\log p)^2 \log\log p)$
413    ///
414    /// $M(n, m, p) = O(n + (m + p) \log (m + p))$
415    ///
416    /// where $T$ is time, $M$ is additional memory, $n$ is `xs.len()`, $m$ is
417    /// `u64::sum(xs.map(Float::significant_bits))`, and $p$ is `prec`.
418    ///
419    /// # Panics
420    /// Panics if `prec` is zero.
421    ///
422    /// # Examples
423    /// ```
424    /// use malachite_float::Float;
425    /// use std::cmp::Ordering::*;
426    ///
427    /// let xs = [Float::from(3), Float::from(5), Float::from(7)];
428    ///
429    /// let (product, o) = Float::product_prec(&xs, 10);
430    /// assert_eq!(product.to_string(), "105.00");
431    /// assert_eq!(o, Equal);
432    ///
433    /// let (product, o) = Float::product_prec(&xs, 3);
434    /// assert_eq!(product.to_string(), "1.1e2");
435    /// assert_eq!(o, Greater);
436    /// ```
437    #[inline]
438    pub fn product_prec(xs: &[Self], prec: u64) -> (Self, Ordering) {
439        Self::product_prec_round(xs, prec, Nearest)
440    }
441
442    /// Computes the product of a slice of [`Float`]s, rounding the result with the specified
443    /// rounding mode. The precision of the result is the maximum of the precisions of the inputs
444    /// (or 1 if there are no inputs). An [`Ordering`] is also returned, indicating whether the
445    /// rounded product is less than, equal to, or greater than the exact product. Although `NaN`s
446    /// are not comparable to any [`Float`], whenever this function returns a `NaN` it also returns
447    /// `Equal`.
448    ///
449    /// Only a single rounding is performed, no matter how many inputs there are: the result is the
450    /// correctly-rounded exact product, with no intermediate rounding, overflow, or underflow. MPFR
451    /// has no equivalent of this function.
452    ///
453    /// See [`RoundingMode`] for a description of the possible rounding modes.
454    ///
455    /// $$
456    /// f((x_i)_ {i=0}^{n-1}, m) = \prod_ {i=0}^{n-1} x_i + \varepsilon.
457    /// $$
458    /// - If $\prod_ {i=0}^{n-1} x_i$ is infinite, zero, or `NaN`, $\varepsilon$ may be ignored or
459    ///   assumed to be 0.
460    /// - If $\prod_ {i=0}^{n-1} x_i$ is finite and nonzero, and $m$ is not `Nearest`, then
461    ///   $|\varepsilon| < 2^{\lfloor\log_2 |\prod_ {i=0}^{n-1} x_i|\rfloor-p+1}$, where $p$ is the
462    ///   maximum precision of the inputs.
463    /// - If $\prod_ {i=0}^{n-1} x_i$ is finite and nonzero, and $m$ is `Nearest`, then
464    ///   $|\varepsilon| \leq 2^{\lfloor\log_2 |\prod_ {i=0}^{n-1} x_i|\rfloor-p}$, where $p$ is the
465    ///   maximum precision of the inputs.
466    ///
467    /// See [`Float::product_prec_round`] for a description of the special cases and of overflow and
468    /// underflow behavior.
469    ///
470    /// If you know you'll be using `Nearest`, consider taking the product of an iterator with
471    /// [`Product`] instead.
472    ///
473    /// # Worst-case complexity
474    /// $T(n, m) = O(n m \log m \log\log m + m (\log m)^2 \log\log m)$
475    ///
476    /// $M(n, m) = O(n + m \log m)$
477    ///
478    /// where $T$ is time, $M$ is additional memory, $n$ is `xs.len()`, and $m$ is
479    /// `u64::sum(xs.map(Float::significant_bits))`.
480    ///
481    /// # Panics
482    /// Panics if `rm` is `Exact` and the exact product is not exactly representable with the
483    /// maximum of the precisions of the inputs.
484    ///
485    /// # Examples
486    /// ```
487    /// use malachite_base::rounding_modes::RoundingMode::*;
488    /// use malachite_float::Float;
489    /// use std::cmp::Ordering::*;
490    ///
491    /// let xs = [Float::from(3), Float::from(5), Float::from(7)];
492    ///
493    /// let (product, o) = Float::product_round(&xs, Floor);
494    /// assert_eq!(product.to_string(), "96.0");
495    /// assert_eq!(o, Less);
496    ///
497    /// let (product, o) = Float::product_round(&xs, Ceiling);
498    /// assert_eq!(product.to_string(), "1.1e2");
499    /// assert_eq!(o, Greater);
500    /// ```
501    #[inline]
502    pub fn product_round(xs: &[Self], rm: RoundingMode) -> (Self, Ordering) {
503        Self::product_prec_round(xs, max_prec(xs.iter()), rm)
504    }
505}
506
507/// Computes the product of a slice of primitive floats, with a single rounding.
508///
509/// The result is correctly rounded to the nearest value: the product is computed as if in infinite
510/// precision and rounded only once, at the end, no matter how many inputs there are. This includes
511/// gradual underflow: results in the subnormal range are correctly rounded to their reduced
512/// precisions. Intermediate overflow and underflow cannot occur.
513///
514/// $$
515/// f((x_i)_ {i=0}^{n-1}) = \prod_ {i=0}^{n-1} x_i + \varepsilon.
516/// $$
517/// - If $\prod_ {i=0}^{n-1} x_i$ is infinite, zero, or `NaN`, $\varepsilon$ may be ignored or
518///   assumed to be 0.
519/// - If $\prod_ {i=0}^{n-1} x_i$ is finite and nonzero, then $|\varepsilon| \leq 2^{\lfloor\log_2
520///   |\prod_ {i=0}^{n-1} x_i|\rfloor-p}$, where $p$ is the precision of the output (typically 24 if
521///   `T` is a [`f32`] and 53 if `T` is a [`f64`], but less if the output is subnormal).
522///
523/// Special cases:
524/// - The product of no floats is $1.0$.
525/// - If any input is `NaN`, or if the inputs include both a zero and an infinity, the product is
526///   `NaN`.
527/// - Otherwise, if any input is infinite, the product is infinite; and if any input is a zero, the
528///   product is a zero. In both cases, as for a regular product, the sign is negative if and only
529///   if an odd number of the inputs are negative, negative zeros and negative infinities included.
530///
531/// If the result overflows, $\pm\infty$ is returned, and if it underflows, $\pm0.0$ is returned.
532///
533/// # Worst-case complexity
534/// $T(n) = O(n^2 \log n \log\log n)$
535///
536/// $M(n) = O(n \log n)$
537///
538/// where $T$ is time, $M$ is additional memory, and $n$ is `xs.len()`: for adversarially
539/// boundary-hugging products the working precision grows to the total input size, though typical
540/// inputs are handled in linear time.
541///
542/// # Examples
543/// ```
544/// use malachite_base::num::float::NiceFloat;
545/// use malachite_float::float::arithmetic::product::primitive_float_product;
546///
547/// // A naive fold underflows to zero and stays there; the correctly-rounded product does not.
548/// let xs = [1.0e-200f64, 1.0e-200, 1.0e300, 1.0e300];
549/// assert_eq!(
550///     NiceFloat(primitive_float_product(&xs)),
551///     NiceFloat(1.0000000000000001e200)
552/// );
553/// assert_eq!(NiceFloat(xs.iter().product::<f64>()), NiceFloat(0.0));
554/// ```
555#[allow(clippy::type_repetition_in_bounds)]
556#[inline]
557pub fn primitive_float_product<T: PrimitiveFloat>(xs: &[T]) -> T
558where
559    Float: From<T> + PartialOrd<T>,
560    for<'a> T: ExactFrom<&'a Float>,
561{
562    emulate_float_slice_to_float_fn(Float::product_prec, xs)
563}
564
565impl Product<Self> for Float {
566    /// Multiplies together all the [`Float`]s in an iterator.
567    ///
568    /// The result has the maximum of the precisions of the inputs (or 1 if there are no inputs),
569    /// and the product is rounded to nearest. Only a single rounding is performed, no matter how
570    /// many inputs there are: the result is the correctly-rounded exact product, with no
571    /// intermediate rounding, overflow, or underflow. MPFR has no equivalent of this function.
572    ///
573    /// $$
574    /// f((x_i)_ {i=0}^{n-1}) = \prod_ {i=0}^{n-1} x_i + \varepsilon.
575    /// $$
576    /// - If $\prod_ {i=0}^{n-1} x_i$ is infinite, zero, or `NaN`, $\varepsilon$ may be ignored or
577    ///   assumed to be 0.
578    /// - If $\prod_ {i=0}^{n-1} x_i$ is finite and nonzero, then $|\varepsilon| \leq
579    ///   2^{\lfloor\log_2 |\prod_ {i=0}^{n-1} x_i|\rfloor-p}$, where $p$ is the maximum precision
580    ///   of the inputs.
581    ///
582    /// See [`Float::product_prec_round`] for a description of the special cases and of overflow and
583    /// underflow behavior.
584    ///
585    /// # Worst-case complexity
586    /// $T(n, m) = O(n m \log m \log\log m + m (\log m)^2 \log\log m)$
587    ///
588    /// $M(n, m) = O(n + m \log m)$
589    ///
590    /// where $T$ is time, $M$ is additional memory, $n$ is `xs.count()`, and $m$ is
591    /// `u64::sum(xs.map(Float::significant_bits))`.
592    ///
593    /// # Examples
594    /// ```
595    /// use core::iter::Product;
596    /// use malachite_base::num::basic::traits::{One, Two};
597    /// use malachite_float::Float;
598    ///
599    /// let product = Float::product([Float::ONE, Float::TWO, Float::from(3)].into_iter());
600    /// assert_eq!(product.to_string(), "6.0");
601    ///
602    /// // All twenty inputs have precision 2, so the result has precision 2, but only a single
603    /// // rounding is performed at the end: the result is the correctly-rounded value of 3^20.
604    /// let product = Float::product(vec![Float::from(3); 20].into_iter());
605    /// assert_eq!(product.to_string(), "3.2e9");
606    /// ```
607    fn product<I>(xs: I) -> Self
608    where
609        I: Iterator<Item = Self>,
610    {
611        let xs: Vec<Self> = xs.collect();
612        let refs: Vec<&Self> = xs.iter().collect();
613        product_prec_round_helper(&refs, max_prec(xs.iter()), Nearest).0
614    }
615}
616
617impl<'a> Product<&'a Self> for Float {
618    /// Multiplies together all the [`Float`]s in an iterator of [`Float`] references.
619    ///
620    /// The result has the maximum of the precisions of the inputs (or 1 if there are no inputs),
621    /// and the product is rounded to nearest. Only a single rounding is performed, no matter how
622    /// many inputs there are: the result is the correctly-rounded exact product, with no
623    /// intermediate rounding, overflow, or underflow. MPFR has no equivalent of this function.
624    ///
625    /// $$
626    /// f((x_i)_ {i=0}^{n-1}) = \prod_ {i=0}^{n-1} x_i + \varepsilon.
627    /// $$
628    /// - If $\prod_ {i=0}^{n-1} x_i$ is infinite, zero, or `NaN`, $\varepsilon$ may be ignored or
629    ///   assumed to be 0.
630    /// - If $\prod_ {i=0}^{n-1} x_i$ is finite and nonzero, then $|\varepsilon| \leq
631    ///   2^{\lfloor\log_2 |\prod_ {i=0}^{n-1} x_i|\rfloor-p}$, where $p$ is the maximum precision
632    ///   of the inputs.
633    ///
634    /// See [`Float::product_prec_round`] for a description of the special cases and of overflow and
635    /// underflow behavior.
636    ///
637    /// # Worst-case complexity
638    /// $T(n, m) = O(n m \log m \log\log m + m (\log m)^2 \log\log m)$
639    ///
640    /// $M(n, m) = O(n + m \log m)$
641    ///
642    /// where $T$ is time, $M$ is additional memory, $n$ is `xs.count()`, and $m$ is
643    /// `u64::sum(xs.map(Float::significant_bits))`.
644    ///
645    /// # Examples
646    /// ```
647    /// use core::iter::Product;
648    /// use malachite_base::num::basic::traits::{One, Two};
649    /// use malachite_float::Float;
650    ///
651    /// let xs = vec![Float::ONE, Float::TWO, Float::from(3)];
652    /// assert_eq!(Float::product(xs.iter()).to_string(), "6.0");
653    /// ```
654    fn product<I>(xs: I) -> Self
655    where
656        I: Iterator<Item = &'a Self>,
657    {
658        let xs: Vec<&Self> = xs.collect();
659        product_prec_round_helper(&xs, max_prec(xs.iter().copied()), Nearest).0
660    }
661}