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}