1#![allow(clippy::suspicious_arithmetic_impl)] use core::ops::{Div, DivAssign, Rem, RemAssign};
4use dashu_base::{DivEuclid, DivRemEuclid, Gcd, Inverse, RemEuclid, UnsignedAbs};
5use dashu_int::{IBig, UBig};
6
7use crate::{
8 error::panic_divide_by_0,
9 helper_macros::{impl_binop_assign_by_taking, impl_binop_with_int, impl_binop_with_macro},
10 rbig::{RBig, Relaxed},
11 repr::Repr,
12};
13
14macro_rules! impl_div_with_rbig {
15 (
16 $a:ident, $b:ident, $c:ident, $d:ident,
17 $ra:ident, $rb:ident, $rc:ident, $rd:ident, $method:ident
18 ) => {{
19 if $rc.is_zero() {
20 panic_divide_by_0()
21 }
22
23 let g_ac = $ra.gcd($rc);
25 let g_bd = $rb.gcd($rd);
26 RBig(Repr {
27 numerator: ($a / &g_ac) * ($d / &g_bd) * $c.sign(),
28 denominator: ($b / g_bd) * ($c.unsigned_abs() / g_ac),
29 })
30 }};
31}
32macro_rules! impl_div_with_relaxed {
33 (
34 $a:ident, $b:ident, $c:ident, $d:ident,
35 $ra:ident, $rb:ident, $rc:ident, $rd:ident, $method:ident
36 ) => {{
37 if $rc.is_zero() {
38 panic_divide_by_0()
39 }
40
41 let _unused = ($ra, $rb, $rd);
42 Relaxed::from_parts($a * $d * $c.sign(), $b * $c.unsigned_abs())
43 }};
44}
45
46impl_binop_with_macro!(impl Div, div, impl_div_with_rbig);
47impl_binop_with_macro!(impl Div for Relaxed, div, impl_div_with_relaxed);
48impl_binop_assign_by_taking!(impl DivAssign for RBig, div_assign, div);
49impl_binop_assign_by_taking!(impl DivAssign for Relaxed, div_assign, div);
50
51macro_rules! impl_rem_with_rbig {
53 (
54 $a:ident, $b:ident, $c:ident, $d:ident,
55 $ra:ident, $rb:ident, $rc:ident, $rd:ident, $method:ident
56 ) => {{
57 let _unused = ($ra, $rc);
58 let g_bd = Gcd::gcd($rb, $rd);
59
60 let ddg = $d / &g_bd;
62 let left = &ddg * $a;
63 let right = $rb / &g_bd * $c.unsigned_abs();
64
65 let (sign, r1) = left.$method(&right).into_parts();
66 let r2 = right - &r1;
67 let rem = if r1 < r2 {
68 IBig::from_parts(sign, r1)
69 } else {
70 IBig::from_parts(-sign, r2)
71 };
72
73 RBig::from_parts(rem, $b * ddg)
74 }};
75}
76macro_rules! impl_rem_with_relaxed {
77 (
78 $a:ident, $b:ident, $c:ident, $d:ident,
79 $ra:ident, $rb:ident, $rc:ident, $rd:ident, $method:ident
80 ) => {{
81 let _unused = ($ra, $rc);
82
83 let (left, right) = ($a * $rd, $c.unsigned_abs() * $rb);
84 let (sign, r1) = left.$method(&right).into_parts();
85 let r2 = right - &r1;
86 let rem = if r1 < r2 {
87 IBig::from_parts(sign, r1)
88 } else {
89 IBig::from_parts(-sign, r2)
90 };
91
92 Relaxed::from_parts(rem, $b * $d)
93 }};
94}
95impl_binop_with_macro!(impl Rem, rem, impl_rem_with_rbig);
96impl_binop_with_macro!(impl Rem for Relaxed, rem, impl_rem_with_relaxed);
97impl_binop_assign_by_taking!(impl RemAssign for RBig, rem_assign, rem);
98impl_binop_assign_by_taking!(impl RemAssign for Relaxed, rem_assign, rem);
99
100macro_rules! impl_rbig_div_ubig {
101 (
102 $a:ident, $b:ident, $i:ident,
103 $ra:ident, $rb:ident, $ri:ident, $method:ident
104 ) => {{
105 if $ri.is_zero() {
106 panic_divide_by_0()
107 }
108
109 let _unused = $rb;
110 let g = $ra.gcd($ri);
111 RBig(Repr {
112 numerator: $a / &g,
113 denominator: $b * ($i / g),
114 })
115 }};
116}
117macro_rules! impl_rbig_div_ibig {
118 (
119 $a:ident, $b:ident, $i:ident,
120 $ra:ident, $rb:ident, $ri:ident, $method:ident
121 ) => {{
122 if $ri.is_zero() {
123 panic_divide_by_0()
124 }
125
126 let _unused = $rb;
127 let g = $ra.gcd($ri);
128 RBig(Repr {
129 numerator: $a / &g * $i.sign(),
130 denominator: $b * ($i.unsigned_abs() / g),
131 })
132 }};
133}
134macro_rules! impl_ubig_or_ibig_div_rbig {
135 (
136 $a:ident, $b:ident, $i:ident,
137 $ra:ident, $rb:ident, $ri:ident, $method:ident
138 ) => {{
139 if $ra.is_zero() {
140 panic_divide_by_0()
141 }
142
143 let _unused = $rb;
144 let g = $ra.gcd($ri);
145 RBig(Repr {
146 numerator: $b * ($i / &g) * $a.sign(),
147 denominator: $a.unsigned_abs() / g,
148 })
149 }};
150}
151impl_binop_with_int!(impl Div<UBig>, div, RBig, impl_rbig_div_ubig);
152impl_binop_with_int!(impl Div<IBig>, div, RBig, impl_rbig_div_ibig);
153impl_binop_with_int!(impl Div for UBig, div, RBig, impl_ubig_or_ibig_div_rbig);
154impl_binop_with_int!(impl Div for IBig, div, RBig, impl_ubig_or_ibig_div_rbig);
155
156macro_rules! impl_relaxed_div_ibig {
157 (
158 $a:ident, $b:ident, $i:ident,
159 $ra:ident, $rb:ident, $ri:ident, $method:ident
160 ) => {{
161 if $ri.is_zero() {
162 panic_divide_by_0()
163 }
164
165 let _unused = ($ra, $rb);
166 Relaxed::from_parts($a * $i.sign(), $b * $i.unsigned_abs())
167 }};
168}
169macro_rules! impl_relaxed_div_ubig {
170 (
171 $a:ident, $b:ident, $i:ident,
172 $ra:ident, $rb:ident, $ri:ident, $method:ident
173 ) => {{
174 if $ri.is_zero() {
175 panic_divide_by_0()
176 }
177
178 let _unused = ($ra, $rb);
179 Relaxed::from_parts($a, $b * $i)
180 }};
181}
182macro_rules! impl_ubig_or_ibig_div_relaxed {
183 (
184 $a:ident, $b:ident, $i:ident,
185 $ra:ident, $rb:ident, $ri:ident, $method:ident
186 ) => {{
187 if $ra.is_zero() {
188 panic_divide_by_0()
189 }
190
191 let _unused = ($ra, $rb, $ri);
192 Relaxed::from_parts($b * $i * $a.sign(), $a.unsigned_abs())
193 }};
194}
195impl_binop_with_int!(impl Div<IBig>, div, Relaxed, impl_relaxed_div_ibig);
196impl_binop_with_int!(impl Div<UBig>, div, Relaxed, impl_relaxed_div_ubig);
197impl_binop_with_int!(impl Div for UBig, div, Relaxed, impl_ubig_or_ibig_div_relaxed);
198impl_binop_with_int!(impl Div for IBig, div, Relaxed, impl_ubig_or_ibig_div_relaxed);
199
200macro_rules! impl_euclid_div {
201 (
202 $a:ident, $b:ident, $c:ident, $d:ident,
203 $ra:ident, $rb:ident, $rc:ident, $rd:ident, $method:ident
204 ) => {{
205 if $rc.is_zero() {
206 panic_divide_by_0()
207 }
208
209 let _unused = ($ra, $rb, $rd);
210 ($a * $d).$method($b * $c)
211 }};
212}
213impl_binop_with_macro!(impl DivEuclid, div_euclid -> IBig, impl_euclid_div);
214impl_binop_with_macro!(impl DivEuclid for Relaxed, div_euclid -> IBig, impl_euclid_div);
215
216macro_rules! impl_euclid_rem_with_rbig {
217 (
218 $a:ident, $b:ident, $c:ident, $d:ident,
219 $ra:ident, $rb:ident, $rc:ident, $rd:ident, $method:ident
220 ) => {{
221 let _unused = ($ra, $rc);
222 let g_bd = Gcd::gcd($rb, $rd);
223
224 let ddg = $d / &g_bd;
225 let left = &ddg * $a;
226 let right = $rb / &g_bd * $c;
227 RBig::from_parts(left.$method(right).into(), $b * ddg)
228 }};
229}
230macro_rules! impl_euclid_rem_with_relaxed {
231 (
232 $a:ident, $b:ident, $c:ident, $d:ident,
233 $ra:ident, $rb:ident, $rc:ident, $rd:ident, $method:ident
234 ) => {{
235 let _unused = ($ra, $rc);
236
237 let (left, right) = ($a * $rd, $c * $rb);
238 Relaxed::from_parts(left.$method(right).into(), $b * $d)
239 }};
240}
241impl_binop_with_macro!(impl RemEuclid, rem_euclid, impl_euclid_rem_with_rbig);
242impl_binop_with_macro!(impl RemEuclid for Relaxed, rem_euclid, impl_euclid_rem_with_relaxed);
243
244macro_rules! impl_euclid_divrem_with_rbig {
245 (
246 $a:ident, $b:ident, $c:ident, $d:ident,
247 $ra:ident, $rb:ident, $rc:ident, $rd:ident, $method:ident
248 ) => {{
249 let _unused = ($ra, $rc);
250 let g_bd = Gcd::gcd($rb, $rd);
251
252 let ddg = $d / &g_bd;
253 let left = &ddg * $a;
254 let right = $rb / &g_bd * $c;
255 let (q, r) = left.$method(right).into();
256 (q, RBig::from_parts(r.into(), $b * ddg))
257 }};
258}
259macro_rules! impl_euclid_divrem_with_relaxed {
260 (
261 $a:ident, $b:ident, $c:ident, $d:ident,
262 $ra:ident, $rb:ident, $rc:ident, $rd:ident, $method:ident
263 ) => {{
264 let _unused = ($ra, $rc);
265
266 let (left, right) = ($a * $rd, $c * $rb);
267 let (q, r) = left.$method(right).into();
268 (q, Relaxed::from_parts(r.into(), $b * $d))
269 }};
270}
271impl_binop_with_macro!(impl DivRemEuclid for RBig, div_rem_euclid, OutputDiv = IBig, OutputRem = RBig, impl_euclid_divrem_with_rbig);
272impl_binop_with_macro!(impl DivRemEuclid for Relaxed, div_rem_euclid, OutputDiv = IBig, OutputRem = Relaxed, impl_euclid_divrem_with_relaxed);
273
274impl Inverse for Repr {
275 type Output = Repr;
276
277 #[inline]
278 fn inv(self) -> Repr {
279 let (sign, num) = self.numerator.into_parts();
280 Repr {
281 numerator: IBig::from_parts(sign, self.denominator),
282 denominator: num,
283 }
284 }
285}
286
287impl Inverse for RBig {
288 type Output = RBig;
289 #[inline]
290 fn inv(self) -> RBig {
291 RBig(self.0.inv())
292 }
293}
294
295impl Inverse for &RBig {
296 type Output = RBig;
297 #[inline]
298 fn inv(self) -> RBig {
299 RBig(self.0.clone().inv())
300 }
301}
302
303impl Inverse for Relaxed {
304 type Output = Relaxed;
305 #[inline]
306 fn inv(self) -> Relaxed {
307 Relaxed(self.0.inv())
308 }
309}
310
311impl Inverse for &Relaxed {
312 type Output = Relaxed;
313 #[inline]
314 fn inv(self) -> Relaxed {
315 Relaxed(self.0.clone().inv())
316 }
317}