1use std::convert::TryInto;
2use std::fmt;
3use std::str::FromStr;
4
5use num_traits::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::ops::building_blocks::{gcd128, gcd16, gcd32, gcd64, gcd8, gcd_usize};
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, $unsigned_target:ty) => {
18 {
19 let floor = $value.numerator / $value.denominator;
20 let magnitude: Option<$unsigned_target> = floor.try_into().ok();
24
25 magnitude.and_then(|magnitude| match $value.sign {
26 Sign::Zero | Sign::Positive => <$target>::try_from(magnitude).ok(),
27 Sign::Negative => {
28 if magnitude <= <$target>::MIN.unsigned_abs() {
29 Some(magnitude.wrapping_neg() as $target)
32 } else {
33 None
34 }
35 }
36 })
37 }
38 }
39}
40
41macro_rules! unsigned_floor {
42 ($value:expr) => {
43 {
44 match $value.sign {
45 Sign::Zero | Sign::Positive => {
46 let floor = $value.numerator / $value.denominator;
47 floor.try_into().ok()
48 }
49 Sign::Negative => None,
50 }
51 }
52 }
53}
54
55macro_rules! float {
56 ($value:expr, $target:ty) => {
57 {
58 let ratio = $value.numerator as $target / $value.denominator as $target;
59 let signed_ratio = match $value.sign {
60 Sign::Zero | Sign::Positive => ratio,
61 Sign::Negative => -ratio,
62 };
63
64 Some(signed_ratio)
65 }
66 }
67}
68
69macro_rules! creation {
70 ($name:ident, $ity:ty, $uty:ty, $gcd_name:ident, $simplify_name:ident) => {
71 impl $name {
72 #[must_use]
85 pub fn new(numerator: $ity, mut denominator: $uty) -> Option<Self> {
86 if denominator.is_zero() {
87 None
88 } else {
89 Some({
90 let mut numerator_abs = numerator.unsigned_abs();
91 if numerator == 0 {
92 <Self as num_traits::Zero>::zero()
93 } else if numerator_abs == denominator {
94 Self {
95 sign: Signed::signum(&numerator),
96 numerator: 1,
97 denominator: 1,
98 }
99 } else {
100 if numerator_abs != 1 && denominator != 1 {
101 let gcd = $gcd_name(numerator_abs, denominator);
104
105 numerator_abs /= gcd;
106 denominator /= gcd;
107 }
108
109 Self {
110 sign: Signed::signum(&numerator),
111 numerator: numerator_abs,
112 denominator,
113 }
114 }
115 })
116 }
117 }
118 #[must_use]
128 pub fn new_signed<T: Into<Sign>>(sign: T, numerator: $uty, denominator: $uty) -> Option<Self> {
129 if denominator == 0 {
130 return None;
131 }
132
133 match (sign.into(), numerator) {
134 (Sign::Zero, 0) => Some(<Self as num_traits::Zero>::zero()),
135 (sign @ (Sign::Positive | Sign::Negative), numerator) if numerator != 0 => {
137 let (numerator, denominator) = $simplify_name(numerator, denominator);
138
139 Some(Self {
140 sign,
141 numerator,
142 denominator,
143 })
144 }
145 _ => None,
146 }
147 }
148 }
149
150 impl Default for $name {
151 fn default() -> Self {
152 Self::zero()
153 }
154 }
155
156 impl fmt::Debug for $name {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 fmt::Display::fmt(self, f)
160 }
161 }
162
163 impl num_traits::FromPrimitive for $name {
164 #[inline]
165 fn from_i64(n: i64) -> Option<Self> {
166 if n.unsigned_abs() <= <$uty>::MAX as u64 {
167 Some(Self {
168 sign: Signed::signum(&n),
169 numerator: n.unsigned_abs() as $uty,
170 denominator: 1,
171 })
172 } else {
173 None
174 }
175 }
176
177 #[inline]
178 fn from_u64(n: u64) -> Option<Self> {
179 if n <= <$uty>::MAX as u64 {
180 Some(Self {
181 sign: Signed::signum(&n),
182 numerator: n as $uty,
183 denominator: 1,
184 })
185 } else {
186 None
187 }
188 }
189
190 #[inline]
193 fn from_i128(n: i128) -> Option<Self> {
194 let numerator = n.unsigned_abs().try_into().ok()?;
195
196 Some(Self {
197 sign: Signed::signum(&n),
198 numerator,
199 denominator: 1,
200 })
201 }
202
203 #[inline]
206 fn from_u128(n: u128) -> Option<Self> {
207 let numerator = n.try_into().ok()?;
208
209 Some(Self {
210 sign: Signed::signum(&n),
211 numerator,
212 denominator: 1,
213 })
214 }
215
216 #[inline]
217 fn from_f32(n: f32) -> Option<Self> {
218 Big::<8>::from_f32(n).map(Self::from_big_if_it_fits).flatten()
219 }
220
221 #[inline]
222 fn from_f64(n: f64) -> Option<Self> {
223 Big::<16>::from_f64(n).map(Self::from_big_if_it_fits).flatten()
224 }
225 }
226
227 impl ToPrimitive for $name {
228 fn to_isize(&self) -> Option<isize> {
229 signed_floor!(self, isize, usize)
230 }
231
232 fn to_i8(&self) -> Option<i8> {
233 signed_floor!(self, i8, u8)
234 }
235
236 fn to_i16(&self) -> Option<i16> {
237 signed_floor!(self, i16, u16)
238 }
239
240 fn to_i32(&self) -> Option<i32> {
241 signed_floor!(self, i32, u32)
242 }
243
244 fn to_i64(&self) -> Option<i64> {
245 signed_floor!(self, i64, u64)
246 }
247
248 fn to_i128(&self) -> Option<i128> {
249 signed_floor!(self, i128, u128)
250 }
251
252 fn to_usize(&self) -> Option<usize> {
253 unsigned_floor!(self)
254 }
255
256 fn to_u8(&self) -> Option<u8> {
257 unsigned_floor!(self)
258 }
259
260 fn to_u16(&self) -> Option<u16> {
261 unsigned_floor!(self)
262 }
263
264 fn to_u32(&self) -> Option<u32> {
265 unsigned_floor!(self)
266 }
267
268 fn to_u64(&self) -> Option<u64> {
269 unsigned_floor!(self)
270 }
271
272 fn to_u128(&self) -> Option<u128> {
273 unsigned_floor!(self)
274 }
275
276 fn to_f32(&self) -> Option<f32> {
277 float!(self, f32)
278 }
279
280 fn to_f64(&self) -> Option<f64> {
281 float!(self, f64)
282 }
283 }
284
285 impl FromStr for $name {
286 type Err = &'static str;
287
288 fn from_str(from: &str) -> Result<Self, Self::Err> {
289 Big::<8>::from_str(from)
290 .map(|big| match Self::from_big_if_it_fits(big) {
291 Some(value) => Ok(value),
292 None => Err("value was too large for this type"),
293 })
294 .flatten()
295 }
296 }
297
298 impl $name {
299 fn from_big_if_it_fits<const S: usize>(big: Big<S>) -> Option<Self> {
300 if num_traits::Zero::is_zero(&big) {
301 return Some(<Self as num_traits::Zero>::zero());
302 }
303
304 const WORDS: usize = {
309 let words = std::mem::size_of::<$uty>() / std::mem::size_of::<usize>();
310 if words > 0 { words } else { 1 }
311 };
312
313 fn scalar(words: &[usize]) -> Option<$uty> {
315 if words.len() > WORDS {
316 return None;
318 }
319
320 let mut value = 0_u128;
323 for (index, &word) in words.iter().enumerate() {
324 value |= (word as u128) << (index as u32 * usize::BITS);
325 }
326
327 value.try_into().ok()
330 }
331
332 Some(Self {
333 sign: big.sign,
334 numerator: scalar(&big.numerator)?,
335 denominator: scalar(&big.denominator)?,
336 })
337 }
338 }
339
340 impl From<&$name> for $name {
341 #[inline]
342 fn from(other: &$name) -> Self {
343 *other
344 }
345 }
346
347 impl num_traits::Zero for $name {
348 #[inline]
349 fn zero() -> Self {
350 Self {
351 sign: Sign::Zero,
352 numerator: 0,
353 denominator: 1,
354 }
355 }
356
357 #[inline]
358 fn set_zero(&mut self) {
359 self.sign = Sign::Zero;
360 self.numerator = 0;
361 self.denominator = 1;
362 }
363
364 #[inline]
365 fn is_zero(&self) -> bool {
366 self.sign == Sign::Zero
367 }
368 }
369 }
370}
371
372creation!(Rational8, i8, u8, gcd8, simplify8);
373creation!(Rational16, i16, u16, gcd16, simplify16);
374creation!(Rational32, i32, u32, gcd32, simplify32);
375creation!(Rational64, i64, u64, gcd64, simplify64);
376creation!(Rational128, i128, u128, gcd128, simplify128);
377creation!(RationalUsize, isize, usize, gcd_usize, simplify_usize);
378
379macro_rules! impl_one {
380 ($name:ident, $sign:ident) => {
381 impl num_traits::One for $name {
382 #[inline]
383 fn one() -> Self {
384 Self {
385 sign: $sign::Positive,
386 numerator: 1,
387 denominator: 1,
388 }
389 }
390
391 #[inline]
392 fn set_one(&mut self) {
393 self.sign = $sign::Positive;
394 self.numerator = 1;
395 self.denominator = 1;
396 }
397
398 #[inline]
399 fn is_one(&self) -> bool {
400 self.numerator == 1 && self.denominator == 1 && self.sign == $sign::Positive
401 }
402 }
403 }
404}
405impl_one!(Rational8, Sign);
406impl_one!(Rational16, Sign);
407impl_one!(Rational32, Sign);
408impl_one!(Rational64, Sign);
409impl_one!(Rational128, Sign);
410impl_one!(RationalUsize, Sign);
411impl_one!(NonZeroRational8, NonZeroSign);
412impl_one!(NonZeroRational16, NonZeroSign);
413impl_one!(NonZeroRational32, NonZeroSign);
414impl_one!(NonZeroRational64, NonZeroSign);
415impl_one!(NonZeroRational128, NonZeroSign);
416impl_one!(NonZeroRationalUsize, NonZeroSign);
417
418macro_rules! size_dependent_unsigned {
419 ($name:ty, $uty:ty, $other:ty, $simplify:ident) => {
420 impl From<$other> for $name {
421 #[inline]
422 fn from(other: $other) -> Self {
423 Self {
424 sign: Signed::signum(&other),
425 numerator: other as $uty,
426 denominator: 1,
427 }
428 }
429 }
430 impl From<&$other> for $name {
431 #[inline]
432 fn from(other: &$other) -> Self {
433 Self {
434 sign: Signed::signum(other),
435 numerator: *other as $uty,
436 denominator: 1,
437 }
438 }
439 }
440 impl From<($other, $other)> for $name {
441 #[inline]
442 fn from(other: ($other, $other)) -> Self {
443 assert_ne!(other.1, 0, "attempt to divide by zero");
444
445 if other.0 == 0 {
447 return <Self as num_traits::Zero>::zero();
448 }
449
450 let (numerator, denominator) = $simplify(other.0, other.1);
451
452 Self {
453 sign: Signed::signum(&other.0) * Signed::signum(&other.1),
454 numerator: numerator as $uty,
455 denominator: denominator as $uty,
456 }
457 }
458 }
459 }
460}
461
462size_dependent_unsigned!(Rational8, u8, u8, simplify8);
463size_dependent_unsigned!(Rational16, u16, u8, simplify8);
464size_dependent_unsigned!(Rational16, u16, u16, simplify16);
465size_dependent_unsigned!(Rational32, u32, u8, simplify8);
466size_dependent_unsigned!(Rational32, u32, u16, simplify16);
467size_dependent_unsigned!(Rational32, u32, u32, simplify32);
468size_dependent_unsigned!(Rational64, u64, u8, simplify8);
469size_dependent_unsigned!(Rational64, u64, u16, simplify16);
470size_dependent_unsigned!(Rational64, u64, u32, simplify32);
471size_dependent_unsigned!(Rational64, u64, u64, simplify64);
472size_dependent_unsigned!(Rational128, u128, u8, simplify8);
473size_dependent_unsigned!(Rational128, u128, u16, simplify16);
474size_dependent_unsigned!(Rational128, u128, u32, simplify32);
475size_dependent_unsigned!(Rational128, u128, u64, simplify64);
476size_dependent_unsigned!(Rational128, u128, u128, simplify128);
477
478macro_rules! size_dependent_signed {
479 ($name:ty, $uty:ty, $other_signed:ty, $simplify:ident) => {
480 impl From<$other_signed> for $name {
481 #[inline]
482 fn from(other: $other_signed) -> Self {
483 Self {
484 sign: Signed::signum(&other),
485 numerator: other.unsigned_abs() as $uty,
486 denominator: 1,
487 }
488 }
489 }
490 impl From<&$other_signed> for $name {
491 #[inline]
492 fn from(other: &$other_signed) -> Self {
493 Self {
494 sign: Signed::signum(other),
495 numerator: other.unsigned_abs() as $uty,
496 denominator: 1,
497 }
498 }
499 }
500 impl From<($other_signed, $other_signed)> for $name {
501 #[inline]
502 fn from(other: ($other_signed, $other_signed)) -> Self {
503 assert_ne!(other.1, 0, "attempt to divide by zero");
504
505 if other.0 == 0 {
507 return <Self as num_traits::Zero>::zero();
508 }
509
510 let (numerator, denominator) = $simplify(other.0.unsigned_abs(), other.1.unsigned_abs());
511
512 Self {
513 sign: Signed::signum(&other.0) * Signed::signum(&other.1),
514 numerator: numerator as $uty,
515 denominator: denominator as $uty,
516 }
517 }
518 }
519 }
520}
521
522size_dependent_signed!(Rational8, u8, i8, simplify8);
523size_dependent_signed!(Rational16, u16, i8, simplify8);
524size_dependent_signed!(Rational16, u16, i16, simplify16);
525size_dependent_signed!(Rational32, u32, i8, simplify8);
526size_dependent_signed!(Rational32, u32, i16, simplify16);
527size_dependent_signed!(Rational32, u32, i32, simplify32);
528size_dependent_signed!(Rational64, u64, i8, simplify8);
529size_dependent_signed!(Rational64, u64, i16, simplify16);
530size_dependent_signed!(Rational64, u64, i32, simplify32);
531size_dependent_signed!(Rational64, u64, i64, simplify64);
532size_dependent_signed!(Rational128, u128, i8, simplify8);
533size_dependent_signed!(Rational128, u128, i16, simplify16);
534size_dependent_signed!(Rational128, u128, i32, simplify32);
535size_dependent_signed!(Rational128, u128, i64, simplify64);
536size_dependent_signed!(Rational128, u128, i128, simplify128);
537
538#[cfg(test)]
539mod test {
540 use std::str::FromStr;
541
542 use num_traits::{FromPrimitive, ToPrimitive};
543
544 use crate::{R16, R32, R64, R8, Rational128, Rational16, Rational32, Rational64, Rational8, RationalUsize};
545 use crate::rational::Ratio;
546 use crate::sign::Sign;
547
548 #[test]
549 fn test_debug() {
550 assert_eq!(format!("{:?}", R8!(2, 3)), "2/3");
551 assert_eq!(format!("{:?}", R8!(0)), "0");
552 assert_eq!(format!("{:?}", R8!(-1)), "-1");
553 assert_eq!(format!("{:?}", R8!(-0)), "0");
554 assert_eq!(format!("{:?}", -R8!(2, 3)), "-2/3");
555 }
556
557 #[test]
559 fn test_debug_round_trips() {
560 for value in [R8!(2, 3), R8!(0), R8!(-1), R8!(1), R8!(-2, 3), R8!(127, 2)] {
561 let rendered = format!("{value:?}");
562 assert_eq!(rendered, format!("{value}"));
563 assert_eq!(Rational8::from_str(&rendered), Ok(value), "{rendered}");
564 }
565 }
566
567 #[test]
568 fn test_from() {
569 assert_eq!(Rational8::from(4_u8), R8!(4));
570 assert_eq!(Rational16::from(-4_i8), R16!(-4));
571 assert_eq!(Rational8::from(&4_u8), R8!(4));
572 assert_eq!(Rational16::from(&-4_i8), R16!(-4));
573 assert_eq!(Rational16::from((-4_i8, 2_i8)), R16!(-2));
574 assert_eq!(Rational16::from((4_u8, 2_u8)), R16!(2));
575 }
576
577 #[test]
578 fn test_to_primitive() {
579 assert_eq!(R8!(0).to_u8(), Some(0));
580 assert_eq!(R8!(1, 2).to_u8(), Some(0));
581 assert_eq!(R8!(3, 4).to_i8(), Some(0));
582 assert_eq!(R8!(3, 2).to_i8(), Some(1));
583 assert_eq!(R8!(-0).to_i8(), Some(0));
584 assert_eq!(R8!(-1, 2).to_i8(), Some(0));
585 assert_eq!(R8!(-3, 4).to_i8(), Some(0));
586 assert_eq!(R8!(-3, 2).to_i8(), Some(-1));
587
588 assert_eq!(Rational8::new(1, 1).unwrap().to_i32(), Some(1));
589 assert_eq!(R8!(-10).to_i32(), Some(-10));
590 assert_eq!(R8!(-11).to_u16(), None);
591 assert_eq!(R64!(2_u64.pow(63) + 2_u64.pow(20)).to_i64(), None);
592 assert_eq!(R8!(0).to_i64(), Some(0));
593 assert_eq!(R8!(0).to_u64(), Some(0));
594 assert_eq!(R8!(1, 2).to_u64(), Some(0));
595 assert_eq!(R8!(8).to_u64(), Some(8));
596
597 assert_eq!(R8!(0).to_f64(), Some(0_f64));
598 assert_eq!(R32!(-156, 99).to_f64(), Some(-156_f64 / 99_f64));
599 assert_eq!(R8!(3, 2).to_f64(), Some(1.5_f64));
600 assert_eq!(R8!(-0).to_f64(), Some(0_f64));
601 assert_eq!(R8!(-3, 2).to_f64(), Some(-1.5_f64));
602 }
603
604 #[test]
606 fn test_new_signed_invalid() {
607 assert_eq!(Rational8::new_signed(Sign::Positive, 1, 0), None);
609 assert_eq!(Rational8::new_signed(Sign::Zero, 0, 0), None);
610 assert_eq!(Rational128::new_signed(Sign::Negative, u128::MAX, 0), None);
611
612 assert_eq!(Rational64::new_signed(Sign::Zero, 1, 1), None);
614 assert_eq!(Rational64::new_signed(Sign::Positive, 0, 1), None);
615 assert_eq!(Rational64::new_signed(Sign::Negative, 0, 1), None);
616
617 assert_eq!(Rational64::new_signed(Sign::Positive, 6, 18), Rational64::new(1, 3));
619 assert_eq!(Rational64::new_signed(Sign::Zero, 0, 6), Some(R64!(0)));
620 assert_eq!(Rational64::new_signed(Sign::Negative, 9, 18), Some(-R64!(1, 2)));
621 assert_eq!(Rational128::new_signed(Sign::Negative, u128::MAX, 1).unwrap().numerator, u128::MAX);
622 }
623
624 #[test]
626 fn test_to_primitive_most_negative() {
627 assert_eq!(Rational8::from_str("-128").unwrap().to_i8(), Some(i8::MIN));
628 assert_eq!(Rational8::from_str("-129").unwrap().to_i8(), None);
629 assert_eq!(Rational8::from_str("128").unwrap().to_i8(), None);
630 assert_eq!(Rational8::from_str("-255/2").unwrap().to_i8(), Some(-127));
631 assert_eq!(Rational16::from_str("-257/2").unwrap().to_i8(), Some(i8::MIN));
632
633 assert_eq!(Rational16::from_str("-32768").unwrap().to_i16(), Some(i16::MIN));
634 assert_eq!(Rational16::from_str("-32769").unwrap().to_i16(), None);
635
636 assert_eq!(Rational64::from_i64(i64::MIN).unwrap().to_i64(), Some(i64::MIN));
637 assert_eq!(Rational64::from_i64(i64::MIN).unwrap().to_i32(), None);
638 assert_eq!(Rational128::from_i128(i128::MIN).unwrap().to_i128(), Some(i128::MIN));
639 assert_eq!(Rational128::from_i128(i128::MIN).unwrap().to_i64(), None);
640 assert_eq!(Rational128::from_i64(i64::MIN).unwrap().to_i64(), Some(i64::MIN));
641
642 let value: RationalUsize = Ratio {
644 sign: Sign::Negative,
645 numerator: 1 << (usize::BITS - 1),
646 denominator: 1,
647 };
648 assert_eq!(value.to_isize(), Some(isize::MIN));
649 let value: RationalUsize = Ratio { sign: Sign::Negative, numerator: usize::MAX, denominator: 1 };
650 assert_eq!(value.to_isize(), None);
651
652 assert_eq!(R8!(-3, 2).to_i8(), Some(-1));
654 assert_eq!(R8!(-0).to_i8(), Some(0));
655 assert_eq!(R8!(-1).to_u8(), None);
656 assert_eq!(R8!(127).to_i8(), Some(127));
657 }
658
659 #[test]
661 fn test_from_str_above_64_bits() {
662 let value = Rational128::from_str("18446744073709551616").unwrap();
663 assert_eq!(value.sign, Sign::Positive);
664 assert_eq!(value.numerator, 1 << 64);
665 assert_eq!(value.denominator, 1);
666
667 let value = Rational128::from_str(&i128::MAX.to_string()).unwrap();
668 assert_eq!(value.numerator, i128::MAX as u128);
669 assert_eq!(value.denominator, 1);
670
671 let value = Rational128::from_str(&u128::MAX.to_string()).unwrap();
672 assert_eq!(value.numerator, u128::MAX);
673 assert_eq!(value.denominator, 1);
674
675 let value = Rational128::from_str(&format!("-{}", u128::MAX)).unwrap();
676 assert_eq!(value.sign, Sign::Negative);
677 assert_eq!(value.numerator, u128::MAX);
678
679 let value = Rational128::from_str("1/18446744073709551616").unwrap();
681 assert_eq!(value.numerator, 1);
682 assert_eq!(value.denominator, 1 << 64);
683
684 assert_eq!(
686 Rational128::from_str("340282366920938463463374607431768211456"),
687 Err("value was too large for this type"),
688 );
689 assert_eq!(Rational64::from_str("18446744073709551616"), Err("value was too large for this type"));
690 assert_eq!(Rational32::from_str("4294967296"), Err("value was too large for this type"));
691 assert_eq!(Rational8::from_str("256"), Err("value was too large for this type"));
692 assert_eq!(Rational8::from_str("1/256"), Err("value was too large for this type"));
693 assert_eq!(RationalUsize::from_str(&usize::MAX.to_string()).unwrap().numerator, usize::MAX);
694 assert_eq!(
695 RationalUsize::from_str(&(usize::MAX as u128 + 1).to_string()),
696 Err("value was too large for this type"),
697 );
698 }
699
700 #[test]
702 fn test_from_f64_above_64_bits() {
703 let value = Rational128::from_f64(1e30).unwrap();
705 assert_eq!(value.numerator, 1_000_000_000_000_000_019_884_624_838_656);
706 assert_eq!(value.denominator, 1);
707
708 let value = Rational128::from_f64(-(2_f64.powi(100))).unwrap();
709 assert_eq!(value.sign, Sign::Negative);
710 assert_eq!(value.numerator, 1 << 100);
711 assert_eq!(value.denominator, 1);
712
713 let value = Rational128::from_f32(2_f32.powi(80)).unwrap();
714 assert_eq!(value.numerator, 1 << 80);
715
716 assert_eq!(Rational128::from_f64(2_f64.powi(128)), None);
718 assert_eq!(Rational128::from_f64(u128::MAX as f64), None);
719 assert_eq!(Rational64::from_f64(1e30), None);
720 }
721
722 #[test]
724 fn test_from_128_bit_primitive() {
725 assert_eq!(Rational128::from_i128(i128::MAX).unwrap().numerator, i128::MAX as u128);
726 assert_eq!(Rational128::from_i128(i128::MIN).unwrap().numerator, 1 << 127);
727 assert_eq!(Rational128::from_i128(i128::MIN).unwrap().sign, Sign::Negative);
728 assert_eq!(Rational128::from_u128(u128::MAX).unwrap().numerator, u128::MAX);
729 assert_eq!(Rational128::from_i128(0).unwrap(), <Rational128 as num_traits::Zero>::zero());
730
731 assert_eq!(RationalUsize::from_u128(usize::MAX as u128).unwrap().numerator, usize::MAX);
732 assert_eq!(RationalUsize::from_u128(usize::MAX as u128 + 1), None);
733
734 assert_eq!(Rational64::from_i128(i128::MAX), None);
735 assert_eq!(Rational64::from_u128(u128::MAX), None);
736 assert_eq!(Rational64::from_i128(i64::MIN as i128).unwrap().numerator, 1 << 63);
737 assert_eq!(Rational8::from_i128(-128).unwrap().numerator, 128);
738 assert_eq!(Rational8::from_i128(-256), None);
739 }
740
741 #[test]
742 #[should_panic]
743 #[allow(unused_must_use)]
744 fn test_from_div_zero() {
745 Rational32::from((4, 0));
746 }
747
748 #[test]
749 fn test_from_tuple_zero_numerator() {
750 macro_rules! assert_canonical_zero {
752 ($value:expr) => {{
753 let value = $value;
754 assert_eq!(value.sign, Sign::Zero);
755 assert_eq!(value.numerator, 0);
756 assert_eq!(value.denominator, 1);
757 }}
758 }
759
760 assert_canonical_zero!(Rational8::from((0_i8, 5_i8)));
762 assert_canonical_zero!(Rational32::from((0_i32, 5_i32)));
763 assert_canonical_zero!(Rational32::from((0_i16, -3_i16)));
764 assert_canonical_zero!(Rational128::from((0_i128, -7_i128)));
765
766 assert_canonical_zero!(Rational8::from((0_u8, 5_u8)));
768 assert_canonical_zero!(Rational32::from((0_u32, 5_u32)));
769 assert_canonical_zero!(Rational32::from((0_u16, 3_u16)));
770 assert_canonical_zero!(Rational128::from((0_u128, 7_u128)));
771
772 assert_eq!(Rational32::from((0_i32, 5_i32)), R32!(0));
773 assert_eq!(Rational32::from((0_u32, 5_u32)), R32!(0));
774 }
775
776 #[test]
777 fn test_new_128_bit_gcd() {
778 let value = Rational128::new(3 << 64, 2_u128 << 64).unwrap();
781 assert_eq!(value.sign, Sign::Positive);
782 assert_eq!(value.numerator, 3);
783 assert_eq!(value.denominator, 2);
784
785 let value = Rational128::new(6, 1_u128 << 64).unwrap();
786 assert_eq!(value.numerator, 3);
787 assert_eq!(value.denominator, 1_u128 << 63);
788
789 let value = Rational128::new(6_i128 << 70, 4_u128 << 70).unwrap();
791 assert_eq!(value.numerator, 3);
792 assert_eq!(value.denominator, 2);
793
794 let large_factor = (1_i128 << 64) + 1;
796 let value = Rational128::new(3 * large_factor, 2 * large_factor as u128).unwrap();
797 assert_eq!(value.sign, Sign::Positive);
798 assert_eq!(value.numerator, 3);
799 assert_eq!(value.denominator, 2);
800
801 let value = Rational128::new(-(5 << 100), 15_u128 << 100).unwrap();
802 assert_eq!(value.sign, Sign::Negative);
803 assert_eq!(value.numerator, 1);
804 assert_eq!(value.denominator, 3);
805 }
806}