1use super::{Integer, IntegerRef, Rational, RationalRef};
19use num::bigint::ToBigInt;
20use num::rational::Ratio;
21use num::traits::{NumAssign, ToPrimitive, Zero};
22use num::BigInt;
23use std::fmt::{Debug, Display};
24
25#[cfg(test)]
26impl Integer for i64 {
27 #[inline(always)]
28 fn from_usize(i: usize) -> Self {
29 i as i64
30 }
31
32 fn get_positive_test_values() -> Vec<Self> {
33 let mut result = Vec::new();
34 for i in 0..=30 {
35 result.push(1 << i);
36 result.push(0x7FFF_FFFF ^ (1 << i));
37 }
38 result
39 }
40}
41
42#[cfg(test)]
43impl IntegerRef<i64> for &i64 {}
44
45impl Integer for BigInt {
46 fn from_usize(i: usize) -> Self {
47 BigInt::from(i)
48 }
49
50 #[cfg(test)]
51 fn get_positive_test_values() -> Vec<Self> {
52 let mut result = Vec::new();
53 for i in 0..64 {
54 result.push(BigInt::from(1u64 << i));
55 result.push(BigInt::from(!(1u64 << i)));
56 }
57 result
58 }
59}
60
61impl IntegerRef<BigInt> for &BigInt {}
62
63impl<I> RationalRef<&I, Ratio<I>> for &Ratio<I> where I: Clone + num::Integer {}
64
65impl<I> Rational<I> for Ratio<I>
66where
67 I: Display + Debug,
68 I: num::Integer,
69 I: ToPrimitive + ToBigInt,
70 I: Integer + NumAssign,
71 for<'a> &'a I: IntegerRef<I>,
72{
73 fn from_int(i: I) -> Self {
74 Ratio::from_integer(i)
75 }
76
77 fn ratio_i(num: I, denom: I) -> Self {
78 Ratio::new(num, denom)
79 }
80
81 fn to_f64(&self) -> f64 {
82 ToPrimitive::to_f64(self).unwrap()
83 }
84
85 fn epsilon() -> Self {
86 Self::zero()
87 }
88
89 fn is_exact() -> bool {
90 true
91 }
92
93 fn description() -> &'static str {
94 "exact rational arithmetic"
95 }
96
97 fn div_up_as_keep_factor(&self, rhs: &Self) -> Self {
98 self / rhs
99 }
100
101 #[cfg(test)]
102 fn get_positive_test_values() -> Vec<Self> {
103 let mut result = Vec::new();
104 for i in 0..=30 {
105 result.push(Self::ratio(1 << i, 1));
106 }
107 for i in 0..=30 {
108 result.push(Self::ratio(1, 1 << i));
109 }
110 for i in 0..=30 {
111 result.push(Self::ratio(0x7FFF_FFFF ^ (1 << i), 1));
112 }
113 for i in 0..=30 {
114 result.push(Self::ratio(1, 0x7FFF_FFFF ^ (1 << i)));
115 }
116 result
117 }
118}
119
120#[cfg(test)]
121mod test {
122 use super::*;
123 use crate::{
124 big_integer_tests, big_numeric_tests, integer_tests, numeric_benchmarks, numeric_tests,
125 };
126 use num::traits::One;
127 use num::BigRational;
128
129 fn make_ratio(num: i64, denom: i64) -> BigRational {
130 BigRational::ratio_i(BigInt::from(num), BigInt::from(denom))
131 }
132
133 integer_tests!(
134 BigInt,
135 testi_values_are_positive,
136 testi_is_zero,
137 testi_zero_is_add_neutral,
138 testi_add_is_commutative,
139 testi_opposite,
140 testi_sub_self,
141 testi_add_sub,
142 testi_sub_add,
143 testi_one_is_mul_neutral,
144 testi_mul_is_commutative,
145 );
146
147 big_integer_tests!(
148 BigInt,
149 Some(100_000),
150 testi_add_is_associative,
151 testi_mul_is_associative,
152 testi_mul_is_distributive,
153 testi_product,
154 );
155
156 numeric_tests!(
157 BigInt,
158 BigRational,
159 test_values_are_positive,
160 test_is_exact,
161 test_ratio,
162 test_ratio_invert,
163 test_is_zero,
164 test_zero_is_add_neutral,
165 test_add_is_commutative,
166 test_opposite,
167 test_sub_self,
168 test_add_sub,
169 test_sub_add,
170 test_one_is_mul_neutral,
171 test_mul_is_commutative,
172 test_mul_up_is_commutative,
173 test_mul_up_integers,
174 test_mul_up_wrt_mul,
175 test_one_is_div_up_neutral,
176 test_div_up_self,
177 test_mul_div_up,
178 test_mul_by_int,
179 test_mul_div_by_int,
180 test_references,
181 test_assign,
182 );
183
184 big_numeric_tests!(
185 BigInt,
186 BigRational,
187 Some(100_000),
188 test_add_is_associative,
189 test_mul_is_associative,
190 test_mul_is_distributive,
191 test_mul_by_int_is_associative,
192 test_mul_by_int_is_distributive,
193 test_div_by_int_is_associative,
194 test_div_by_int_is_distributive,
195 test_sum,
196 test_product,
197 );
198
199 numeric_benchmarks!(
200 BigInt,
201 BigRational,
202 bench_add,
203 bench_sub,
204 bench_mul,
205 bench_div_up,
206 );
207
208 #[test]
209 fn test_description() {
210 assert_eq!(BigRational::description(), "exact rational arithmetic");
211 }
212
213 #[test]
214 fn test_display() {
215 assert_eq!(format!("{}", BigRational::zero()), "0");
216 assert_eq!(format!("{}", BigRational::one()), "1");
217 assert_eq!(format!("{}", make_ratio(0, 1)), "0");
218 assert_eq!(format!("{}", make_ratio(1, 1)), "1");
219 assert_eq!(format!("{}", make_ratio(1, 2)), "1/2");
220 assert_eq!(format!("{}", make_ratio(1, 23456789)), "1/23456789");
221 assert_eq!(format!("{}", make_ratio(123456789, 1)), "123456789");
222 assert_eq!(format!("{}", make_ratio(-1, 1)), "-1");
223 assert_eq!(format!("{}", make_ratio(-1, 2)), "-1/2");
224 assert_eq!(format!("{}", make_ratio(2, 2)), "1");
225 assert_eq!(format!("{}", make_ratio(60, 14)), "30/7");
226 }
227
228 #[test]
229 fn test_display_test_values() {
230 #[rustfmt::skip]
231 let expected_displays = [
232 "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048", "4096",
233 "8192", "16384", "32768", "65536", "131072", "262144", "524288", "1048576", "2097152",
234 "4194304", "8388608", "16777216", "33554432", "67108864", "134217728", "268435456",
235 "536870912", "1073741824",
236 "1", "1/2", "1/4", "1/8", "1/16", "1/32", "1/64", "1/128", "1/256", "1/512", "1/1024",
237 "1/2048", "1/4096", "1/8192", "1/16384", "1/32768", "1/65536", "1/131072", "1/262144",
238 "1/524288", "1/1048576", "1/2097152", "1/4194304", "1/8388608", "1/16777216",
239 "1/33554432", "1/67108864", "1/134217728", "1/268435456", "1/536870912", "1/1073741824",
240 "2147483646", "2147483645", "2147483643", "2147483639", "2147483631", "2147483615",
241 "2147483583", "2147483519", "2147483391", "2147483135", "2147482623", "2147481599",
242 "2147479551", "2147475455", "2147467263", "2147450879", "2147418111", "2147352575",
243 "2147221503", "2146959359", "2146435071", "2145386495", "2143289343", "2139095039",
244 "2130706431", "2113929215", "2080374783", "2013265919", "1879048191", "1610612735",
245 "1073741823",
246 "1/2147483646", "1/2147483645", "1/2147483643", "1/2147483639", "1/2147483631",
247 "1/2147483615", "1/2147483583", "1/2147483519", "1/2147483391", "1/2147483135",
248 "1/2147482623", "1/2147481599", "1/2147479551", "1/2147475455", "1/2147467263",
249 "1/2147450879", "1/2147418111", "1/2147352575", "1/2147221503", "1/2146959359",
250 "1/2146435071", "1/2145386495", "1/2143289343", "1/2139095039", "1/2130706431",
251 "1/2113929215", "1/2080374783", "1/2013265919", "1/1879048191", "1/1610612735",
252 "1/1073741823",
253 ];
254 let actual_displays: Vec<String> = BigRational::get_positive_test_values()
255 .iter()
256 .map(|x| format!("{x}"))
257 .collect();
258 assert_eq!(actual_displays, expected_displays);
259 }
260}