1use std::fmt;
3use std::fmt::Display;
4use std::ops::Neg;
5
6use crate::integer::big::ops::normalize::gcd_scalar;
7use crate::Negateable;
8use crate::non_zero::NonZeroSign;
9use crate::rational::Ratio;
10use crate::sign::Sign;
11
12mod io;
13pub(crate) mod ops;
14
15macro_rules! rational {
16 ($name:ident, $ity:ty, $uty:ty) => {
17 pub type $name = Ratio<Sign, $uty, $uty>;
19
20 impl Neg for $name {
21 type Output = Self;
22
23 #[must_use]
24 #[inline]
25 fn neg(mut self) -> Self::Output {
26 Negateable::negate(&mut self.sign);
27 self
28 }
29 }
30
31 impl Neg for &$name {
32 type Output = $name;
33
34 #[must_use]
35 #[inline]
36 fn neg(self) -> Self::Output {
37 Self::Output {
38 sign: !self.sign,
39 numerator: self.numerator,
40 denominator: self.denominator,
41 }
42 }
43 }
44
45 impl PartialEq for $name {
46 fn eq(&self, other: &Self) -> bool {
47 match (self.sign, other.sign) {
48 (Sign::Positive, Sign::Negative) |
49 (Sign::Negative, Sign::Positive) => false,
50 (Sign::Zero, Sign::Zero) => true,
51 (Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => {
52 self.numerator == other.numerator && self.denominator == other.denominator
53 }
54 (Sign::Zero, Sign::Positive | Sign::Negative) |
55 (Sign::Positive | Sign::Negative, Sign::Zero) => false,
56 }
57 }
58 }
59 impl Eq for $name {}
60
61 impl Display for $name {
62 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63 match self.sign {
64 Sign::Positive => {}
65 Sign::Zero => return write!(f, "0"),
66 Sign::Negative => {
67 write!(f, "-")?;
68 }
69 }
70
71 write!(f, "{}", self.numerator)?;
72 if self.denominator != 1 {
73 write!(f, "/")?;
74 write!(f, "{}", self.denominator)?;
75 }
76
77 fmt::Result::Ok(())
78 }
79 }
80 }
81}
82rational!(Rational8, i8, u8);
83rational!(Rational16, i16, u16);
84rational!(Rational32, i32, u32);
85rational!(Rational64, i64, u64);
86rational!(RationalUsize, isize, usize);
87rational!(Rational128, i128, u128);
88
89macro_rules! rational_non_zero {
90 ($name:ident, $ity:ty, $uty:ty) => {
91 pub type $name = Ratio<NonZeroSign, $uty, $uty>;
93
94 impl PartialEq for $name {
95 fn eq(&self, other: &Self) -> bool {
96 self.numerator == other.numerator &&
97 self.denominator == other.denominator &&
98 self.sign == other.sign
99 }
100 }
101 impl Eq for $name {}
102 }
103}
104rational_non_zero!(NonZeroRational8, i8, u8);
105rational_non_zero!(NonZeroRational16, i16, u16);
106rational_non_zero!(NonZeroRational32, i32, u32);
107rational_non_zero!(NonZeroRational64, i64, u64);
108rational_non_zero!(NonZeroRational128, i128, u128);
109rational_non_zero!(NonZeroRationalUsize, isize, usize);
110
111#[cfg(test)]
112mod test {
113 use std::cmp::Ordering;
114 use std::str::FromStr;
115
116 use num_traits::{FromPrimitive, One, Zero};
117
118 use crate::{NonZero, NonZeroSign, NonZeroSigned, Rational128};
119 use crate::{R16, R32, R64, R8};
120 use crate::rational::{Ratio, Rational16, Rational32, Rational64, Rational8, Sign};
121
122 #[test]
123 fn test_new() {
124 assert_eq!(R8!(0, 2), Ratio { sign: Sign::Zero, numerator: 0_u8, denominator: 1 });
125 assert_eq!(R8!(2, 2), Ratio { sign: Sign::Positive, numerator: 1, denominator: 1 });
126 assert_eq!(R8!(6, 2), Ratio { sign: Sign::Positive, numerator: 3, denominator: 1 });
127 assert_eq!(R8!(-6, 2), Ratio { sign: Sign::Negative, numerator: 3, denominator: 1 });
128 }
129
130 #[test]
131 fn test_from() {
132 assert_eq!(<Rational8 as From<_>>::from(1_u8), Rational8::one());
133 assert_eq!(<Rational32 as From<_>>::from(1), Rational32::one());
134
135 assert_eq!(FromPrimitive::from_u64(16), Some(R8!(16)));
136 assert_eq!(FromPrimitive::from_u16(0), Some(Rational8::zero()));
137 assert_eq!(<Rational16 as FromPrimitive>::from_u32(u32::MAX), None);
138 assert_eq!(FromPrimitive::from_i32(i32::MAX), Some(R32!(i32::MAX, 1)));
139 assert_eq!(<Rational64 as FromPrimitive>::from_i128(i128::MAX), None);
140 assert_eq!(FromPrimitive::from_i16(-1), Some(R8!(-2, 2)));
141
142 assert_eq!(<Rational128 as FromPrimitive>::from_f64(f64::NAN), None);
143 assert_eq!(<Rational64 as FromPrimitive>::from_f64(f64::INFINITY), None);
144 assert_eq!(<Rational32 as FromPrimitive>::from_f64(f64::NEG_INFINITY), None);
145 assert_eq!(FromPrimitive::from_f64(-0_f64), Some(Rational8::zero()));
146 assert!(<Rational128 as FromPrimitive>::from_f64(u128::MAX as f64).is_none());
148
149 assert_eq!(<Rational32 as FromPrimitive>::from_i64(i64::MAX), None);
150
151 assert_eq!(Rational64::from((-1, 2)), R64!(-1, 2));
152 }
153
154 #[test]
155 fn test_nonzero() {
156 assert!(!Rational8::zero().is_not_zero());
157 assert_eq!(Rational16::zero().is_zero(), !Rational16::zero().is_not_zero());
158
159 assert_eq!(R8!(1).non_zero_signum(), NonZeroSign::Positive);
160 }
161
162 #[test]
163 #[should_panic]
164 fn test_sign_panic() {
165 R8!(0).non_zero_signum();
166 }
167
168 #[test]
169 fn test_one() {
170 assert!(Rational64::zero() < Rational64::one());
171 assert!(Rational64::one().is_one());
172 let mut x = Rational32::zero();
173 x.set_one();
174 assert_eq!(x, Rational32::one());
175 }
176
177 #[test]
178 fn test_cmp() {
179 assert!(R8!(12) < R8!(13));
180 assert!(R8!(1, 2) > R8!(1, 3));
181 assert_eq!(R8!(7, 11), R8!(7, 11));
182 assert!(R8!(3, 4) < R8!(5, 6));
183 assert!(R8!(13) > R8!(12));
184 assert_eq!(R32!(0), R32!(0));
185 assert_eq!(R32!(0).partial_cmp(&R32!(0)), Some(Ordering::Equal));
186 assert_eq!(R32!(12, 5).partial_cmp(&R32!(23, 10)), Some(Ordering::Greater));
187 assert!(!(R32!(7, 11) < R32!(7, 11)));
188 assert!(R64!(-3, 11) < R64!(3, 11));
189 assert_ne!(R64!(-9, 4), R64!(9, 4));
190
191 assert!(R8!(-3) < R8!(-2));
192 assert!(R8!(-3) < R8!(0));
193 assert!(R8!(-3) < R8!(2));
194 assert!(R8!(-3) < R8!(3));
195
196 assert!(Rational8::from_str("255/2").unwrap() < R8!(128));
197 }
198
199 #[test]
200 fn test_eq() {
201 assert_eq!(R8!(3), R8!(3));
202 assert_eq!(R8!(0), R8!(0));
203 assert_eq!(R8!(-1), R8!(-1));
204 assert_ne!(R8!(-1), R8!(0));
205 assert_ne!(R8!(-1), R8!(1));
206 assert_ne!(R8!(0), R8!(1));
207 }
208
209 #[test]
210 fn test_add() {
211 assert_eq!(Rational64::one() + Rational64::one(), R64!(2));
212 assert_eq!(R64!(3, 2) + R64!(3, 2), R64!(3));
213 assert_eq!(R64!(-3, 2) + R64!(3, 2), Rational64::zero());
214 assert_eq!(R64!(948, 64) + Rational64::zero(), R64!(948, 64));
215 assert_eq!(-Rational64::one() + Rational64::one(), Rational64::zero());
216 assert_eq!(Rational128::zero() + Rational128::one(), Rational128::one());
217 assert_eq!(Rational128::zero() + -Rational128::one(), -Rational128::one());
218
219 assert_eq!(&R32!(3, 9) + &R32!(-1, 3), R32!(0));
220 assert_eq!(R8!(4, 5) + R8!(1, 5), R8!(1));
221 assert_eq!(R8!(5, 1) + R8!(3, 2), R8!(13, 2));
222 assert_eq!(R8!(3, 4) + R8!(3), R8!(15, 4));
223 assert_eq!(R8!(3, 4) + R8!(17, 5), R8!(83, 20));
224 assert_eq!(R32!(3, 4) + R32!(3, 32), R32!(27, 32));
225 assert_eq!(R32!(-10) + R32!(9), R32!(-1));
226
227 let limit = 10;
228 for a in -limit..limit {
229 for b in 1..limit {
230 for c in -limit..limit {
231 for d in 1..limit {
232 assert_eq!(R32!(a, b as u32) + R32!(c, d as u32), R32!(a * d + c * b, b as u32 * d as u32), "{} / {} + {} / {}", a, b, c, d);
233 }
234 }
235 }
236 }
237 }
238
239 #[test]
240 fn test_sum() {
241 assert_eq!((0..10).map(Rational32::from).sum::<Rational32>(), R32!(45));
242 assert_eq!((0_i16..10).map(|i| Rational16::new(i, 2).unwrap()).sum::<Rational16>(), R16!(45, 2));
243 let vs = vec![
244 (R32!(23, 31), R32!(-699, 65)),
245 (R32!(29, 31), R32!(-30736, 1885)),
246 ];
247 let product = vs.into_iter().map(|(a, b)| &a * &b).sum::<Rational32>();
248 let constant = R32!(-2826, 155);
249 assert_eq!(constant - product, R32!(5));
250 }
251
252 #[test]
253 fn test_sub() {
254 assert_eq!(Rational64::one() - Rational64::one(), R64!(0));
255 assert_eq!(R64!(3, 2) - R64!(3, 2), R64!(0));
256 assert_eq!(R64!(-3, 2) - R64!(3, 2), -R64!(3));
257 assert_eq!(R64!(948, 64) - Rational64::zero(), R64!(948, 64));
258 assert_eq!(-Rational64::one() - Rational64::one(), -R64!(2));
259 assert_eq!(Rational64::one() - Rational64::one(), -R64!(0));
260 assert_eq!(Rational128::zero() - Rational128::one(), -Rational128::one());
261 assert_eq!(Rational128::zero() - -Rational128::one(), Rational128::one());
262
263 assert_eq!(&R32!(3, 9) - &R32!(1, 3), R32!(0));
264 assert_eq!(R8!(4, 5) - R8!(1, 5), R8!(3, 5));
265 assert_eq!(R8!(5, 1) - R8!(3, 2), R8!(7, 2));
266 assert_eq!(R8!(3, 4) - R8!(3), R8!(-9, 4));
267 assert_eq!(R8!(3, 4) - R8!(17, 5), R8!(15 - 4 * 17, 20));
268 assert_eq!(R8!(17, 5) - R8!(3, 4), R8!(4 * 17 - 15, 20));
269
270 assert_eq!(R32!(3601, 155) - R32!(2826, 155), R32!(5));
271 assert_eq!(R32!(-2826, 155) - R32!(-3601, 155), R32!(5));
272
273 let limit = 10;
274 for a in -limit..limit {
275 for b in 1..limit {
276 for c in -limit..limit {
277 for d in 1..limit {
278 assert_eq!(R32!(a, b as u32) - R32!(c, d as u32), R32!(a * d - c * b, b as u32 * d as u32), "{} / {} - {} / {}", a, b, c, d);
279 }
280 }
281 }
282 }
283 }
284
285 #[test]
286 fn test_mul() {
287 assert_eq!(Rational64::one() * Rational64::one(), R64!(1));
288 assert_eq!(R64!(3, 2) * R64!(3, 2), R64!(9, 4));
289 assert_eq!(R64!(-3, 2) * R64!(3, 2), -R64!(9, 4));
290 assert_eq!(R64!(948, 64) * Rational64::zero(), R64!(0));
291 assert_eq!(-Rational64::one() * Rational64::one(), -R64!(1));
292 assert_eq!(Rational64::one() * Rational64::one(), R64!(1));
293 assert_eq!(Rational128::zero() * Rational128::one(), -Rational128::zero());
294 assert_eq!(Rational128::zero() * -Rational128::one(), Rational128::zero());
295
296 assert_eq!(R8!(3, 2) * R8!(4, 9), R8!(2, 3));
297 assert_eq!(R32!(27, 32) * R32!(2), R32!(27, 16));
298
299 let limit = 10;
300 for a in -limit..limit {
301 for b in 1..limit {
302 for c in -limit..limit {
303 for d in 1..limit {
304 assert_eq!(R32!(a, b as u32) * R32!(c, d as u32), R32!(a * c, b as u32 * d as u32), "{} / {} * {} / {}", a, b, c, d);
305 }
306 }
307 }
308 }
309 }
310
311 #[test]
312 fn test_div() {
313 assert_eq!(Rational64::one() / Rational64::one(), R64!(1));
314 assert_eq!(R64!(3, 2) / R64!(3, 2), R64!(1));
315 assert_eq!(R64!(-3, 2) / R64!(3, 2), -R64!(1));
316 assert_eq!(-Rational64::one() / Rational64::one(), -R64!(1));
317 assert_eq!(Rational128::zero() / Rational128::one(), -Rational128::zero());
318 assert_eq!(Rational128::zero() / -Rational128::one(), Rational128::zero());
319 }
320
321 #[test]
322 fn test_new_signed() {
323 assert_eq!(Rational64::new_signed(Sign::Positive, 6, 18), R64!(1, 3));
324 assert_eq!(Rational64::new_signed(Sign::Zero, 0, 6), R64!(0));
325 assert_eq!(Rational64::new_signed(Sign::Negative, 9, 18), -R64!(1, 2));
326 }
327
328 #[test]
329 #[should_panic]
330 fn test_new_signed_panic_1() {
331 Rational64::new_signed(Sign::Zero, 1, 1);
332 }
333
334 #[test]
335 #[should_panic]
336 fn test_new_signed_panic_2() {
337 Rational64::new_signed(Sign::Positive, 0, 1);
338 }
339
340 #[test]
341 fn test_display() {
342 assert_eq!(Rational64::one().to_string(), "1");
343 assert_eq!(Rational64::zero().to_string(), "0");
344 assert_eq!(R64!(1, 2).to_string(), "1/2");
345 assert_eq!(R64!(-1, 2).to_string(), "-1/2");
346 }
347
348 #[test]
349 fn test_from_str() {
350 assert_eq!(Rational8::from_str("8"), Ok(R8!(8)));
351 assert_eq!(Rational8::from_str("-8"), Ok(-R8!(8)));
352 assert_eq!(Rational16::from_str("-16/3"), Ok(R16!(-16, 3)));
353 assert_eq!(Rational16::from_str("16/4"), Ok(R16!(16, 4)));
354 assert_eq!(Rational32::from_str("4294967297"), Err("value was too large for this type"));
355 }
356}