dashu_ratio/
add.rs

1#![allow(clippy::suspicious_arithmetic_impl)] // Clippy doesn't like that add/sub is implemented with mul.
2
3use 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        // a/b ± c/d = (ad ± bc)/bd
22        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    // sub is not commutative
76    (
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);