Skip to main content

malachite_nz/integer/comparison/
cmp_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::integer::Integer;
10use crate::natural::Natural;
11use core::cmp::Ordering::{self, *};
12use malachite_base::num::comparison::traits::{OrdProduct, OrdProductNeg};
13
14// Compares `a * b` with the integer whose sign is `c_sign` (`true` for non-negative) and whose
15// absolute value is `c_abs`; `c_sign` is ignored when `c_abs` is zero. The signs settle every case
16// except when `a * b` and `c` are nonzero with the same sign, where the absolute values are
17// compared by `Natural::cmp_product`.
18fn cmp_product_helper(a: &Integer, b: &Integer, c_sign: bool, c_abs: &Natural) -> Ordering {
19    let c_zero = *c_abs == 0u32;
20    if a.abs == 0u32 || b.abs == 0u32 {
21        if c_zero {
22            Equal
23        } else if c_sign {
24            Less
25        } else {
26            Greater
27        }
28    } else if a.sign == b.sign {
29        if c_zero || !c_sign {
30            Greater
31        } else {
32            Natural::cmp_product(&a.abs, &b.abs, c_abs)
33        }
34    } else if c_zero || c_sign {
35        Less
36    } else {
37        Natural::cmp_product(&a.abs, &b.abs, c_abs).reverse()
38    }
39}
40
41impl OrdProduct for Integer {
42    /// Compares the product of two [`Integer`]s with a third, computing the product only as a last
43    /// resort.
44    ///
45    /// $$
46    /// f(a, b, c) = \operatorname{cmp}(ab, c).
47    /// $$
48    ///
49    /// The signs decide every case except when $ab$ and $c$ are nonzero and have the same sign,
50    /// where the absolute values are compared by [`Natural::cmp_product`](OrdProduct::cmp_product),
51    /// which multiplies only as a last resort.
52    ///
53    /// # Worst-case complexity
54    /// $T(n) = O(n \log n \log\log n)$
55    ///
56    /// $M(n) = O(n \log n)$
57    ///
58    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(a.significant_bits(),
59    /// b.significant_bits())`.
60    ///
61    /// # Examples
62    /// ```
63    /// use core::cmp::Ordering::*;
64    /// use malachite_base::num::comparison::traits::OrdProduct;
65    /// use malachite_nz::integer::Integer;
66    ///
67    /// let z = |x: i32| Integer::from(x);
68    /// assert_eq!(Integer::cmp_product(&z(-3), &z(-7), &z(21)), Equal);
69    /// assert_eq!(Integer::cmp_product(&z(-3), &z(7), &z(-20)), Less);
70    /// assert_eq!(Integer::cmp_product(&z(3), &z(7), &z(-21)), Greater);
71    /// ```
72    ///
73    /// This is equivalent to `compareProduct` from `AzInt/CompareProduct.lean`, Azurite.
74    #[inline]
75    fn cmp_product(a: &Self, b: &Self, c: &Self) -> Ordering {
76        cmp_product_helper(a, b, c.sign, &c.abs)
77    }
78}
79
80impl OrdProductNeg for Integer {
81    /// Compares the product of two [`Integer`]s with the negative of a third, computing the product
82    /// only as a last resort and never computing the negative; equivalently, the sign of $ab + c$.
83    ///
84    /// $$
85    /// f(a, b, c) = \operatorname{cmp}(ab, -c).
86    /// $$
87    ///
88    /// The negative is handled by flipping the sign of $c$ as it is read, so no value is allocated
89    /// for it.
90    ///
91    /// # Worst-case complexity
92    /// $T(n) = O(n \log n \log\log n)$
93    ///
94    /// $M(n) = O(n \log n)$
95    ///
96    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(a.significant_bits(),
97    /// b.significant_bits())`.
98    ///
99    /// # Examples
100    /// ```
101    /// use core::cmp::Ordering::*;
102    /// use malachite_base::num::comparison::traits::OrdProductNeg;
103    /// use malachite_nz::integer::Integer;
104    ///
105    /// let z = |x: i32| Integer::from(x);
106    /// assert_eq!(Integer::cmp_product_neg(&z(-3), &z(-7), &z(-21)), Equal);
107    /// assert_eq!(Integer::cmp_product_neg(&z(-3), &z(7), &z(20)), Less);
108    /// assert_eq!(Integer::cmp_product_neg(&z(3), &z(7), &z(21)), Greater);
109    /// ```
110    #[inline]
111    fn cmp_product_neg(a: &Self, b: &Self, c: &Self) -> Ordering {
112        cmp_product_helper(a, b, !c.sign, &c.abs)
113    }
114}