Skip to main content

malachite_nz/integer_vector/arithmetic/
entrywise_div_round.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::integer_vector::IntegerVector;
11use crate::natural::Natural;
12use malachite_base::num::arithmetic::traits::{
13    DivRound, DivRoundAssign, EntrywiseDivRound, EntrywiseDivRoundAssign, NegAssign,
14};
15use malachite_base::num::basic::traits::{One, Zero};
16use malachite_base::rounding_modes::RoundingMode;
17
18impl EntrywiseDivRound<Integer> for IntegerVector {
19    type Output = Self;
20
21    /// Divides every element of an [`IntegerVector`] by an [`Integer`], taking the vector by value
22    /// and the scalar by value, and rounds every quotient according to the specified rounding mode.
23    ///
24    /// Each quotient is rounded as by [`DivRound`], but no [`Ordering`](core::cmp::Ordering) is
25    /// returned, since with `Nearest` different elements may be rounded in different directions.
26    /// Passing `Down` is equivalent to using `/`.
27    ///
28    /// $f(v, c, r)_i = \operatorname{round}(v_i/c)$, where $\operatorname{round}$ rounds according
29    /// to `rm`.
30    ///
31    /// # Worst-case complexity
32    /// $T(n) = O(n \log n \log\log n)$
33    ///
34    /// $M(n) = O(n \log n)$
35    ///
36    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
37    /// elements and of `c`.
38    ///
39    /// # Panics
40    /// Panics if `c` is zero, or if `rm` is `Exact` and some element is not divisible by `c`.
41    ///
42    /// # Examples
43    /// See [here](super::entrywise_div_round#entrywise_div_round).
44    ///
45    /// With `rm` equal to `Floor`, this is equivalent to `_fmpz_vec_scalar_fdiv_q_fmpz` from
46    /// `fmpz_vec/scalar.c`, FLINT 3.6.0.
47    #[inline]
48    fn entrywise_div_round(mut self, c: Integer, rm: RoundingMode) -> Self {
49        self.entrywise_div_round_assign(&c, rm);
50        self
51    }
52}
53
54impl EntrywiseDivRound<&Integer> for IntegerVector {
55    type Output = Self;
56
57    /// Divides every element of an [`IntegerVector`] by an [`Integer`], taking the vector by value
58    /// and the scalar by reference, and rounds every quotient according to the specified rounding
59    /// mode.
60    ///
61    /// Each quotient is rounded as by [`DivRound`], but no [`Ordering`](core::cmp::Ordering) is
62    /// returned, since with `Nearest` different elements may be rounded in different directions.
63    /// Passing `Down` is equivalent to using `/`.
64    ///
65    /// $f(v, c, r)_i = \operatorname{round}(v_i/c)$, where $\operatorname{round}$ rounds according
66    /// to `rm`.
67    ///
68    /// # Worst-case complexity
69    /// $T(n) = O(n \log n \log\log n)$
70    ///
71    /// $M(n) = O(n \log n)$
72    ///
73    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
74    /// elements and of `c`.
75    ///
76    /// # Panics
77    /// Panics if `c` is zero, or if `rm` is `Exact` and some element is not divisible by `c`.
78    ///
79    /// # Examples
80    /// See [here](super::entrywise_div_round#entrywise_div_round).
81    ///
82    /// With `rm` equal to `Floor`, this is equivalent to `_fmpz_vec_scalar_fdiv_q_fmpz` from
83    /// `fmpz_vec/scalar.c`, FLINT 3.6.0.
84    #[inline]
85    fn entrywise_div_round(mut self, c: &Integer, rm: RoundingMode) -> Self {
86        self.entrywise_div_round_assign(c, rm);
87        self
88    }
89}
90
91impl EntrywiseDivRound<Integer> for &IntegerVector {
92    type Output = IntegerVector;
93
94    /// Divides every element of an [`IntegerVector`] by an [`Integer`], taking the vector by
95    /// reference and the scalar by value, and rounds every quotient according to the specified
96    /// rounding mode.
97    ///
98    /// Each quotient is rounded as by [`DivRound`], but no [`Ordering`](core::cmp::Ordering) is
99    /// returned, since with `Nearest` different elements may be rounded in different directions.
100    /// Passing `Down` is equivalent to using `/`.
101    ///
102    /// $f(v, c, r)_i = \operatorname{round}(v_i/c)$, where $\operatorname{round}$ rounds according
103    /// to `rm`.
104    ///
105    /// # Worst-case complexity
106    /// $T(n) = O(n \log n \log\log n)$
107    ///
108    /// $M(n) = O(n \log n)$
109    ///
110    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
111    /// elements and of `c`.
112    ///
113    /// # Panics
114    /// Panics if `c` is zero, or if `rm` is `Exact` and some element is not divisible by `c`.
115    ///
116    /// # Examples
117    /// See [here](super::entrywise_div_round#entrywise_div_round).
118    ///
119    /// With `rm` equal to `Floor`, this is equivalent to `_fmpz_vec_scalar_fdiv_q_fmpz` from
120    /// `fmpz_vec/scalar.c`, FLINT 3.6.0.
121    #[inline]
122    fn entrywise_div_round(self, c: Integer, rm: RoundingMode) -> IntegerVector {
123        self.entrywise_div_round(&c, rm)
124    }
125}
126
127impl EntrywiseDivRound<&Integer> for &IntegerVector {
128    type Output = IntegerVector;
129
130    /// Divides every element of an [`IntegerVector`] by an [`Integer`], taking the vector by
131    /// reference and the scalar by reference, and rounds every quotient according to the specified
132    /// rounding mode.
133    ///
134    /// Each quotient is rounded as by [`DivRound`], but no [`Ordering`](core::cmp::Ordering) is
135    /// returned, since with `Nearest` different elements may be rounded in different directions.
136    /// Passing `Down` is equivalent to using `/`.
137    ///
138    /// $f(v, c, r)_i = \operatorname{round}(v_i/c)$, where $\operatorname{round}$ rounds according
139    /// to `rm`.
140    ///
141    /// # Worst-case complexity
142    /// $T(n) = O(n \log n \log\log n)$
143    ///
144    /// $M(n) = O(n \log n)$
145    ///
146    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
147    /// elements and of `c`.
148    ///
149    /// # Panics
150    /// Panics if `c` is zero, or if `rm` is `Exact` and some element is not divisible by `c`.
151    ///
152    /// # Examples
153    /// See [here](super::entrywise_div_round#entrywise_div_round).
154    ///
155    /// With `rm` equal to `Floor`, this is equivalent to `_fmpz_vec_scalar_fdiv_q_fmpz` from
156    /// `fmpz_vec/scalar.c`, FLINT 3.6.0.
157    fn entrywise_div_round(self, c: &Integer, rm: RoundingMode) -> IntegerVector {
158        IntegerVector {
159            elements: match *c {
160                integer_zero!() => panic!("division by zero"),
161                integer_one!() => self.elements.clone(),
162                integer_negative_one!() => self.elements.iter().map(|x| -x).collect(),
163                _ => self.elements.iter().map(|x| x.div_round(c, rm).0).collect(),
164            },
165        }
166    }
167}
168
169impl EntrywiseDivRoundAssign<Integer> for IntegerVector {
170    /// Divides every element of an [`IntegerVector`] by an [`Integer`], in place, taking the scalar
171    /// by value, and rounds every quotient according to the specified rounding mode.
172    ///
173    /// Each quotient is rounded as by [`DivRound`], but no [`Ordering`](core::cmp::Ordering) is
174    /// returned, since with `Nearest` different elements may be rounded in different directions.
175    /// Passing `Down` is equivalent to using `/`.
176    ///
177    /// $v_i \gets \operatorname{round}(v_i/c)$, where $\operatorname{round}$ rounds according to
178    /// `rm`.
179    ///
180    /// # Worst-case complexity
181    /// $T(n) = O(n \log n \log\log n)$
182    ///
183    /// $M(n) = O(n \log n)$
184    ///
185    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
186    /// elements and of `c`.
187    ///
188    /// # Panics
189    /// Panics if `c` is zero, or if `rm` is `Exact` and some element is not divisible by `c`.
190    ///
191    /// # Examples
192    /// See [here](super::entrywise_div_round#entrywise_div_round_assign).
193    ///
194    /// With `rm` equal to `Floor`, this is equivalent to `_fmpz_vec_scalar_fdiv_q_fmpz` from
195    /// `fmpz_vec/scalar.c`, FLINT 3.6.0.
196    #[inline]
197    fn entrywise_div_round_assign(&mut self, c: Integer, rm: RoundingMode) {
198        self.entrywise_div_round_assign(&c, rm);
199    }
200}
201
202impl EntrywiseDivRoundAssign<&Integer> for IntegerVector {
203    /// Divides every element of an [`IntegerVector`] by an [`Integer`], in place, taking the scalar
204    /// by reference, and rounds every quotient according to the specified rounding mode.
205    ///
206    /// Each quotient is rounded as by [`DivRound`], but no [`Ordering`](core::cmp::Ordering) is
207    /// returned, since with `Nearest` different elements may be rounded in different directions.
208    /// Passing `Down` is equivalent to using `/`.
209    ///
210    /// $v_i \gets \operatorname{round}(v_i/c)$, where $\operatorname{round}$ rounds according to
211    /// `rm`.
212    ///
213    /// # Worst-case complexity
214    /// $T(n) = O(n \log n \log\log n)$
215    ///
216    /// $M(n) = O(n \log n)$
217    ///
218    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
219    /// elements and of `c`.
220    ///
221    /// # Panics
222    /// Panics if `c` is zero, or if `rm` is `Exact` and some element is not divisible by `c`.
223    ///
224    /// # Examples
225    /// See [here](super::entrywise_div_round#entrywise_div_round_assign).
226    ///
227    /// With `rm` equal to `Floor`, this is equivalent to `_fmpz_vec_scalar_fdiv_q_fmpz` from
228    /// `fmpz_vec/scalar.c`, FLINT 3.6.0.
229    fn entrywise_div_round_assign(&mut self, c: &Integer, rm: RoundingMode) {
230        match *c {
231            integer_zero!() => panic!("division by zero"),
232            integer_one!() => {}
233            integer_negative_one!() => {
234                for x in &mut self.elements {
235                    x.neg_assign();
236                }
237            }
238            _ => {
239                for x in &mut self.elements {
240                    x.div_round_assign(c, rm);
241                }
242            }
243        }
244    }
245}