1use super::{Integer, IntegerRef, Rational, RationalRef};
18use log::trace;
19use num::traits::Zero;
20
21impl Integer for f64 {
22 fn from_usize(i: usize) -> Self {
23 i as f64
24 }
25
26 #[cfg(test)]
27 fn get_positive_test_values() -> Vec<Self> {
28 let mut result = Vec::new();
29 for i in 0..=30 {
30 result.push((1 << i) as f64);
31 result.push((0x7FFF_FFFF ^ (1 << i)) as f64);
32 }
33 result
34 }
35}
36
37impl IntegerRef<f64> for &f64 {}
38
39impl RationalRef<&f64, f64> for &f64 {}
40
41impl Rational<f64> for f64 {
42 fn from_int(i: f64) -> Self {
43 i
44 }
45
46 fn ratio_i(num: f64, denom: f64) -> Self {
47 num / denom
48 }
49
50 fn to_f64(&self) -> f64 {
51 *self
52 }
53
54 fn assert_eq(a: Self, b: Self, msg: &str) {
55 if a != b {
56 let error = 2f64 * (a - b).abs() / (a.abs() + b.abs());
57 let error_eps = (error / f64::EPSILON).round() as usize;
58 if error_eps <= 1000 {
59 trace!("{msg}: Failed comparison {a} != {b} (error = {error_eps} * eps)");
60 } else {
61 panic!("{msg}: Failed comparison {a} != {b} (error = {error_eps} * eps)");
62 }
63 }
64 }
65
66 fn epsilon() -> Self {
67 Self::zero()
68 }
69
70 fn is_exact() -> bool {
71 true
72 }
73
74 fn description() -> &'static str {
75 "64-bit floating-point arithmetic"
76 }
77
78 fn div_up_as_keep_factor(&self, rhs: &Self) -> Self {
79 self / rhs
80 }
81
82 #[cfg(test)]
83 fn get_positive_test_values() -> Vec<Self> {
84 let mut result = Vec::new();
85 for i in 0..=30 {
86 result.push((1 << i) as f64);
87 }
88 for i in 0..=30 {
89 result.push((0x7FFF_FFFF ^ (1 << i)) as f64);
90 }
91 for i in 0..=30 {
92 result.push(1.0 / (1 << i) as f64);
93 }
94 for i in 0..=30 {
95 result.push(1.0 / (0x7FFF_FFFF ^ (1 << i)) as f64);
96 }
97 result
98 }
99}
100
101#[cfg(test)]
102mod test {
103 use super::*;
104 use crate::util::log_tester::ThreadLocalLogger;
105 use crate::{
106 big_integer_tests, big_numeric_tests, integer_tests, numeric_benchmarks, numeric_tests,
107 };
108 use log::Level::Trace;
109
110 integer_tests!(
111 f64,
112 testi_values_are_positive,
113 testi_is_zero,
114 testi_zero_is_add_neutral,
115 testi_add_is_commutative,
116 testi_opposite,
117 testi_sub_self,
118 testi_add_sub,
119 testi_sub_add,
120 testi_one_is_mul_neutral,
121 testi_mul_is_commutative,
122 );
123
124 big_integer_tests!(
125 f64,
126 None,
127 testi_add_is_associative,
128 testi_mul_is_associative => fail(r"assertion `left == right` failed: (a * b) * c != a * (b * c) for 2147483646, 2147483646, 2147483583
129 left: 9.903519996076708e27
130 right: 9.903519996076707e27"),
131 testi_mul_is_distributive => fail(r"assertion `left == right` failed: a * (b + c) != (a * b) + (a * c) for 2147483646, 1, 2147483519
132 left: 4.6116857392545137e18
133 right: 4.611685739254514e18"),
134 testi_product,
135 );
136
137 numeric_tests!(
138 f64,
139 f64,
140 test_values_are_positive,
141 test_is_exact,
142 test_ratio,
143 test_ratio_invert => fail(r"assertion `left == right` failed: R::ratio(1, a) * a != 1 for 49
144 left: 0.9999999999999999
145 right: 1.0"),
146 test_is_zero,
147 test_zero_is_add_neutral,
148 test_add_is_commutative,
149 test_opposite,
150 test_sub_self,
151 test_add_sub => fail(r"assertion `left == right` failed: (a + b) - b != a for 1, 0.0000000004656613430357376
152 left: 0.9999999999999999
153 right: 1.0"),
154 test_sub_add => fail(r"assertion `left == right` failed: (a - b) + b != a for 0.00000011920928955078125, 2147483646
155 left: 0.0
156 right: 1.1920928955078125e-7"),
157 test_one_is_mul_neutral,
158 test_mul_is_commutative,
159 test_mul_up_is_commutative,
160 test_mul_up_integers,
161 test_mul_up_wrt_mul,
162 test_one_is_div_up_neutral,
163 test_div_up_self,
164 test_mul_div_up => fail(r"assertion `left == right` failed: div_up(a * b, b) != a for 2147483646, 0.000000000465661315280157
165 left: 2147483646.0000002
166 right: 2147483646.0"),
167 test_mul_by_int,
168 test_mul_div_by_int => fail(r"assertion `left == right` failed: a * int(b) / int(b) != a for 0.0000000005321843286349222, 7
169 left: 5.321843286349223e-10
170 right: 5.321843286349222e-10"),
171 test_references,
172 test_assign,
173 );
174
175 big_numeric_tests!(
176 f64,
177 f64,
178 None,
179 test_add_is_associative => fail(r"assertion `left == right` failed: (a + b) + c != a + (b + c) for 1, 1, 0.0000000004656615095692907
180 left: 2.0000000004656617
181 right: 2.0000000004656613"),
182 test_mul_is_associative => fail(r"assertion `left == right` failed: (a * b) * c != a * (b * c) for 2147483646, 2147483646, 2147483583
183 left: 9.903519996076708e27
184 right: 9.903519996076707e27"),
185 test_mul_is_distributive => fail(r"assertion `left == right` failed: a * (b + c) != (a * b) + (a * c) for 2147483646, 1, 2147483519
186 left: 4.6116857392545137e18
187 right: 4.611685739254514e18"),
188 test_mul_by_int_is_associative => fail(r"assertion `left == right` failed: (a * b) * c != a * (b * c) for 0.0000000004656612944634737, 3, 3
189 left: 4.190951650171264e-9
190 right: 4.190951650171263e-9"),
191 test_mul_by_int_is_distributive => fail(r"assertion `left == right` failed: (a + b) * c != (a * c) + (b * c) for 1, 0.0000000004656613985469087, 3
192 left: 3.0000000013969848
193 right: 3.0000000013969843"),
194 test_div_by_int_is_associative => fail(r"assertion `left == right` failed: (a / b) / c != a / (b * c) for 1, 3, 11
195 left: 0.0303030303030303
196 right: 0.030303030303030304"),
197 test_div_by_int_is_distributive => fail(r"assertion `left == right` failed: (a + b) / c != (a / c) + (b / c) for 1, 2, 5
198 left: 0.6
199 right: 0.6000000000000001"),
200 test_sum,
201 test_product,
202 );
203
204 numeric_benchmarks!(f64, f64, bench_add, bench_sub, bench_mul, bench_div_up,);
205
206 #[test]
207 fn test_description() {
208 assert_eq!(f64::description(), "64-bit floating-point arithmetic");
209 }
210
211 #[test]
212 fn test_assert_eq() {
213 let logger = ThreadLocalLogger::start();
214 f64::assert_eq(0.0, 0.0, "Error message");
215 logger.check_target_logs("stv_rs::arithmetic::float64", []);
216
217 let logger = ThreadLocalLogger::start();
218 f64::assert_eq(1.0, 1.0 + f64::EPSILON, "Error message");
219 logger.check_target_logs(
220 "stv_rs::arithmetic::float64",
221 [(
222 Trace,
223 "Error message: Failed comparison 1 != 1.0000000000000002 (error = 1 * eps)",
224 )],
225 );
226
227 let logger = ThreadLocalLogger::start();
228 f64::assert_eq(1.0, 1.0 + 999.0 * f64::EPSILON, "Error message");
229 logger.check_target_logs(
230 "stv_rs::arithmetic::float64",
231 [(
232 Trace,
233 "Error message: Failed comparison 1 != 1.0000000000002218 (error = 999 * eps)",
234 )],
235 );
236
237 let logger = ThreadLocalLogger::start();
238 f64::assert_eq(1.0, 1.0 + 1000.0 * f64::EPSILON, "Error message");
239 logger.check_target_logs(
240 "stv_rs::arithmetic::float64",
241 [(
242 Trace,
243 "Error message: Failed comparison 1 != 1.000000000000222 (error = 1000 * eps)",
244 )],
245 );
246 }
247
248 #[test]
249 #[should_panic(
250 expected = "Error message: Failed comparison 1 != 1.0000000000002223 (error = 1001 * eps)"
251 )]
252 fn test_assert_ne() {
253 f64::assert_eq(1.0, 1.0 + 1001.0 * f64::EPSILON, "Error message");
254 }
255
256 #[test]
257 fn test_display_test_values() {
258 #[rustfmt::skip]
259 let expected_displays = [
260 "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192",
261 "16384", "32768", "65536", "131072", "262144", "524288", "1048576", "2097152", "4194304",
262 "8388608", "16777216", "33554432", "67108864", "134217728", "268435456", "536870912",
263 "1073741824", "2147483646", "2147483645", "2147483643", "2147483639", "2147483631",
264 "2147483615", "2147483583", "2147483519", "2147483391", "2147483135", "2147482623",
265 "2147481599", "2147479551", "2147475455", "2147467263", "2147450879", "2147418111",
266 "2147352575", "2147221503", "2146959359", "2146435071", "2145386495", "2143289343",
267 "2139095039", "2130706431", "2113929215", "2080374783", "2013265919", "1879048191",
268 "1610612735", "1073741823",
269 "1", "0.5", "0.25", "0.125", "0.0625", "0.03125", "0.015625", "0.0078125", "0.00390625",
270 "0.001953125", "0.0009765625", "0.00048828125", "0.000244140625", "0.0001220703125",
271 "0.00006103515625", "0.000030517578125", "0.0000152587890625", "0.00000762939453125",
272 "0.000003814697265625", "0.0000019073486328125", "0.00000095367431640625",
273 "0.000000476837158203125", "0.0000002384185791015625", "0.00000011920928955078125",
274 "0.00000005960464477539063", "0.000000029802322387695313", "0.000000014901161193847656",
275 "0.000000007450580596923828", "0.000000003725290298461914", "0.000000001862645149230957",
276 "0.0000000009313225746154785", "0.0000000004656612877414201",
277 "0.0000000004656612879582606", "0.0000000004656612883919414",
278 "0.0000000004656612892593032", "0.0000000004656612909940266",
279 "0.0000000004656612944634737", "0.0000000004656613014023679",
280 "0.000000000465661315280157", "0.0000000004656613430357376",
281 "0.0000000004656613985469087", "0.0000000004656615095692907",
282 "0.0000000004656617316142135", "0.0000000004656621757046943",
283 "0.000000000465663063888197", "0.0000000004656648402653671",
284 "0.0000000004656683930603658", "0.0000000004656754988130022",
285 "0.0000000004656897109688659", "0.0000000004657181378832345",
286 "0.0000000004657750021247607", "0.0000000004658887722767739",
287 "0.0000000004661164793992049", "0.000000000466572562060278",
288 "0.0000000004674874102216082", "0.0000000004693279118375177",
289 "0.0000000004730527365364029", "0.0000000004806826193874318",
290 "0.0000000004967053733749714", "0.0000000005321843286349222",
291 "0.0000000006208817167958132", "0.0000000009313225754828403"
292 ];
293 let actual_displays: Vec<String> = <f64 as Rational<_>>::get_positive_test_values()
294 .iter()
295 .map(|x| format!("{x}"))
296 .collect();
297 assert_eq!(actual_displays, expected_displays);
298 }
299}