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}