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 / g) * $i,
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 / g) * $i.unsigned_abs(),
131 })
132 }};
133}
134impl_binop_with_int!(impl Div<UBig>, div, RBig, impl_rbig_div_ubig);
135impl_binop_with_int!(impl Div<IBig>, div, RBig, impl_rbig_div_ibig);
136
137macro_rules! impl_relaxed_div_ibig {
138 (
139 $a:ident, $b:ident, $i:ident,
140 $ra:ident, $rb:ident, $ri:ident, $method:ident
141 ) => {{
142 if $ri.is_zero() {
143 panic_divide_by_0()
144 }
145
146 let _unused = ($ra, $rb);
147 Relaxed::from_parts($a * $i.sign(), $b * $i.unsigned_abs())
148 }};
149}
150macro_rules! impl_relaxed_div_ubig {
151 (
152 $a:ident, $b:ident, $i:ident,
153 $ra:ident, $rb:ident, $ri:ident, $method:ident
154 ) => {{
155 if $ri.is_zero() {
156 panic_divide_by_0()
157 }
158
159 let _unused = ($ra, $rb);
160 Relaxed::from_parts($a, $b * $i)
161 }};
162}
163impl_binop_with_int!(impl Div<IBig>, div, Relaxed, impl_relaxed_div_ibig);
164impl_binop_with_int!(impl Div<UBig>, div, Relaxed, impl_relaxed_div_ubig);
165
166macro_rules! impl_euclid_div {
167 (
168 $a:ident, $b:ident, $c:ident, $d:ident,
169 $ra:ident, $rb:ident, $rc:ident, $rd:ident, $method:ident
170 ) => {{
171 if $rc.is_zero() {
172 panic_divide_by_0()
173 }
174
175 let _unused = ($ra, $rb, $rd);
176 ($a * $d).$method($b * $c)
177 }};
178}
179impl_binop_with_macro!(impl DivEuclid, div_euclid -> IBig, impl_euclid_div);
180impl_binop_with_macro!(impl DivEuclid for Relaxed, div_euclid -> IBig, impl_euclid_div);
181
182macro_rules! impl_euclid_rem_with_rbig {
183 (
184 $a:ident, $b:ident, $c:ident, $d:ident,
185 $ra:ident, $rb:ident, $rc:ident, $rd:ident, $method:ident
186 ) => {{
187 let _unused = ($ra, $rc);
188 let g_bd = Gcd::gcd($rb, $rd);
189
190 let ddg = $d / &g_bd;
191 let left = &ddg * $a;
192 let right = $rb / &g_bd * $c;
193 RBig::from_parts(left.$method(right).into(), $b * ddg)
194 }};
195}
196macro_rules! impl_euclid_rem_with_relaxed {
197 (
198 $a:ident, $b:ident, $c:ident, $d:ident,
199 $ra:ident, $rb:ident, $rc:ident, $rd:ident, $method:ident
200 ) => {{
201 let _unused = ($ra, $rc);
202
203 let (left, right) = ($a * $rd, $c * $rb);
204 Relaxed::from_parts(left.$method(right).into(), $b * $d)
205 }};
206}
207impl_binop_with_macro!(impl RemEuclid, rem_euclid, impl_euclid_rem_with_rbig);
208impl_binop_with_macro!(impl RemEuclid for Relaxed, rem_euclid, impl_euclid_rem_with_relaxed);
209
210macro_rules! impl_euclid_divrem_with_rbig {
211 (
212 $a:ident, $b:ident, $c:ident, $d:ident,
213 $ra:ident, $rb:ident, $rc:ident, $rd:ident, $method:ident
214 ) => {{
215 let _unused = ($ra, $rc);
216 let g_bd = Gcd::gcd($rb, $rd);
217
218 let ddg = $d / &g_bd;
219 let left = &ddg * $a;
220 let right = $rb / &g_bd * $c;
221 let (q, r) = left.$method(right).into();
222 (q, RBig::from_parts(r.into(), $b * ddg))
223 }};
224}
225macro_rules! impl_euclid_divrem_with_relaxed {
226 (
227 $a:ident, $b:ident, $c:ident, $d:ident,
228 $ra:ident, $rb:ident, $rc:ident, $rd:ident, $method:ident
229 ) => {{
230 let _unused = ($ra, $rc);
231
232 let (left, right) = ($a * $rd, $c * $rb);
233 let (q, r) = left.$method(right).into();
234 (q, Relaxed::from_parts(r.into(), $b * $d))
235 }};
236}
237impl_binop_with_macro!(impl DivRemEuclid for RBig, div_rem_euclid, OutputDiv = IBig, OutputRem = RBig, impl_euclid_divrem_with_rbig);
238impl_binop_with_macro!(impl DivRemEuclid for Relaxed, div_rem_euclid, OutputDiv = IBig, OutputRem = Relaxed, impl_euclid_divrem_with_relaxed);
239
240impl Inverse for Repr {
241 type Output = Repr;
242
243 #[inline]
244 fn inv(self) -> Repr {
245 let (sign, num) = self.numerator.into_parts();
246 Repr {
247 numerator: IBig::from_parts(sign, self.denominator),
248 denominator: num,
249 }
250 }
251}
252
253impl Inverse for RBig {
254 type Output = RBig;
255 #[inline]
256 fn inv(self) -> RBig {
257 RBig(self.0.inv())
258 }
259}
260
261impl Inverse for &RBig {
262 type Output = RBig;
263 #[inline]
264 fn inv(self) -> RBig {
265 RBig(self.0.clone().inv())
266 }
267}
268
269impl Inverse for Relaxed {
270 type Output = Relaxed;
271 #[inline]
272 fn inv(self) -> Relaxed {
273 Relaxed(self.0.inv())
274 }
275}
276
277impl Inverse for &Relaxed {
278 type Output = Relaxed;
279 #[inline]
280 fn inv(self) -> Relaxed {
281 Relaxed(self.0.clone().inv())
282 }
283}