1#![allow(clippy::suspicious_arithmetic_impl)] use core::ops::{Add, AddAssign, Sub, SubAssign};
4use dashu_base::Gcd;
5use dashu_int::{IBig, UBig};
6
7use crate::{
8 helper_macros::{impl_binop_assign_by_taking, impl_binop_with_int, impl_binop_with_macro},
9 rbig::{RBig, Relaxed},
10 repr::Repr,
11};
12
13macro_rules! impl_add_or_sub_with_rbig {
14 (
15 $a:ident, $b:ident, $c:ident, $d:ident,
16 $ra:ident, $rb:ident, $rc:ident, $rd:ident, $method:ident
17 ) => {{
18 let _unused = ($ra, $rc);
19 let g_bd = Gcd::gcd($rb, $rd);
20
21 let repr = if g_bd.is_one() {
23 let left = $a * $rd;
24 let right = $c * $rb;
25 Repr {
26 numerator: left.$method(right),
27 denominator: $b * $d,
28 }
29 } else {
30 let ddg = $d / &g_bd;
31 let left = &ddg * $a;
32 let right = $rb / &g_bd * $c;
33 Repr {
34 numerator: left.$method(right),
35 denominator: $b * ddg,
36 }
37 .reduce_with_hint(g_bd)
38 };
39
40 RBig(repr)
41 }};
42}
43impl_binop_with_macro!(impl Add, add, impl_add_or_sub_with_rbig);
44impl_binop_with_macro!(impl Sub, sub, impl_add_or_sub_with_rbig);
45impl_binop_assign_by_taking!(impl AddAssign for RBig, add_assign, add);
46impl_binop_assign_by_taking!(impl SubAssign for RBig, sub_assign, sub);
47
48macro_rules! impl_addsub_with_relaxed {
49 (
50 $a:ident, $b:ident, $c:ident, $d:ident,
51 $ra:ident, $rb:ident, $rc:ident, $rd:ident, $method:ident
52 ) => {{
53 let _unused = ($ra, $rc);
54 Relaxed::from_parts(($a * $rd).$method($c * $rb), $b * $d)
55 }};
56}
57impl_binop_with_macro!(impl Add for Relaxed, add, impl_addsub_with_relaxed);
58impl_binop_with_macro!(impl Sub for Relaxed, sub, impl_addsub_with_relaxed);
59impl_binop_assign_by_taking!(impl AddAssign for Relaxed, add_assign, add);
60impl_binop_assign_by_taking!(impl SubAssign for Relaxed, sub_assign, sub);
61
62macro_rules! impl_add_or_sub_int_with_rbig {
63 (
64 $a:ident, $b:ident, $i:ident,
65 $ra:ident, $rb:ident, $ri:ident, $method:ident
66 ) => {{
67 let _unused = ($ra, $ri);
68 RBig(Repr {
69 numerator: $a.$method($rb * $i),
70 denominator: $b,
71 })
72 }};
73}
74macro_rules! impl_int_sub_rbig {
75 (
77 $a:ident, $b:ident, $i:ident,
78 $ra:ident, $rb:ident, $ri:ident, $method:ident
79 ) => {{
80 let _unused = ($ra, $ri);
81 RBig(Repr {
82 numerator: ($rb * $i).$method($a),
83 denominator: $b,
84 })
85 }};
86}
87impl_binop_with_int!(impl Add<UBig>, add, impl_add_or_sub_int_with_rbig);
88impl_binop_with_int!(impl Add<IBig>, add, impl_add_or_sub_int_with_rbig);
89impl_binop_with_int!(impl Sub<UBig>, sub, impl_add_or_sub_int_with_rbig);
90impl_binop_with_int!(impl Sub<IBig>, sub, impl_add_or_sub_int_with_rbig);
91impl_binop_with_int!(impl Add for UBig, add, impl_add_or_sub_int_with_rbig);
92impl_binop_with_int!(impl Add for IBig, add, impl_add_or_sub_int_with_rbig);
93impl_binop_with_int!(impl Sub for UBig, sub, impl_int_sub_rbig);
94impl_binop_with_int!(impl Sub for IBig, sub, impl_int_sub_rbig);
95
96macro_rules! impl_addsub_int_with_relaxed {
97 (
98 $a:ident, $b:ident, $i:ident,
99 $ra:ident, $rb:ident, $ri:ident, $method:ident
100 ) => {{
101 let _unused = ($ra, $ri);
102 Relaxed(Repr {
103 numerator: $a.$method($rb * $i),
104 denominator: $b,
105 })
106 }};
107}
108macro_rules! impl_int_sub_relaxed {
109 (
110 $a:ident, $b:ident, $i:ident,
111 $ra:ident, $rb:ident, $ri:ident, $method:ident
112 ) => {{
113 let _unused = ($ra, $ri);
114 Relaxed(Repr {
115 numerator: ($rb * $i).$method($a),
116 denominator: $b,
117 })
118 }};
119}
120impl_binop_with_int!(impl Add<UBig>, add, Relaxed, impl_addsub_int_with_relaxed);
121impl_binop_with_int!(impl Add<IBig>, add, Relaxed, impl_addsub_int_with_relaxed);
122impl_binop_with_int!(impl Sub<UBig>, sub, Relaxed, impl_addsub_int_with_relaxed);
123impl_binop_with_int!(impl Sub<IBig>, sub, Relaxed, impl_addsub_int_with_relaxed);
124impl_binop_with_int!(impl Add for UBig, add, Relaxed, impl_addsub_int_with_relaxed);
125impl_binop_with_int!(impl Add for IBig, add, Relaxed, impl_addsub_int_with_relaxed);
126impl_binop_with_int!(impl Sub for UBig, sub, Relaxed, impl_int_sub_relaxed);
127impl_binop_with_int!(impl Sub for IBig, sub, Relaxed, impl_int_sub_relaxed);