1use std::convert::TryInto;
2use std::fmt;
3use std::str::FromStr;
4
5use num_traits::{One, Zero};
6use num_traits::ToPrimitive;
7
8use crate::non_zero::NonZeroSign;
9use crate::rational::big::Big;
10use crate::rational::small::{Rational128, Rational16, Rational32, Rational64, Rational8, RationalUsize};
11use crate::rational::small::{NonZeroRational128, NonZeroRational16, NonZeroRational32, NonZeroRational64, NonZeroRational8, NonZeroRationalUsize};
12use crate::rational::small::gcd_scalar;
13use crate::rational::small::ops::building_blocks::{simplify128, simplify16, simplify32, simplify64, simplify8, simplify_usize};
14use crate::sign::{Sign, Signed};
15
16macro_rules! signed_floor {
17 ($value:expr, $target:ty) => {
18 {
19 let floor = $value.numerator / $value.denominator;
20 floor.try_into().ok()
21 .map(|value: $target| match $value.sign {
22 Sign::Zero | Sign::Positive => value,
23 Sign::Negative => -value,
24 })
25 }
26 }
27}
28
29macro_rules! unsigned_floor {
30 ($value:expr) => {
31 {
32 match $value.sign {
33 Sign::Zero | Sign::Positive => {
34 let floor = $value.numerator / $value.denominator;
35 floor.try_into().ok()
36 }
37 Sign::Negative => None,
38 }
39 }
40 }
41}
42
43macro_rules! float {
44 ($value:expr, $target:ty) => {
45 {
46 let ratio = $value.numerator as $target / $value.denominator as $target;
47 let signed_ratio = match $value.sign {
48 Sign::Zero | Sign::Positive => ratio,
49 Sign::Negative => -ratio,
50 };
51
52 Some(signed_ratio)
53 }
54 }
55}
56
57macro_rules! creation {
58 ($name:ident, $ity:ty, $uty:ty, $gcd_name:ident, $simplify_name:ident) => {
59 impl $name {
60 #[must_use]
61 pub fn new(numerator: $ity, mut denominator: $uty) -> Option<Self> {
62 if denominator.is_zero() {
63 None
64 } else {
65 Some({
66 let mut numerator_abs = numerator.unsigned_abs();
67 if numerator == 0 {
68 <Self as num_traits::Zero>::zero()
69 } else if numerator_abs == denominator {
70 Self {
71 sign: Signed::signum(&numerator),
72 numerator: 1,
73 denominator: 1,
74 }
75 } else {
76 if numerator_abs != 1 && denominator != 1 {
77 let gcd = gcd_scalar(numerator_abs as usize, denominator as usize) as $uty;
78
79 numerator_abs /= gcd;
80 denominator /= gcd;
81 }
82
83 Self {
84 sign: Signed::signum(&numerator),
85 numerator: numerator_abs,
86 denominator,
87 }
88 }
89 })
90 }
91 }
92 pub fn new_signed<T: Into<Sign>>(sign: T, numerator: $uty, denominator: $uty) -> Self {
93 debug_assert_ne!(denominator, 0);
94 let sign = sign.into();
95 debug_assert!((numerator == 0) == (sign == Sign::Zero));
96
97 match sign {
98 Sign::Positive => debug_assert_ne!(numerator, 0),
99 Sign::Zero => {
100 debug_assert_eq!(numerator, 0);
101 return <Self as num_traits::Zero>::zero();
102 },
103 Sign::Negative => {}
104 }
105
106 let (numerator, denominator) = $simplify_name(numerator, denominator);
107
108 Self {
109 sign,
110 numerator,
111 denominator,
112 }
113 }
114 }
115
116 impl Default for $name {
117 fn default() -> Self {
118 Self::zero()
119 }
120 }
121
122 impl fmt::Debug for $name {
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 match self.sign {
125 Sign::Positive => {}
126 Sign::Zero => return f.write_str("0"),
127 Sign::Negative => f.write_str("-")?,
128 }
129
130 fmt::Debug::fmt(&self.numerator, f)?;
131 if !self.denominator.is_one() {
132 f.write_str(" / ")?;
133 fmt::Debug::fmt(&self.denominator, f)?;
134 }
135
136 Ok(())
137 }
138 }
139
140 impl num_traits::FromPrimitive for $name {
141 #[inline]
142 fn from_i64(n: i64) -> Option<Self> {
143 if n.unsigned_abs() <= <$uty>::MAX as u64 {
144 Some(Self {
145 sign: Signed::signum(&n),
146 numerator: n.unsigned_abs() as $uty,
147 denominator: 1,
148 })
149 } else {
150 None
151 }
152 }
153
154 #[inline]
155 fn from_u64(n: u64) -> Option<Self> {
156 if n <= <$uty>::MAX as u64 {
157 Some(Self {
158 sign: Signed::signum(&n),
159 numerator: n as $uty,
160 denominator: 1,
161 })
162 } else {
163 None
164 }
165 }
166
167 #[inline]
168 fn from_f32(n: f32) -> Option<Self> {
169 Big::<8>::from_f32(n).map(Self::from_big_if_it_fits).flatten()
170 }
171
172 #[inline]
173 fn from_f64(n: f64) -> Option<Self> {
174 Big::<16>::from_f64(n).map(Self::from_big_if_it_fits).flatten()
175 }
176 }
177
178 impl ToPrimitive for $name {
179 fn to_isize(&self) -> Option<isize> {
180 signed_floor!(self, isize)
181 }
182
183 fn to_i8(&self) -> Option<i8> {
184 signed_floor!(self, i8)
185 }
186
187 fn to_i16(&self) -> Option<i16> {
188 signed_floor!(self, i16)
189 }
190
191 fn to_i32(&self) -> Option<i32> {
192 signed_floor!(self, i32)
193 }
194
195 fn to_i64(&self) -> Option<i64> {
196 signed_floor!(self, i64)
197 }
198
199 fn to_i128(&self) -> Option<i128> {
200 signed_floor!(self, i128)
201 }
202
203 fn to_usize(&self) -> Option<usize> {
204 unsigned_floor!(self)
205 }
206
207 fn to_u8(&self) -> Option<u8> {
208 unsigned_floor!(self)
209 }
210
211 fn to_u16(&self) -> Option<u16> {
212 unsigned_floor!(self)
213 }
214
215 fn to_u32(&self) -> Option<u32> {
216 unsigned_floor!(self)
217 }
218
219 fn to_u64(&self) -> Option<u64> {
220 unsigned_floor!(self)
221 }
222
223 fn to_u128(&self) -> Option<u128> {
224 unsigned_floor!(self)
225 }
226
227 fn to_f32(&self) -> Option<f32> {
228 float!(self, f32)
229 }
230
231 fn to_f64(&self) -> Option<f64> {
232 float!(self, f64)
233 }
234 }
235
236 impl FromStr for $name {
237 type Err = &'static str;
238
239 fn from_str(from: &str) -> Result<Self, Self::Err> {
240 Big::<8>::from_str(from)
241 .map(|big| match Self::from_big_if_it_fits(big) {
242 Some(value) => Ok(value),
243 None => Err("value was too large for this type"),
244 })
245 .flatten()
246 }
247 }
248
249 impl $name {
250 fn from_big_if_it_fits<const S: usize>(big: Big<S>) -> Option<Self> {
251 if num_traits::Zero::is_zero(&big) {
252 return Some(<Self as num_traits::Zero>::zero());
253 }
254
255 if big.numerator.len() == 1 && big.denominator.len() == 1 {
256 if big.numerator[0] <= <$uty>::MAX as usize && big.denominator[0] <= <$uty>::MAX as usize {
257 return Some(Self {
258 sign: big.sign,
259 numerator: big.numerator[0] as $uty,
260 denominator: big.denominator[0] as $uty,
261 })
262 }
263 }
264
265 None
266 }
267 }
268
269 impl From<&$name> for $name {
270 #[inline]
271 fn from(other: &$name) -> Self {
272 *other
273 }
274 }
275
276 impl num_traits::Zero for $name {
277 #[inline]
278 fn zero() -> Self {
279 Self {
280 sign: Sign::Zero,
281 numerator: 0,
282 denominator: 1,
283 }
284 }
285
286 #[inline]
287 fn set_zero(&mut self) {
288 self.sign = Sign::Zero;
289 self.numerator = 0;
290 self.denominator = 1;
291 }
292
293 #[inline]
294 fn is_zero(&self) -> bool {
295 self.sign == Sign::Zero
296 }
297 }
298 }
299}
300
301creation!(Rational8, i8, u8, gcd8, simplify8);
302creation!(Rational16, i16, u16, gcd16, simplify16);
303creation!(Rational32, i32, u32, gcd32, simplify32);
304creation!(Rational64, i64, u64, gcd64, simplify64);
305creation!(Rational128, i128, u128, gcd128, simplify128);
306creation!(RationalUsize, isize, usize, gcd_usize, simplify_usize);
307
308macro_rules! impl_one {
309 ($name:ident, $sign:ident) => {
310 impl num_traits::One for $name {
311 #[inline]
312 fn one() -> Self {
313 Self {
314 sign: $sign::Positive,
315 numerator: 1,
316 denominator: 1,
317 }
318 }
319
320 #[inline]
321 fn set_one(&mut self) {
322 self.sign = $sign::Positive;
323 self.numerator = 1;
324 self.denominator = 1;
325 }
326
327 #[inline]
328 fn is_one(&self) -> bool {
329 self.numerator == 1 && self.denominator == 1 && self.sign == $sign::Positive
330 }
331 }
332 }
333}
334impl_one!(Rational8, Sign);
335impl_one!(Rational16, Sign);
336impl_one!(Rational32, Sign);
337impl_one!(Rational64, Sign);
338impl_one!(Rational128, Sign);
339impl_one!(RationalUsize, Sign);
340impl_one!(NonZeroRational8, NonZeroSign);
341impl_one!(NonZeroRational16, NonZeroSign);
342impl_one!(NonZeroRational32, NonZeroSign);
343impl_one!(NonZeroRational64, NonZeroSign);
344impl_one!(NonZeroRational128, NonZeroSign);
345impl_one!(NonZeroRationalUsize, NonZeroSign);
346
347macro_rules! size_dependent_unsigned {
348 ($name:ty, $uty:ty, $other:ty, $simplify:ident) => {
349 impl From<$other> for $name {
350 #[inline]
351 fn from(other: $other) -> Self {
352 Self {
353 sign: Signed::signum(&other),
354 numerator: other as $uty,
355 denominator: 1,
356 }
357 }
358 }
359 impl From<&$other> for $name {
360 #[inline]
361 fn from(other: &$other) -> Self {
362 Self {
363 sign: Signed::signum(other),
364 numerator: *other as $uty,
365 denominator: 1,
366 }
367 }
368 }
369 impl From<($other, $other)> for $name {
370 #[inline]
371 fn from(other: ($other, $other)) -> Self {
372 assert_ne!(other.1, 0, "attempt to divide by zero");
373
374 let (numerator, denominator) = $simplify(other.0, other.1);
375
376 Self {
377 sign: Signed::signum(&other.0) * Signed::signum(&other.1),
378 numerator: numerator as $uty,
379 denominator: denominator as $uty,
380 }
381 }
382 }
383 }
384}
385
386size_dependent_unsigned!(Rational8, u8, u8, simplify8);
387size_dependent_unsigned!(Rational16, u16, u8, simplify8);
388size_dependent_unsigned!(Rational16, u16, u16, simplify16);
389size_dependent_unsigned!(Rational32, u32, u8, simplify8);
390size_dependent_unsigned!(Rational32, u32, u16, simplify16);
391size_dependent_unsigned!(Rational32, u32, u32, simplify32);
392size_dependent_unsigned!(Rational64, u64, u8, simplify8);
393size_dependent_unsigned!(Rational64, u64, u16, simplify16);
394size_dependent_unsigned!(Rational64, u64, u32, simplify32);
395size_dependent_unsigned!(Rational64, u64, u64, simplify64);
396size_dependent_unsigned!(Rational128, u128, u8, simplify8);
397size_dependent_unsigned!(Rational128, u128, u16, simplify16);
398size_dependent_unsigned!(Rational128, u128, u32, simplify32);
399size_dependent_unsigned!(Rational128, u128, u64, simplify64);
400size_dependent_unsigned!(Rational128, u128, u128, simplify128);
401
402macro_rules! size_dependent_signed {
403 ($name:ty, $uty:ty, $other_signed:ty, $simplify:ident) => {
404 impl From<$other_signed> for $name {
405 #[inline]
406 fn from(other: $other_signed) -> Self {
407 Self {
408 sign: Signed::signum(&other),
409 numerator: other.unsigned_abs() as $uty,
410 denominator: 1,
411 }
412 }
413 }
414 impl From<&$other_signed> for $name {
415 #[inline]
416 fn from(other: &$other_signed) -> Self {
417 Self {
418 sign: Signed::signum(other),
419 numerator: other.unsigned_abs() as $uty,
420 denominator: 1,
421 }
422 }
423 }
424 impl From<($other_signed, $other_signed)> for $name {
425 #[inline]
426 fn from(other: ($other_signed, $other_signed)) -> Self {
427 assert_ne!(other.1, 0, "attempt to divide by zero");
428
429 let (numerator, denominator) = $simplify(other.0.unsigned_abs(), other.1.unsigned_abs());
430
431 Self {
432 sign: Signed::signum(&other.0) * Signed::signum(&other.1),
433 numerator: numerator as $uty,
434 denominator: denominator as $uty,
435 }
436 }
437 }
438 }
439}
440
441size_dependent_signed!(Rational8, u8, i8, simplify8);
442size_dependent_signed!(Rational16, u16, i8, simplify8);
443size_dependent_signed!(Rational16, u16, i16, simplify16);
444size_dependent_signed!(Rational32, u32, i8, simplify8);
445size_dependent_signed!(Rational32, u32, i16, simplify16);
446size_dependent_signed!(Rational32, u32, i32, simplify32);
447size_dependent_signed!(Rational64, u64, i8, simplify8);
448size_dependent_signed!(Rational64, u64, i16, simplify16);
449size_dependent_signed!(Rational64, u64, i32, simplify32);
450size_dependent_signed!(Rational64, u64, i64, simplify64);
451size_dependent_signed!(Rational128, u128, i8, simplify8);
452size_dependent_signed!(Rational128, u128, i16, simplify16);
453size_dependent_signed!(Rational128, u128, i32, simplify32);
454size_dependent_signed!(Rational128, u128, i64, simplify64);
455size_dependent_signed!(Rational128, u128, i128, simplify128);
456
457#[cfg(test)]
458mod test {
459 use num_traits::ToPrimitive;
460
461 use crate::{R16, R32, R64, R8, Rational16, Rational32, Rational8};
462
463 #[test]
464 fn test_debug() {
465 assert_eq!(format!("{:?}", R8!(2, 3)), "2 / 3");
466 assert_eq!(format!("{:?}", R8!(0)), "0");
467 assert_eq!(format!("{:?}", R8!(-1)), "-1");
468 assert_eq!(format!("{:?}", R8!(-0)), "0");
469 assert_eq!(format!("{:?}", -R8!(2, 3)), "-2 / 3");
470 }
471
472 #[test]
473 fn test_from() {
474 assert_eq!(Rational8::from(4_u8), R8!(4));
475 assert_eq!(Rational16::from(-4_i8), R16!(-4));
476 assert_eq!(Rational8::from(&4_u8), R8!(4));
477 assert_eq!(Rational16::from(&-4_i8), R16!(-4));
478 assert_eq!(Rational16::from((-4_i8, 2_i8)), R16!(-2));
479 assert_eq!(Rational16::from((4_u8, 2_u8)), R16!(2));
480 }
481
482 #[test]
483 fn test_to_primitive() {
484 assert_eq!(R8!(0).to_u8(), Some(0));
485 assert_eq!(R8!(1, 2).to_u8(), Some(0));
486 assert_eq!(R8!(3, 4).to_i8(), Some(0));
487 assert_eq!(R8!(3, 2).to_i8(), Some(1));
488 assert_eq!(R8!(-0).to_i8(), Some(0));
489 assert_eq!(R8!(-1, 2).to_i8(), Some(0));
490 assert_eq!(R8!(-3, 4).to_i8(), Some(0));
491 assert_eq!(R8!(-3, 2).to_i8(), Some(-1));
492
493 assert_eq!(Rational8::new(1, 1).unwrap().to_i32(), Some(1));
494 assert_eq!(R8!(-10).to_i32(), Some(-10));
495 assert_eq!(R8!(-11).to_u16(), None);
496 assert_eq!(R64!(2_u64.pow(63) + 2_u64.pow(20)).to_i64(), None);
497 assert_eq!(R8!(0).to_i64(), Some(0));
498 assert_eq!(R8!(0).to_u64(), Some(0));
499 assert_eq!(R8!(1, 2).to_u64(), Some(0));
500 assert_eq!(R8!(8).to_u64(), Some(8));
501
502 assert_eq!(R8!(0).to_f64(), Some(0_f64));
503 assert_eq!(R32!(-156, 99).to_f64(), Some(-156_f64 / 99_f64));
504 assert_eq!(R8!(3, 2).to_f64(), Some(1.5_f64));
505 assert_eq!(R8!(-0).to_f64(), Some(0_f64));
506 assert_eq!(R8!(-3, 2).to_f64(), Some(-1.5_f64));
507 }
508
509 #[test]
510 #[should_panic]
511 #[allow(unused_must_use)]
512 fn test_from_div_zero() {
513 Rational32::from((4, 0));
514 }
515}