1use alloc::format;
2use core::{
3 cmp,
4 fmt,
5 fmt::Display,
6 marker::PhantomData,
7 ops::{
8 Add,
9 Div,
10 Mul,
11 Sub,
12 },
13 str::FromStr,
14};
15
16use anyhow::Error;
17use num::{
18 FromPrimitive,
19 Integer,
20 PrimInt,
21 Signed,
22 Zero,
23 integer::Roots,
24 pow::Pow,
25 traits::{
26 SaturatingAdd,
27 SaturatingMul,
28 SaturatingSub,
29 WrappingAdd,
30 WrappingMul,
31 WrappingSub,
32 },
33};
34use serde::{
35 Deserialize,
36 Serialize,
37 Serializer,
38 de::{
39 Unexpected,
40 Visitor,
41 },
42};
43
44pub trait FractionInteger: Integer + FromPrimitive + Copy {}
46impl<I> FractionInteger for I where I: Integer + FromPrimitive + Copy {}
47
48#[derive(Debug, Clone, Copy)]
57pub struct Fraction<I> {
58 num: I,
59 den: I,
60}
61
62impl<I> Fraction<I>
63where
64 I: FractionInteger,
65{
66 pub fn new(n: I, d: I) -> Self {
68 Self { num: n, den: d }
69 }
70
71 pub fn percentage(n: I) -> Self {
73 Fraction {
74 num: n,
75 den: I::from_u8(100).unwrap(),
76 }
77 .simplify()
78 }
79
80 pub fn from_f64(value: f64) -> Self {
84 let num = I::from_f64(value * 4096f64).unwrap();
85 Self::new(num, I::from_u16(4096).unwrap()).simplify()
86 }
87
88 pub fn numerator(&self) -> I {
90 self.num
91 }
92
93 pub fn denominator(&self) -> I {
97 self.den
98 }
99
100 pub fn is_whole(&self) -> bool {
102 self.den == I::one()
103 }
104
105 pub fn simplify(&self) -> Self {
107 let n = self.numerator();
108 let d = self.denominator();
109 let gcd = n.gcd(&d);
110 Fraction::new(n.div(gcd), d.div(gcd))
111 }
112
113 pub fn floor(&self) -> I {
117 self.numerator().div(self.denominator())
118 }
119
120 pub fn ceil(&self) -> I {
122 num::Integer::div_ceil(&self.numerator(), &self.denominator())
123 }
124
125 pub fn round(&self) -> I
127 where
128 I: PrimInt,
129 {
130 (self.numerator().add(self.denominator().shr(1))).div(self.denominator())
131 }
132
133 pub fn convert<T>(self) -> Fraction<T>
135 where
136 T: FractionInteger + From<I>,
137 {
138 Fraction::new(T::from(self.numerator()), T::from(self.denominator()))
139 }
140
141 pub fn try_convert<T>(self) -> Result<Fraction<T>, T::Error>
143 where
144 T: FractionInteger + TryFrom<I>,
145 {
146 Ok(Fraction::new(
147 T::try_from(self.numerator())?,
148 T::try_from(self.denominator())?,
149 ))
150 }
151
152 pub fn inverse(&self) -> Self {
154 Self::new(self.denominator(), self.numerator())
155 }
156
157 fn normalize(a: &Fraction<I>, b: &Fraction<I>) -> (Fraction<I>, Fraction<I>) {
158 let a1 = a.numerator();
159 let a2 = a.denominator();
160 let b1 = b.numerator();
161 let b2 = b.denominator();
162 let lcm = a2.lcm(&b2);
164 let a_mul = lcm.div(a2);
165 let b_mul = lcm.div(b2);
166 (
168 Fraction::new(a1.mul(a_mul), lcm),
169 Fraction::new(b1.mul(b_mul), lcm),
170 )
171 }
172}
173
174impl<I> Fraction<I>
175where
176 I: FractionInteger + Roots,
177{
178 pub fn sqrt(&self) -> Self {
179 Self::new(self.numerator().sqrt(), self.denominator().sqrt()).simplify()
180 }
181
182 pub fn nth_root(&self, n: u32) -> Self {
183 Self::new(self.numerator().nth_root(n), self.denominator().nth_root(n)).simplify()
184 }
185
186 pub fn pow<J>(self, rhs: Fraction<J>) -> Result<Self, <J as TryInto<u32>>::Error>
187 where
188 I: Pow<u32, Output = I> + TryInto<J> + Zero,
189 J: FractionInteger + TryInto<u32> + Signed,
190 {
191 let negative = rhs < J::zero();
192 let rhs_num = rhs.numerator().abs();
193 let rhs_den = rhs.denominator().abs();
194 let num = self
195 .numerator()
196 .pow(rhs_num.try_into()?)
197 .nth_root(rhs_den.try_into()?);
198 let den = self
199 .denominator()
200 .pow(rhs_num.try_into()?)
201 .nth_root(rhs_den.try_into()?);
202 let result = if negative {
203 Self::new(den, num)
204 } else {
205 Self::new(num, den)
206 };
207 Ok(result)
208 }
209}
210
211impl<I> Default for Fraction<I>
212where
213 I: FractionInteger,
214{
215 fn default() -> Self {
216 Self::from(I::zero())
217 }
218}
219
220impl<I> Display for Fraction<I>
221where
222 I: FractionInteger + Display,
223{
224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225 if self.den == I::one() {
226 write!(f, "{}", self.num)
227 } else {
228 write!(f, "{}/{}", self.num, self.den)
229 }
230 }
231}
232
233impl<I, J> From<I> for Fraction<J>
234where
235 I: FractionInteger,
236 J: FractionInteger + From<I>,
237{
238 fn from(value: I) -> Self {
239 Self::new(J::from(value), J::from(I::one()))
240 }
241}
242
243impl<I> FromStr for Fraction<I>
244where
245 I: FractionInteger + FromStr + Display,
246 <I as FromStr>::Err: Display,
247 <I as FromStr>::Err: Into<anyhow::Error>,
248{
249 type Err = Error;
250 fn from_str(s: &str) -> Result<Self, Self::Err> {
251 if let Some((n, d)) = s.split_once('/') {
252 let n = n.parse().map_err(|err| {
253 Into::<Error>::into(err).context(format!("invalid numerator: {n}"))
254 })?;
255 let d = d.parse().map_err(|err| {
256 Into::<Error>::into(err).context(format!("invalid denominator: {n}"))
257 })?;
258 Ok(Self::new(n, d))
259 } else {
260 let s = match s.strip_suffix('%') {
261 Some(s) => s,
262 None => s,
263 };
264 Ok(Self::percentage(s.parse().map_err(|err| {
265 Into::<Error>::into(err).context(format!("invalid percentage"))
266 })?))
267 }
268 }
269}
270
271impl<I> PartialEq for Fraction<I>
272where
273 I: FractionInteger,
274{
275 fn eq(&self, other: &Self) -> bool {
276 let (a, b) = Self::normalize(self, other);
277 a.numerator().eq(&b.numerator())
278 }
279}
280
281impl<I> Eq for Fraction<I> where I: FractionInteger {}
282
283impl<I> PartialEq<I> for Fraction<I>
284where
285 I: FractionInteger,
286{
287 fn eq(&self, other: &I) -> bool {
288 self.eq(&Fraction::from(*other))
289 }
290}
291
292impl<I> Ord for Fraction<I>
293where
294 I: FractionInteger,
295{
296 fn cmp(&self, other: &Self) -> cmp::Ordering {
297 let (a, b) = Self::normalize(self, other);
298 a.numerator().cmp(&b.numerator())
299 }
300}
301
302impl<I> PartialOrd for Fraction<I>
303where
304 I: FractionInteger,
305{
306 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
307 Some(self.cmp(other))
308 }
309}
310
311impl<I> PartialOrd<I> for Fraction<I>
312where
313 I: FractionInteger,
314{
315 fn partial_cmp(&self, other: &I) -> Option<cmp::Ordering> {
316 self.partial_cmp(&Fraction::from(*other))
317 }
318}
319
320impl<I> Add<I> for Fraction<I>
321where
322 I: FractionInteger,
323{
324 type Output = Self;
325 fn add(self, rhs: I) -> Self::Output {
326 Self::Output::new(
327 self.numerator().add(rhs.mul(self.denominator())),
328 self.denominator(),
329 )
330 .simplify()
331 }
332}
333
334impl<I> Add for Fraction<I>
335where
336 I: FractionInteger,
337{
338 type Output = Self;
339 fn add(self, rhs: Self) -> Self::Output {
340 let (lhs, rhs) = Self::normalize(&self, &rhs);
341 Self::Output::new(lhs.numerator().add(rhs.numerator()), lhs.denominator())
342 }
343}
344
345impl<I> Sub<I> for Fraction<I>
346where
347 I: FractionInteger,
348{
349 type Output = Self;
350 fn sub(self, rhs: I) -> Self::Output {
351 Self::Output::new(
352 self.numerator().sub(rhs.mul(self.denominator())),
353 self.denominator(),
354 )
355 .simplify()
356 }
357}
358
359impl<I> Sub<Fraction<I>> for Fraction<I>
360where
361 I: FractionInteger,
362{
363 type Output = Self;
364 fn sub(self, rhs: Self) -> Self::Output {
365 let (lhs, rhs) = Self::normalize(&self, &rhs);
366 Self::Output::new(lhs.numerator().sub(rhs.numerator()), lhs.denominator())
367 }
368}
369
370impl<I> Mul<I> for Fraction<I>
371where
372 I: FractionInteger,
373{
374 type Output = Self;
375 fn mul(self, rhs: I) -> Self::Output {
376 Self::Output::new(self.numerator().mul(rhs), self.denominator()).simplify()
377 }
378}
379
380impl<I> Mul<Fraction<I>> for Fraction<I>
381where
382 I: FractionInteger,
383{
384 type Output = Self;
385 fn mul(self, rhs: Self) -> Self::Output {
386 Self::Output::new(
387 self.numerator().mul(rhs.numerator()),
388 self.denominator().mul(rhs.denominator()),
389 )
390 .simplify()
391 }
392}
393
394impl<I> Div<I> for Fraction<I>
395where
396 I: FractionInteger,
397{
398 type Output = Self;
399 fn div(self, rhs: I) -> Self::Output {
400 self.mul(Fraction::new(I::one(), rhs))
401 }
402}
403
404impl<I> Div<Fraction<I>> for Fraction<I>
405where
406 I: FractionInteger,
407{
408 type Output = Self;
409 fn div(self, rhs: Self) -> Self::Output {
410 self.mul(rhs.inverse())
411 }
412}
413
414impl<I> WrappingAdd for Fraction<I>
415where
416 I: FractionInteger + WrappingAdd,
417{
418 fn wrapping_add(&self, v: &Self) -> Self {
419 let (lhs, rhs) = Self::normalize(&self, &v);
420 Self::new(
421 lhs.numerator().wrapping_add(&rhs.numerator()),
422 lhs.denominator(),
423 )
424 }
425}
426
427impl<I> WrappingSub for Fraction<I>
428where
429 I: FractionInteger + WrappingSub,
430{
431 fn wrapping_sub(&self, v: &Self) -> Self {
432 let (lhs, rhs) = Self::normalize(&self, &v);
433 Self::new(
434 lhs.numerator().wrapping_sub(&rhs.numerator()),
435 lhs.denominator(),
436 )
437 }
438}
439
440impl<I> WrappingMul for Fraction<I>
441where
442 I: FractionInteger + WrappingMul,
443{
444 fn wrapping_mul(&self, v: &Self) -> Self {
445 Self::new(
446 self.numerator().wrapping_mul(&v.numerator()),
447 self.denominator().wrapping_mul(&v.denominator()),
448 )
449 .simplify()
450 }
451}
452
453impl<I> SaturatingAdd for Fraction<I>
454where
455 I: FractionInteger + SaturatingAdd,
456{
457 fn saturating_add(&self, v: &Self) -> Self {
458 let (lhs, rhs) = Self::normalize(&self, &v);
459 Self::new(
460 lhs.numerator().saturating_add(&rhs.numerator()),
461 lhs.denominator(),
462 )
463 }
464}
465
466impl<I> SaturatingSub for Fraction<I>
467where
468 I: FractionInteger + SaturatingSub,
469{
470 fn saturating_sub(&self, v: &Self) -> Self {
471 let (lhs, rhs) = Self::normalize(&self, &v);
472 Self::new(
473 lhs.numerator().saturating_sub(&rhs.numerator()),
474 lhs.denominator(),
475 )
476 }
477}
478
479impl<I> SaturatingMul for Fraction<I>
480where
481 I: FractionInteger + SaturatingMul,
482{
483 fn saturating_mul(&self, v: &Self) -> Self {
484 Self::new(
485 self.numerator().saturating_mul(&v.numerator()),
486 self.denominator().saturating_mul(&v.denominator()),
487 )
488 .simplify()
489 }
490}
491
492impl<I> Serialize for Fraction<I>
493where
494 I: FractionInteger + Into<u64> + Display,
495{
496 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
497 where
498 S: Serializer,
499 {
500 if self.is_whole() {
501 serializer.serialize_u64(self.floor().into())
502 } else {
503 serializer.serialize_str(&format!("{self}"))
504 }
505 }
506}
507
508struct FractionVisitor<I> {
509 _phantom: PhantomData<I>,
510}
511
512impl<I> FractionVisitor<I>
513where
514 I: Integer,
515{
516 pub fn new() -> Self {
517 Self {
518 _phantom: PhantomData,
519 }
520 }
521}
522
523impl<'de> Visitor<'de> for FractionVisitor<u16> {
524 type Value = Fraction<u16>;
525
526 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
527 write!(
528 formatter,
529 "an integer, a fraction string, a percentage string, or an array of 2 integers"
530 )
531 }
532
533 fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
534 where
535 E: serde::de::Error,
536 {
537 Ok(Self::Value::from(v as u16))
538 }
539
540 fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
541 where
542 E: serde::de::Error,
543 {
544 Ok(Self::Value::from(v))
545 }
546
547 fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
548 where
549 E: serde::de::Error,
550 {
551 Ok(Self::Value::from(v as u16))
552 }
553
554 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
555 where
556 E: serde::de::Error,
557 {
558 Ok(Self::Value::from(v as u16))
559 }
560
561 fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
562 where
563 E: serde::de::Error,
564 {
565 Ok(Self::Value::from_f64(v))
566 }
567
568 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
569 where
570 E: serde::de::Error,
571 {
572 Self::Value::from_str(v).map_err(|_| E::invalid_value(Unexpected::Str(&v), &self))
573 }
574
575 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
576 where
577 A: serde::de::SeqAccess<'de>,
578 {
579 let num = match seq.next_element()? {
580 Some(v) => v,
581 None => return Err(serde::de::Error::invalid_length(0, &self)),
582 };
583 let den = match seq.next_element()? {
584 Some(v) => v,
585 None => return Err(serde::de::Error::invalid_length(1, &self)),
586 };
587 if seq.next_element::<u8>()?.is_some() {
588 return Err(serde::de::Error::invalid_length(3, &self));
589 }
590 Ok(Self::Value::new(num, den))
591 }
592}
593
594impl<'de> Deserialize<'de> for Fraction<u16> {
595 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
596 where
597 D: serde::Deserializer<'de>,
598 {
599 deserializer.deserialize_any(FractionVisitor::<u16>::new())
600 }
601}
602
603#[cfg(test)]
604mod fraction_test {
605 use alloc::vec;
606
607 use crate::{
608 Fraction,
609 test_util::{
610 test_deserialization,
611 test_serialization,
612 },
613 };
614
615 #[test]
616 fn serializes_to_string() {
617 test_serialization(Fraction::percentage(25), "\"1/4\"");
618 test_serialization(Fraction::percentage(100), "1");
619 test_serialization(Fraction::new(1, 2), "\"1/2\"");
620 test_serialization(Fraction::new(1, 3), "\"1/3\"");
621 test_serialization(Fraction::new(20, 147), "\"20/147\"");
622 }
623
624 #[test]
625 fn deserializes_integers() {
626 test_deserialization("25", Fraction::new(25, 1));
627 test_deserialization("77", Fraction::new(77, 1));
628 test_deserialization("100", Fraction::new(100, 1));
629 }
630
631 #[test]
632 fn deserializes_floats() {
633 test_deserialization("2.5", Fraction::new(5, 2));
634 test_deserialization("1.33", Fraction::new(5447, 4096));
635 test_deserialization("10.0", Fraction::new(10, 1));
636 }
637
638 #[test]
639 fn deserializes_flat_percentages() {
640 test_deserialization("\"25%\"", Fraction::new(1, 4));
641 test_deserialization("\"77%\"", Fraction::new(77, 100));
642 test_deserialization("\"100%\"", Fraction::new(1, 1));
643 }
644
645 #[test]
646 fn deserializes_fraction_arrays() {
647 test_deserialization("[1,2]", Fraction::new(1, 2));
648 test_deserialization("[33, 100]", Fraction::new(33, 100));
649 }
650
651 #[test]
652 fn percentage_equality() {
653 assert_eq!(Fraction::percentage(10), Fraction::percentage(10));
654 assert_eq!(Fraction::percentage(20), Fraction::new(1, 5));
655 assert_eq!(Fraction::new(35, 100), Fraction::percentage(35));
656 assert_eq!(Fraction::new(3, 4), Fraction::new(12, 16));
657 }
658
659 #[test]
660 fn percentage_inequality() {
661 assert_ne!(Fraction::percentage(10), Fraction::percentage(100));
662 assert_ne!(Fraction::percentage(20), Fraction::new(1, 20));
663 assert_ne!(Fraction::new(35, 100), Fraction::percentage(12));
664 assert_ne!(Fraction::new(3, 4), Fraction::new(3, 5));
665 }
666
667 #[test]
668 fn percentage_ordering() {
669 let mut percentages = vec![
670 Fraction::new(3, 4),
671 Fraction::new(3, 200),
672 Fraction::percentage(1),
673 Fraction::new(2, 7),
674 Fraction::new(2, 100),
675 Fraction::percentage(100),
676 Fraction::new(1, 4),
677 Fraction::new(1, 2),
678 Fraction::percentage(60),
679 ];
680 percentages.sort();
681 pretty_assertions::assert_eq!(
682 percentages,
683 vec![
684 Fraction::percentage(1),
685 Fraction::new(3, 200),
686 Fraction::new(2, 100),
687 Fraction::new(1, 4),
688 Fraction::new(2, 7),
689 Fraction::new(1, 2),
690 Fraction::percentage(60),
691 Fraction::new(3, 4),
692 Fraction::percentage(100),
693 ]
694 );
695 }
696
697 #[test]
698 fn floor_division() {
699 assert_eq!(Fraction::percentage(1).floor(), 0);
700 assert_eq!(Fraction::new(77, 12).floor(), 6);
701 assert_eq!(Fraction::percentage(2500).floor(), 25);
702 assert_eq!(Fraction::new(33, 15).floor(), 2);
703 assert_eq!(Fraction::new(1020, 25).floor(), 40);
704 assert_eq!(Fraction::new(1, 2).floor(), 0);
705 }
706
707 #[test]
708 fn round_division() {
709 assert_eq!(Fraction::percentage(1).round(), 0);
710 assert_eq!(Fraction::new(77, 12).round(), 6);
711 assert_eq!(Fraction::percentage(2500).round(), 25);
712 assert_eq!(Fraction::new(33, 15).round(), 2);
713 assert_eq!(Fraction::new(1020, 25).round(), 41);
714
715 assert_eq!(Fraction::new(1, 2).round(), 1);
716 assert_eq!(Fraction::new(2, 2).round(), 1);
717 assert_eq!(Fraction::new(3, 2).round(), 2);
718 assert_eq!(Fraction::new(4, 2).round(), 2);
719
720 assert_eq!(Fraction::new(1, 7).round(), 0);
721 assert_eq!(Fraction::new(2, 7).round(), 0);
722 assert_eq!(Fraction::new(3, 7).round(), 0);
723 assert_eq!(Fraction::new(4, 7).round(), 1);
724 assert_eq!(Fraction::new(5, 7).round(), 1);
725 assert_eq!(Fraction::new(6, 7).round(), 1);
726 assert_eq!(Fraction::new(7, 7).round(), 1);
727 assert_eq!(Fraction::new(8, 7).round(), 1);
728 }
729
730 #[test]
731 fn ceil_division() {
732 assert_eq!(Fraction::percentage(1).ceil(), 1);
733 assert_eq!(Fraction::new(77, 12).ceil(), 7);
734 assert_eq!(Fraction::percentage(2500).ceil(), 25);
735 }
736
737 #[test]
738 fn integer_addition() {
739 assert_eq!(Fraction::percentage(1) + 10000, Fraction::new(1000001, 100));
740 assert_eq!(Fraction::new(12, 77) + 2, Fraction::new(166, 77));
741 assert_eq!(Fraction::percentage(25) + 0, Fraction::new(1, 4));
742 }
743
744 #[test]
745 fn fraction_addition() {
746 assert_eq!(
747 Fraction::new(12, 77) + Fraction::new(5, 6),
748 Fraction::new(457, 462)
749 );
750 assert_eq!(
751 Fraction::new(12, 12) + Fraction::new(53, 53),
752 Fraction::from(2)
753 );
754 assert_eq!(
755 Fraction::new(1, 4) + Fraction::new(2, 4),
756 Fraction::new(3, 4)
757 );
758 }
759
760 #[test]
761 fn integer_subtraction() {
762 assert_eq!(Fraction::percentage(1) - 10000, Fraction::new(-999999, 100));
763 assert_eq!(Fraction::new(2000, 77) - 2, Fraction::new(1846, 77));
764 assert_eq!(Fraction::percentage(25) - 0, Fraction::new(1, 4));
765 }
766
767 #[test]
768 fn fraction_subtraction() {
769 assert_eq!(
770 Fraction::new(12, 77) - Fraction::new(5, 6),
771 Fraction::new(-313, 462)
772 );
773 assert_eq!(
774 Fraction::new(12, 12) - Fraction::new(53, 53),
775 Fraction::from(0)
776 );
777 assert_eq!(
778 Fraction::new(2, 4) - Fraction::new(1, 4),
779 Fraction::new(1, 4)
780 );
781 }
782
783 #[test]
784 fn integer_multiplication() {
785 assert_eq!(Fraction::percentage(1) * 10000, Fraction::from(100));
786 assert_eq!(Fraction::new(12, 77) * 85, Fraction::new(1020, 77));
787 assert_eq!(Fraction::percentage(25) * 100, Fraction::from(25));
788 assert_eq!(Fraction::percentage(25) * 1, Fraction::new(1, 4));
789 assert_eq!(Fraction::new(10, 50) * 2, Fraction::new(2, 5));
790 }
791
792 #[test]
793 fn fraction_multiplication() {
794 assert_eq!(
795 Fraction::new(12, 77) * Fraction::new(5, 6),
796 Fraction::new(10, 77)
797 );
798 assert_eq!(
799 Fraction::new(12, 12) * Fraction::new(53, 53),
800 Fraction::from(1)
801 );
802 assert_eq!(
803 Fraction::new(1, 4) * Fraction::new(2, 4),
804 Fraction::new(1, 8)
805 );
806 }
807
808 #[test]
809 fn integer_division() {
810 assert_eq!(Fraction::percentage(1) / 10000, Fraction::new(1, 1000000));
811 assert_eq!(Fraction::new(12, 77) / 85, Fraction::new(12, 6545));
812 assert_eq!(Fraction::percentage(25) / 100, Fraction::new(1, 400));
813 assert_eq!(Fraction::percentage(25) / 1, Fraction::new(1, 4));
814 assert_eq!(Fraction::new(10, 50) / 2, Fraction::new(1, 10));
815 }
816
817 #[test]
818 fn fraction_division() {
819 assert_eq!(
820 Fraction::new(12, 77) / Fraction::new(5, 6),
821 Fraction::new(72, 385)
822 );
823 assert_eq!(
824 Fraction::new(12, 12) / Fraction::new(53, 53),
825 Fraction::from(1)
826 );
827 assert_eq!(
828 Fraction::new(1, 4) / Fraction::new(2, 4),
829 Fraction::new(1, 2)
830 );
831 }
832
833 #[test]
834 fn fraction_exponentiation() {
835 assert_eq!(
836 Fraction::from(12).pow::<i32>(Fraction::from(5)),
837 Ok(Fraction::new(248832, 1))
838 );
839 assert_eq!(
840 Fraction::from(-12).pow::<i32>(Fraction::from(5)),
841 Ok(Fraction::new(-248832, 1))
842 );
843 assert_eq!(
844 Fraction::new(25, 2).pow::<i32>(Fraction::from(4)),
845 Ok(Fraction::new(390625, 16))
846 );
847 assert_eq!(
848 Fraction::new(1, 2).pow(Fraction::new(4, 2)),
849 Ok(Fraction::new(1, 4))
850 );
851 assert_eq!(
853 Fraction::new(1, 2).pow(Fraction::new(3, 2)),
854 Ok(Fraction::new(1, 2))
855 );
856 assert_eq!(
857 Fraction::new(33, 7).pow(Fraction::new(4, 7)),
858 Ok(Fraction::new(7, 3))
859 );
860
861 assert_eq!(
862 Fraction::new(1, 2).pow(Fraction::new(-4, 2)),
863 Ok(Fraction::new(4, 1))
864 );
865 assert_eq!(
866 Fraction::new(1, 2).pow(Fraction::new(4, -2)),
867 Ok(Fraction::new(4, 1))
868 );
869
870 assert_eq!(
871 Fraction::new(1, 2).pow(Fraction::new(-3, 2)),
872 Ok(Fraction::new(2, 1))
873 );
874 assert_eq!(
875 Fraction::new(33, 7).pow(Fraction::new(4, -7)),
876 Ok(Fraction::new(3, 7))
877 );
878 }
879}