malachite-q 0.14.0

The arbitrary-precision type Rational, with efficient algorithms partially derived from GMP and FLINT.
Documentation
// Copyright © 2026 Mikhail Hogrefe
//
// Uses code adopted from the FLINT Library.
//
//      Copyright © 2011 Fredrik Johansson
//
// This file is part of Malachite.
//
// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.

use crate::Rational;
use malachite_base::num::arithmetic::traits::{AddMul, AddMulAssign};

// Like `fmpq_addmul`, this forms the product and adds it, rather than fusing the two steps. Both
// halves put their result in lowest terms, and the intermediate product is the smaller thing to
// reduce, so there is nothing to be saved by deferring that to a single reduction at the end.
//
// This is equivalent to `_fmpq_addmul` from `fmpq/addmul.c`, FLINT 3.6.0.
//
// A split-cancellation variant, its measurements, and the full argument that no fused schedule
// improves on this composition are recorded on `add_mul_split` in the crate's
// `test_util::rational::arithmetic::add_mul`.

impl AddMul<Self, Self> for Rational {
    type Output = Self;

    /// Adds a [`Rational`] and the product of two other [`Rational`]s, taking all three by value.
    ///
    /// $f(x, y, z) = x + yz$.
    ///
    /// # Worst-case complexity
    /// $T(n) = O(n (\log n)^2 \log\log n)$
    ///
    /// $M(n) = O(n \log n)$
    ///
    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
    /// y.significant_bits(), z.significant_bits())`.
    ///
    /// # Examples
    /// ```
    /// use malachite_base::num::arithmetic::traits::AddMul;
    /// use malachite_base::num::basic::traits::OneHalf;
    /// use malachite_q::Rational;
    ///
    /// assert_eq!(
    ///     Rational::ONE_HALF
    ///         .add_mul(Rational::from_signeds(2, 3), Rational::from_signeds(3, 4))
    ///         .to_string(),
    ///     "1"
    /// );
    /// assert_eq!(
    ///     Rational::from_signeds(22, 7)
    ///         .add_mul(Rational::from_signeds(-1, 2), Rational::from_signeds(1, 3))
    ///         .to_string(),
    ///     "125/42"
    /// );
    /// ```
    #[inline]
    fn add_mul(self, y: Self, z: Self) -> Self {
        self + y * z
    }
}

impl<'a> AddMul<Self, &'a Self> for Rational {
    type Output = Self;

    /// Adds a [`Rational`] and the product of two other [`Rational`]s, taking the first two by
    /// value and the third by reference.
    ///
    /// $f(x, y, z) = x + yz$.
    ///
    /// # Worst-case complexity
    /// $T(n) = O(n (\log n)^2 \log\log n)$
    ///
    /// $M(n) = O(n \log n)$
    ///
    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
    /// y.significant_bits(), z.significant_bits())`.
    ///
    /// # Examples
    /// ```
    /// use malachite_base::num::arithmetic::traits::AddMul;
    /// use malachite_base::num::basic::traits::OneHalf;
    /// use malachite_q::Rational;
    ///
    /// assert_eq!(
    ///     Rational::ONE_HALF
    ///         .add_mul(Rational::from_signeds(2, 3), &Rational::from_signeds(3, 4))
    ///         .to_string(),
    ///     "1"
    /// );
    /// ```
    #[inline]
    fn add_mul(self, y: Self, z: &'a Self) -> Self {
        self + y * z
    }
}

impl<'a> AddMul<&'a Self, Self> for Rational {
    type Output = Self;

    /// Adds a [`Rational`] and the product of two other [`Rational`]s, taking the first and third
    /// by value and the second by reference.
    ///
    /// $f(x, y, z) = x + yz$.
    ///
    /// # Worst-case complexity
    /// $T(n) = O(n (\log n)^2 \log\log n)$
    ///
    /// $M(n) = O(n \log n)$
    ///
    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
    /// y.significant_bits(), z.significant_bits())`.
    ///
    /// # Examples
    /// ```
    /// use malachite_base::num::arithmetic::traits::AddMul;
    /// use malachite_base::num::basic::traits::OneHalf;
    /// use malachite_q::Rational;
    ///
    /// assert_eq!(
    ///     Rational::ONE_HALF
    ///         .add_mul(&Rational::from_signeds(2, 3), Rational::from_signeds(3, 4))
    ///         .to_string(),
    ///     "1"
    /// );
    /// ```
    #[inline]
    fn add_mul(self, y: &'a Self, z: Self) -> Self {
        self + y * z
    }
}

impl<'a, 'b> AddMul<&'a Self, &'b Self> for Rational {
    type Output = Self;

    /// Adds a [`Rational`] and the product of two other [`Rational`]s, taking the first by value
    /// and the second and third by reference.
    ///
    /// $f(x, y, z) = x + yz$.
    ///
    /// # Worst-case complexity
    /// $T(n) = O(n (\log n)^2 \log\log n)$
    ///
    /// $M(n) = O(n \log n)$
    ///
    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
    /// y.significant_bits(), z.significant_bits())`.
    ///
    /// # Examples
    /// ```
    /// use malachite_base::num::arithmetic::traits::AddMul;
    /// use malachite_base::num::basic::traits::OneHalf;
    /// use malachite_q::Rational;
    ///
    /// assert_eq!(
    ///     Rational::ONE_HALF
    ///         .add_mul(&Rational::from_signeds(2, 3), &Rational::from_signeds(3, 4))
    ///         .to_string(),
    ///     "1"
    /// );
    /// ```
    #[inline]
    fn add_mul(self, y: &'a Self, z: &'b Self) -> Self {
        self + y * z
    }
}

