Skip to main content

relp_num/rational/big/
with_one.rs

1use std::cmp::Ordering;
2use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
3
4use num_traits::Zero;
5
6use crate::Sign;
7use crate::fixed::One;
8use crate::integer::big::ops::non_zero::{add_assign, is_one_non_zero, subtracting_cmp};
9use crate::rational::big::Big;
10
11impl<const S: usize> From<One> for Big<S> {
12    #[inline]
13    fn from(_: One) -> Self {
14        num_traits::One::one()
15    }
16}
17
18impl<const S: usize> From<&One> for Big<S> {
19    #[inline]
20    fn from(_: &One) -> Self {
21        num_traits::One::one()
22    }
23}
24
25impl<const S: usize> Add<One> for Big<S> {
26    type Output = Self;
27
28    #[inline]
29    fn add(mut self, _: One) -> Self::Output {
30        <Self as AddAssign<One>>::add_assign(&mut self, One);
31        self
32    }
33}
34
35impl<const S: usize> Add<&One> for Big<S> {
36    type Output = Self;
37
38    #[inline]
39    fn add(mut self, _: &One) -> Self::Output {
40        <Self as AddAssign<&One>>::add_assign(&mut self, &One);
41        self
42    }
43}
44
45impl<const S: usize> AddAssign<One> for Big<S> {
46    #[inline]
47    fn add_assign(&mut self, _: One) {
48        AddAssign::add_assign(self, &One);
49    }
50}
51
52impl<const S: usize> AddAssign<&One> for Big<S> {
53    #[inline]
54    fn add_assign(&mut self, _: &One) {
55        match self.sign {
56            Sign::Positive => unsafe {
57                // SAFETY: Well formed and non zero
58                add_assign(self.numerator.inner_mut(), self.denominator.inner());
59            },
60            Sign::Zero => {
61                self.sign = Sign::Positive;
62                debug_assert!(self.numerator.is_zero());
63                num_traits::One::set_one(&mut self.numerator);
64                debug_assert!(num_traits::One::is_one(&self.denominator));
65            }
66            Sign::Negative => {
67                // `-a/b + 1 == 0` requires `a == b`, which in lowest terms means both are one.
68                // Testing only one of the two would cancel values such as `-1/2` and `-2`.
69                let is_minus_one = unsafe {
70                    // SAFETY: Both are well formed and non zero
71                    is_one_non_zero(self.numerator.inner())
72                        && is_one_non_zero(self.denominator.inner())
73                };
74                if is_minus_one {
75                    self.set_zero();
76                } else {
77                    unsafe {
78                        let sign_change = subtracting_cmp(
79                            self.numerator.inner_mut(), self.denominator.inner(),
80                        );
81                        debug_assert_ne!(
82                            sign_change, Ordering::Equal,
83                            "only -1 + 1 cancels, and that was handled above",
84                        );
85                        if sign_change == Ordering::Less {
86                            self.sign = Sign::Positive;
87                        }
88                    }
89                }
90            }
91        }
92    }
93}
94
95impl<const S: usize> Sub<One> for Big<S> {
96    type Output = Self;
97
98    #[inline]
99    fn sub(mut self, _: One) -> Self::Output {
100        SubAssign::sub_assign(&mut self, One);
101        self
102    }
103}
104
105impl<const S: usize> Sub<&One> for Big<S> {
106    type Output = Self;
107
108    #[inline]
109    fn sub(mut self, _: &One) -> Self::Output {
110        SubAssign::sub_assign(&mut self, One);
111        self
112    }
113}
114
115impl<const S: usize> SubAssign<One> for Big<S> {
116    #[inline]
117    fn sub_assign(&mut self, _: One) {
118        SubAssign::sub_assign(self, &One);
119    }
120}
121
122impl<const S: usize> SubAssign<&One> for Big<S> {
123    #[inline]
124    fn sub_assign(&mut self, _: &One) {
125        match self.sign {
126            Sign::Positive => {
127                let numerator_is_one = unsafe { is_one_non_zero(self.numerator.inner()) };
128                if !numerator_is_one || !num_traits::One::is_one(&self.denominator) {
129                    let direction = unsafe {
130                        subtracting_cmp(self.numerator.inner_mut(), self.denominator.inner())
131                    };
132                    if direction == Ordering::Less {
133                        self.sign = Sign::Negative;
134                    }
135                } else {
136                    self.set_zero();
137                }
138            }
139            Sign::Zero => {
140                self.sign = Sign::Negative;
141                debug_assert!(self.numerator.is_empty());
142                unsafe {
143                    // SAFETY: Value was empty before
144                    self.numerator.inner_mut().push(1);
145                }
146                debug_assert_eq!(self.denominator[0], 1);
147                debug_assert_eq!(self.denominator.len(), 1);
148            }
149            Sign::Negative => unsafe {
150                // SAFETY: Both are well-formed and non zero
151                add_assign(self.numerator.inner_mut(), &self.denominator)
152            },
153        }
154    }
155}
156
157impl<const S: usize> Mul<One> for Big<S> {
158    type Output = Self;
159
160    #[inline]
161    fn mul(self, _: One) -> Self::Output {
162        self
163    }
164}
165
166impl<const S: usize> Mul<&One> for Big<S> {
167    type Output = Self;
168
169    #[inline]
170    fn mul(self, _: &One) -> Self::Output {
171        self
172    }
173}
174
175impl<const S: usize> Mul<One> for &Big<S> {
176    type Output = Big<S>;
177
178    #[inline]
179    fn mul(self, _: One) -> Self::Output {
180        self.clone()
181    }
182}
183
184impl<const S: usize> Mul<&One> for &Big<S> {
185    type Output = Big<S>;
186
187    #[inline]
188    fn mul(self, _: &One) -> Self::Output {
189        self.clone()
190    }
191}
192
193impl<const S: usize> MulAssign<One> for Big<S> {
194    #[inline]
195    fn mul_assign(&mut self, _: One) {
196    }
197}
198
199impl<const S: usize> MulAssign<&One> for Big<S> {
200    #[inline]
201    fn mul_assign(&mut self, _: &One) {
202    }
203}
204
205impl<const S: usize> Div<One> for Big<S> {
206    type Output = Self;
207
208    #[inline]
209    fn div(self, _: One) -> Self::Output {
210        self
211    }
212}
213
214impl<const S: usize> Div<&One> for Big<S> {
215    type Output = Self;
216
217    #[inline]
218    fn div(self, _: &One) -> Self::Output {
219        self
220    }
221}
222
223impl<const S: usize> Div<One> for &Big<S> {
224    type Output = Big<S>;
225
226    #[inline]
227    fn div(self, _: One) -> Self::Output {
228        self.clone()
229    }
230}
231
232impl<const S: usize> Div<&One> for &Big<S> {
233    type Output = Big<S>;
234
235    #[inline]
236    fn div(self, _: &One) -> Self::Output {
237        self.clone()
238    }
239}
240
241impl<const S: usize> DivAssign<One> for Big<S> {
242    #[inline]
243    fn div_assign(&mut self, _: One) {
244    }
245}
246
247impl<const S: usize> DivAssign<&One> for Big<S> {
248    #[inline]
249    fn div_assign(&mut self, _: &One) {
250    }
251}
252
253#[cfg(test)]
254mod test {
255    use crate::fixed::One;
256    use crate::{R8, RB, Rational8, RationalBig};
257
258    /// `-a/b + 1` is zero only when `a == b == 1`; every other negative value must survive.
259    ///
260    /// The guard used to fire whenever the numerator *or* the denominator was one, so values
261    /// such as `-1/2` and `-2` were silently collapsed to zero.
262    #[test]
263    fn add_one_to_negative() {
264        assert_eq!(RB!(-1) + One, RB!(0));
265        assert_eq!(RB!(-1, 2) + One, RB!(1, 2));
266        assert_eq!(RB!(-2) + One, RB!(-1));
267        assert_eq!(RB!(-3) + One, RB!(-2));
268        assert_eq!(RB!(-3, 2) + One, RB!(-1, 2));
269        assert_eq!(RB!(-1, 3) + One, RB!(2, 3));
270        assert_eq!(RB!(-5, 4) + One, RB!(-1, 4));
271        assert_eq!(RB!(-7, 3) + One, RB!(-4, 3));
272    }
273
274    /// The arbitrary precision and the fixed size implementations must agree.
275    #[test]
276    fn add_one_agrees_with_small() {
277        for numerator in -6_i8..=6 {
278            for denominator in 1_u8..=6 {
279                let small = Rational8::new(numerator, denominator).unwrap();
280                assert_eq!(
281                    RationalBig::from(small) + One,
282                    RationalBig::from(small + One),
283                    "{numerator}/{denominator} + 1",
284                );
285            }
286        }
287        assert_eq!(RB!(-1, 2) + One, RationalBig::from(R8!(-1, 2) + One));
288    }
289}