1#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8pub struct Rat {
9 n: i128,
10 d: i128, }
12
13const fn gcd(mut a: i128, mut b: i128) -> i128 {
14 if a < 0 {
15 a = -a;
16 }
17 if b < 0 {
18 b = -b;
19 }
20 while b != 0 {
21 let t = a % b;
22 a = b;
23 b = t;
24 }
25 if a == 0 {
26 1
27 } else {
28 a
29 }
30}
31
32#[allow(clippy::should_implement_trait)]
35impl Rat {
36 pub fn new(n: i128, d: i128) -> Rat {
37 let (mut n, mut d) = if d < 0 { (-n, -d) } else { (n, d) };
38 let g = gcd(n, d);
39 n /= g;
40 d /= g;
41 Rat { n, d }
42 }
43
44 pub fn int(v: i64) -> Rat {
45 Rat { n: v as i128, d: 1 }
46 }
47
48 pub fn from_u64(v: u64) -> Rat {
49 Rat { n: v as i128, d: 1 }
50 }
51
52 pub fn mul(self, o: Rat) -> Rat {
53 let g1 = gcd(self.n, o.d);
55 let g2 = gcd(o.n, self.d);
56 Rat::new((self.n / g1) * (o.n / g2), (self.d / g2) * (o.d / g1))
57 }
58
59 pub fn div(self, o: Rat) -> Rat {
60 self.mul(Rat::new(o.d, o.n))
61 }
62
63 pub fn add(self, o: Rat) -> Rat {
64 Rat::new(self.n * o.d + o.n * self.d, self.d * o.d)
65 }
66
67 pub fn sub(self, o: Rat) -> Rat {
68 Rat::new(self.n * o.d - o.n * self.d, self.d * o.d)
69 }
70
71 pub fn pow10(exp: i64) -> Rat {
73 let e = exp.unsigned_abs().min(38);
74 let mut p: i128 = 1;
75 let mut i = 0;
76 while i < e {
77 p *= 10;
78 i += 1;
79 }
80 if exp >= 0 {
81 Rat { n: p, d: 1 }
82 } else {
83 Rat { n: 1, d: p }
84 }
85 }
86
87 pub fn round(self) -> i64 {
89 let half = self.d / 2;
90 let n = if self.n >= 0 {
91 self.n + half
92 } else {
93 self.n - half
94 };
95 (n / self.d) as i64
96 }
97
98 pub fn to_f64(self) -> f64 {
99 let q = self.n / self.d;
101 let r = self.n % self.d;
102 q as f64 + (r as f64) / (self.d as f64)
103 }
104
105 pub fn from_f64(v: f64) -> Rat {
108 if !v.is_finite() {
109 return Rat::int(0);
110 }
111 if v == (v as i64) as f64 {
112 return Rat::int(v as i64);
113 }
114 let mut d: i128 = 1;
118 let mut x = v;
119 for _ in 0..12 {
120 if x == (x as i128) as f64 {
121 break;
122 }
123 x *= 10.0;
124 d *= 10;
125 }
126 let n = if x >= 0.0 {
127 (x + 0.5) as i128
128 } else {
129 (x - 0.5) as i128
130 };
131 Rat::new(n, d)
132 }
133}