impl AddMul<&Rational, &Rational> for &Rational {
    type Output = Rational;

    /// Adds a [`Rational`] and the product of two other [`Rational`]s, taking all three by
    /// reference.
    ///
    /// $f(x, y, z) = x + yz$.
    ///
    /// # Worst-case complexity
    /// $T(n) = O(n (\log n)^2 \log\log n)$
    ///
    /// $M(n) = O(n \log n)$
    ///
    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
    /// y.significant_bits(), z.significant_bits())`.
    ///
    /// # Examples
    /// ```
    /// use malachite_base::num::arithmetic::traits::AddMul;
    /// use malachite_base::num::basic::traits::OneHalf;
    /// use malachite_q::Rational;
    ///
    /// assert_eq!(
    ///     (&Rational::ONE_HALF)
    ///         .add_mul(&Rational::from_signeds(2, 3), &Rational::from_signeds(3, 4))
    ///         .to_string(),
    ///     "1"
    /// );
    /// ```
    #[inline]
    fn add_mul(self, y: &Rational, z: &Rational) -> Rational {
        self + y * z
    }
}

impl AddMulAssign<Self, Self> for Rational {
    /// Adds the product of two other [`Rational`]s to a [`Rational`] in place, taking both
    /// [`Rational`]s on the right-hand side by value.
    ///
    /// $x \gets x + yz$.
    ///
    /// # Worst-case complexity
    /// $T(n) = O(n (\log n)^2 \log\log n)$
    ///
    /// $M(n) = O(n \log n)$
    ///
    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
    /// y.significant_bits(), z.significant_bits())`.
    ///
    /// # Examples
    /// ```
    /// use malachite_base::num::arithmetic::traits::AddMulAssign;
    /// use malachite_base::num::basic::traits::OneHalf;
    /// use malachite_q::Rational;
    ///
    /// let mut x = Rational::ONE_HALF;
    /// x.add_mul_assign(Rational::from_signeds(2, 3), Rational::from_signeds(3, 4));
    /// assert_eq!(x.to_string(), "1");
    /// ```
    #[inline]
    fn add_mul_assign(&mut self, y: Self, z: Self) {
        *self += y * z;
    }
}

impl<'a> AddMulAssign<Self, &'a Self> for Rational {
    /// Adds the product of two other [`Rational`]s to a [`Rational`] in place, taking the first
    /// [`Rational`] on the right-hand side by value and the second by reference.
    ///
    /// $x \gets x + yz$.
    ///
    /// # Worst-case complexity
    /// $T(n) = O(n (\log n)^2 \log\log n)$
    ///
    /// $M(n) = O(n \log n)$
    ///
    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
    /// y.significant_bits(), z.significant_bits())`.
    ///
    /// # Examples
    /// ```
    /// use malachite_base::num::arithmetic::traits::AddMulAssign;
    /// use malachite_base::num::basic::traits::OneHalf;
    /// use malachite_q::Rational;
    ///
    /// let mut x = Rational::ONE_HALF;
    /// x.add_mul_assign(Rational::from_signeds(2, 3), &Rational::from_signeds(3, 4));
    /// assert_eq!(x.to_string(), "1");
    /// ```
    #[inline]
    fn add_mul_assign(&mut self, y: Self, z: &'a Self) {
        *self += y * z;
    }
}

impl<'a> AddMulAssign<&'a Self, Self> for Rational {
    /// Adds the product of two other [`Rational`]s to a [`Rational`] in place, taking the first
    /// [`Rational`] on the right-hand side by reference and the second by value.
    ///
    /// $x \gets x + yz$.
    ///
    /// # Worst-case complexity
    /// $T(n) = O(n (\log n)^2 \log\log n)$
    ///
    /// $M(n) = O(n \log n)$
    ///
    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
    /// y.significant_bits(), z.significant_bits())`.
    ///
    /// # Examples
    /// ```
    /// use malachite_base::num::arithmetic::traits::AddMulAssign;
    /// use malachite_base::num::basic::traits::OneHalf;
    /// use malachite_q::Rational;
    ///
    /// let mut x = Rational::ONE_HALF;
    /// x.add_mul_assign(&Rational::from_signeds(2, 3), Rational::from_signeds(3, 4));
    /// assert_eq!(x.to_string(), "1");
    /// ```
    #[inline]
    fn add_mul_assign(&mut self, y: &'a Self, z: Self) {
        *self += y * z;
    }
}

impl<'a, 'b> AddMulAssign<&'a Self, &'b Self> for Rational {
    /// Adds the product of two other [`Rational`]s to a [`Rational`] in place, taking both
    /// [`Rational`]s on the right-hand side by reference.
    ///
    /// $x \gets x + yz$.
    ///
    /// # Worst-case complexity
    /// $T(n) = O(n (\log n)^2 \log\log n)$
    ///
    /// $M(n) = O(n \log n)$
    ///
    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
    /// y.significant_bits(), z.significant_bits())`.
    ///
    /// # Examples
    /// ```
    /// use malachite_base::num::arithmetic::traits::AddMulAssign;
    /// use malachite_base::num::basic::traits::OneHalf;
    /// use malachite_q::Rational;
    ///
    /// let mut x = Rational::ONE_HALF;
    /// x.add_mul_assign(&Rational::from_signeds(2, 3), &Rational::from_signeds(3, 4));
    /// assert_eq!(x.to_string(), "1");
    /// ```
    #[inline]
    fn add_mul_assign(&mut self, y: &'a Self, z: &'b Self) {
        *self += y * z;
    }
}