gluesql_core/data/value/binary_op/
f64.rs

1use {
2    super::TryBinaryOperator,
3    crate::{
4        data::{NumericBinaryOperator, ValueError},
5        prelude::Value,
6        result::Result,
7    },
8    Value::*,
9    rust_decimal::prelude::Decimal,
10    std::cmp::Ordering,
11};
12
13impl PartialEq<Value> for f64 {
14    fn eq(&self, other: &Value) -> bool {
15        let lhs = *self;
16
17        match *other {
18            I8(rhs) => (lhs - f64::from(rhs)).abs() < f64::EPSILON,
19            I16(rhs) => (lhs - f64::from(rhs)).abs() < f64::EPSILON,
20            I32(rhs) => (lhs - f64::from(rhs)).abs() < f64::EPSILON,
21            I64(rhs) => (lhs - (rhs as f64)).abs() < f64::EPSILON,
22            I128(rhs) => (lhs - (rhs as f64)).abs() < f64::EPSILON,
23            U8(rhs) => (lhs - f64::from(rhs)).abs() < f64::EPSILON,
24            U16(rhs) => (lhs - f64::from(rhs)).abs() < f64::EPSILON,
25            U32(rhs) => (lhs - f64::from(rhs)).abs() < f64::EPSILON,
26            U64(rhs) => (lhs - (rhs as f64)).abs() < f64::EPSILON,
27            U128(rhs) => (lhs - (rhs as f64)).abs() < f64::EPSILON,
28            F32(rhs) => (lhs - f64::from(rhs)).abs() < f64::EPSILON,
29            F64(rhs) => (lhs - rhs).abs() < f64::EPSILON,
30            Decimal(rhs) => Decimal::from_f64_retain(lhs).is_some_and(|x| rhs == x),
31            _ => false,
32        }
33    }
34}
35
36impl PartialOrd<Value> for f64 {
37    fn partial_cmp(&self, other: &Value) -> Option<Ordering> {
38        match *other {
39            I8(rhs) => self.partial_cmp(&f64::from(rhs)),
40            I16(rhs) => self.partial_cmp(&f64::from(rhs)),
41            I32(rhs) => self.partial_cmp(&f64::from(rhs)),
42            I64(rhs) => self.partial_cmp(&(rhs as f64)),
43            I128(rhs) => self.partial_cmp(&(rhs as f64)),
44            U8(rhs) => self.partial_cmp(&f64::from(rhs)),
45            U16(rhs) => self.partial_cmp(&f64::from(rhs)),
46            U32(rhs) => self.partial_cmp(&f64::from(rhs)),
47            U64(rhs) => self.partial_cmp(&(rhs as f64)),
48            U128(rhs) => self.partial_cmp(&(rhs as f64)),
49            F32(rhs) => self.partial_cmp(&f64::from(rhs)),
50            F64(rhs) => self.partial_cmp(&rhs),
51            Decimal(rhs) => Decimal::from_f64_retain(*self).and_then(|x| x.partial_cmp(&rhs)),
52            _ => None,
53        }
54    }
55}
56
57impl TryBinaryOperator for f64 {
58    type Rhs = Value;
59
60    fn try_add(&self, rhs: &Self::Rhs) -> Result<Value> {
61        let lhs = *self;
62
63        match *rhs {
64            I8(rhs) => Ok(F64(lhs + f64::from(rhs))),
65            I16(rhs) => Ok(F64(lhs + f64::from(rhs))),
66            I32(rhs) => Ok(F64(lhs + f64::from(rhs))),
67            I64(rhs) => Ok(F64(lhs + rhs as f64)),
68            I128(rhs) => Ok(F64(lhs + rhs as f64)),
69            U8(rhs) => Ok(F64(lhs + f64::from(rhs))),
70            U16(rhs) => Ok(F64(lhs + f64::from(rhs))),
71            U32(rhs) => Ok(F64(lhs + f64::from(rhs))),
72            U64(rhs) => Ok(F64(lhs + rhs as f64)),
73            U128(rhs) => Ok(F64(lhs + rhs as f64)),
74            F32(rhs) => Ok(F64(lhs + f64::from(rhs))),
75            F64(rhs) => Ok(F64(lhs + rhs)),
76            Decimal(rhs) => Decimal::from_f64_retain(lhs).map_or_else(
77                || Err(ValueError::FloatToDecimalConversionFailure(lhs).into()),
78                |x| Ok(Decimal(x + rhs)),
79            ),
80            Null => Ok(Null),
81            _ => Err(ValueError::NonNumericMathOperation {
82                lhs: F64(lhs),
83                operator: NumericBinaryOperator::Add,
84                rhs: rhs.clone(),
85            }
86            .into()),
87        }
88    }
89
90    fn try_subtract(&self, rhs: &Self::Rhs) -> Result<Value> {
91        let lhs = *self;
92
93        match *rhs {
94            I8(rhs) => Ok(F64(lhs - f64::from(rhs))),
95            I16(rhs) => Ok(F64(lhs - f64::from(rhs))),
96            I32(rhs) => Ok(F64(lhs - f64::from(rhs))),
97            I64(rhs) => Ok(F64(lhs - rhs as f64)),
98            I128(rhs) => Ok(F64(lhs - rhs as f64)),
99            U8(rhs) => Ok(F64(lhs - f64::from(rhs))),
100            U16(rhs) => Ok(F64(lhs - f64::from(rhs))),
101            U32(rhs) => Ok(F64(lhs - f64::from(rhs))),
102            U64(rhs) => Ok(F64(lhs - rhs as f64)),
103            U128(rhs) => Ok(F64(lhs - rhs as f64)),
104            F32(rhs) => Ok(F64(lhs - f64::from(rhs))),
105            F64(rhs) => Ok(F64(lhs - rhs)),
106            Decimal(rhs) => Decimal::from_f64_retain(lhs).map_or_else(
107                || Err(ValueError::FloatToDecimalConversionFailure(lhs).into()),
108                |x| Ok(Decimal(x - rhs)),
109            ),
110            Null => Ok(Null),
111            _ => Err(ValueError::NonNumericMathOperation {
112                lhs: F64(lhs),
113                operator: NumericBinaryOperator::Subtract,
114                rhs: rhs.clone(),
115            }
116            .into()),
117        }
118    }
119
120    fn try_multiply(&self, rhs: &Self::Rhs) -> Result<Value> {
121        let lhs = *self;
122
123        match *rhs {
124            I8(rhs) => Ok(F64(lhs * f64::from(rhs))),
125            I16(rhs) => Ok(F64(lhs * f64::from(rhs))),
126            I32(rhs) => Ok(F64(lhs * f64::from(rhs))),
127            I64(rhs) => Ok(F64(lhs * rhs as f64)),
128            I128(rhs) => Ok(F64(lhs * rhs as f64)),
129            U8(rhs) => Ok(F64(lhs * f64::from(rhs))),
130            U16(rhs) => Ok(F64(lhs * f64::from(rhs))),
131            U32(rhs) => Ok(F64(lhs * f64::from(rhs))),
132            U64(rhs) => Ok(F64(lhs * rhs as f64)),
133            U128(rhs) => Ok(F64(lhs * rhs as f64)),
134            F32(rhs) => Ok(F64(lhs * f64::from(rhs))),
135            F64(rhs) => Ok(F64(lhs * rhs)),
136            Interval(rhs) => Ok(Interval(lhs * rhs)),
137            Decimal(rhs) => Decimal::from_f64_retain(lhs).map_or_else(
138                || Err(ValueError::FloatToDecimalConversionFailure(lhs).into()),
139                |x| Ok(Decimal(x * rhs)),
140            ),
141            Null => Ok(Null),
142            _ => Err(ValueError::NonNumericMathOperation {
143                lhs: F64(lhs),
144                operator: NumericBinaryOperator::Multiply,
145                rhs: rhs.clone(),
146            }
147            .into()),
148        }
149    }
150
151    fn try_divide(&self, rhs: &Self::Rhs) -> Result<Value> {
152        let lhs = *self;
153
154        match *rhs {
155            I8(rhs) => Ok(F64(lhs / f64::from(rhs))),
156            I16(rhs) => Ok(F64(lhs / f64::from(rhs))),
157            I32(rhs) => Ok(F64(lhs / f64::from(rhs))),
158            I64(rhs) => Ok(F64(lhs / rhs as f64)),
159            I128(rhs) => Ok(F64(lhs / rhs as f64)),
160            U8(rhs) => Ok(F64(lhs / f64::from(rhs))),
161            U16(rhs) => Ok(F64(lhs / f64::from(rhs))),
162            U32(rhs) => Ok(F64(lhs / f64::from(rhs))),
163            U64(rhs) => Ok(F64(lhs / rhs as f64)),
164            U128(rhs) => Ok(F64(lhs / rhs as f64)),
165            F32(rhs) => Ok(F64(lhs / f64::from(rhs))),
166            F64(rhs) => Ok(F64(lhs / rhs)),
167            Decimal(rhs) => Decimal::from_f64_retain(lhs).map_or_else(
168                || Err(ValueError::FloatToDecimalConversionFailure(lhs).into()),
169                |x| Ok(Decimal(x / rhs)),
170            ),
171            Null => Ok(Null),
172            _ => Err(ValueError::NonNumericMathOperation {
173                lhs: F64(lhs),
174                operator: NumericBinaryOperator::Divide,
175                rhs: rhs.clone(),
176            }
177            .into()),
178        }
179    }
180
181    fn try_modulo(&self, rhs: &Self::Rhs) -> Result<Value> {
182        let lhs = *self;
183
184        match *rhs {
185            I8(rhs) => Ok(F64(lhs % f64::from(rhs))),
186            I16(rhs) => Ok(F64(lhs % f64::from(rhs))),
187            I32(rhs) => Ok(F64(lhs % f64::from(rhs))),
188            I64(rhs) => Ok(F64(lhs % rhs as f64)),
189            I128(rhs) => Ok(F64(lhs % rhs as f64)),
190            U8(rhs) => Ok(F64(lhs % f64::from(rhs))),
191            U16(rhs) => Ok(F64(lhs % f64::from(rhs))),
192            U32(rhs) => Ok(F64(lhs % f64::from(rhs))),
193            U64(rhs) => Ok(F64(lhs % rhs as f64)),
194            U128(rhs) => Ok(F64(lhs % rhs as f64)),
195            F32(rhs) => Ok(F64(lhs % f64::from(rhs))),
196            F64(rhs) => Ok(F64(lhs % rhs)),
197            Decimal(rhs) => match Decimal::from_f64_retain(lhs) {
198                Some(x) => x.checked_rem(rhs).map_or_else(
199                    || {
200                        Err(ValueError::BinaryOperationOverflow {
201                            lhs: F64(lhs),
202                            operator: NumericBinaryOperator::Modulo,
203                            rhs: Decimal(rhs),
204                        }
205                        .into())
206                    },
207                    |y| Ok(Decimal(y)),
208                ),
209                _ => Err(ValueError::FloatToDecimalConversionFailure(lhs).into()),
210            },
211            Null => Ok(Null),
212            _ => Err(ValueError::NonNumericMathOperation {
213                lhs: F64(lhs),
214                operator: NumericBinaryOperator::Modulo,
215                rhs: rhs.clone(),
216            }
217            .into()),
218        }
219    }
220}
221
222#[cfg(test)]
223mod tests {
224    use {
225        super::{TryBinaryOperator, Value::*},
226        crate::data::{NumericBinaryOperator, ValueError},
227        rust_decimal::prelude::Decimal,
228        std::cmp::Ordering,
229    };
230
231    #[test]
232    fn eq() {
233        let base = 1.0_f64;
234
235        assert_eq!(base, I8(1));
236        assert_eq!(base, I16(1));
237        assert_eq!(base, I32(1));
238        assert_eq!(base, I64(1));
239        assert_eq!(base, I128(1));
240        assert_eq!(base, U8(1));
241        assert_eq!(base, U16(1));
242        assert_eq!(base, U32(1));
243        assert_eq!(base, U64(1));
244        assert_eq!(base, U128(1));
245        assert_eq!(base, F32(1.0_f32));
246        assert_eq!(base, F64(1.0));
247        assert_eq!(base, Decimal(Decimal::from(1)));
248
249        assert_ne!(base, Bool(true));
250    }
251
252    #[test]
253    fn partial_cmp() {
254        let base = 1.0_f64;
255
256        assert_eq!(base.partial_cmp(&I8(1)), Some(Ordering::Equal));
257        assert_eq!(base.partial_cmp(&I16(1)), Some(Ordering::Equal));
258        assert_eq!(base.partial_cmp(&I32(1)), Some(Ordering::Equal));
259        assert_eq!(base.partial_cmp(&I64(1)), Some(Ordering::Equal));
260        assert_eq!(base.partial_cmp(&I128(1)), Some(Ordering::Equal));
261        assert_eq!(base.partial_cmp(&U8(1)), Some(Ordering::Equal));
262        assert_eq!(base.partial_cmp(&U16(1)), Some(Ordering::Equal));
263        assert_eq!(base.partial_cmp(&U32(1)), Some(Ordering::Equal));
264        assert_eq!(base.partial_cmp(&U64(1)), Some(Ordering::Equal));
265        assert_eq!(base.partial_cmp(&U128(1)), Some(Ordering::Equal));
266        assert_eq!(base.partial_cmp(&F32(1.0_f32)), Some(Ordering::Equal));
267        assert_eq!(base.partial_cmp(&F64(1.0)), Some(Ordering::Equal));
268        assert_eq!(
269            base.partial_cmp(&Decimal(Decimal::ONE)),
270            Some(Ordering::Equal)
271        );
272
273        assert_eq!(base.partial_cmp(&Bool(true)), None);
274    }
275
276    #[test]
277    fn try_add() {
278        let base = 1.0_f64;
279
280        assert!(matches!(base.try_add(&I8(1)), Ok(F64(x)) if (x - 2.0).abs() < f64::EPSILON ));
281        assert!(matches!(base.try_add(&I16(1)), Ok(F64(x)) if (x - 2.0).abs() < f64::EPSILON ));
282        assert!(matches!(base.try_add(&I32(1)), Ok(F64(x)) if (x - 2.0).abs() < f64::EPSILON ));
283        assert!(matches!(base.try_add(&I64(1)), Ok(F64(x)) if (x - 2.0).abs() < f64::EPSILON ));
284        assert!(matches!(base.try_add(&I128(1)), Ok(F64(x)) if (x - 2.0).abs() < f64::EPSILON ));
285        assert!(matches!(base.try_add(&U8(1)), Ok(F64(x)) if (x - 2.0).abs() < f64::EPSILON ));
286        assert!(matches!(base.try_add(&U16(1)), Ok(F64(x)) if (x - 2.0).abs() < f64::EPSILON ));
287        assert!(matches!(base.try_add(&U32(1)),Ok(F64(x)) if (x-2.0).abs() < f64::EPSILON));
288        assert!(matches!(base.try_add(&U64(1)),Ok(F64(x)) if (x-2.0).abs() < f64::EPSILON));
289        assert!(matches!(base.try_add(&U128(1)),Ok(F64(x)) if (x-2.0).abs()<f64::EPSILON));
290        assert!(
291            matches!(base.try_add(&F32(1.0_f32)), Ok(F64(x)) if (x - 2.0).abs() < f64::EPSILON )
292        );
293        assert!(matches!(base.try_add(&F64(1.0)), Ok(F64(x)) if (x - 2.0).abs() < f64::EPSILON ));
294        assert!(
295            matches!(base.try_add(&Decimal(Decimal::ONE)), Ok(Decimal(x)) if x == Decimal::TWO)
296        );
297
298        assert_eq!(
299            base.try_add(&Bool(true)),
300            Err(ValueError::NonNumericMathOperation {
301                lhs: F64(1.0),
302                operator: NumericBinaryOperator::Add,
303                rhs: Bool(true)
304            }
305            .into())
306        );
307    }
308
309    #[test]
310    fn try_subtract() {
311        let base = 1.0_f64;
312
313        assert!(matches!(base.try_subtract(&I8(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON ));
314        assert!(
315            matches!(base.try_subtract(&I16(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON )
316        );
317        assert!(
318            matches!(base.try_subtract(&I32(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON )
319        );
320        assert!(
321            matches!(base.try_subtract(&I64(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON )
322        );
323        assert!(
324            matches!(base.try_subtract(&I128(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON )
325        );
326        assert!(matches!(base.try_subtract(&U8(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON ));
327        assert!(
328            matches!(base.try_subtract(&U16(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON )
329        );
330        assert!(
331            matches!(base.try_subtract(&U32(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON )
332        );
333
334        assert!(
335            matches!(base.try_subtract(&U64(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON )
336        );
337        assert!(
338            matches!(base.try_subtract(&U128(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON )
339        );
340
341        assert!(
342            matches!(base.try_subtract(&F32(1.0_f32)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON )
343        );
344        assert!(
345            matches!(base.try_subtract(&F64(1.0)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON )
346        );
347        assert!(
348            matches!(base.try_subtract(&Decimal(Decimal::ONE)), Ok(Decimal(x)) if x == Decimal::ZERO)
349        );
350
351        assert_eq!(
352            base.try_subtract(&Bool(true)),
353            Err(ValueError::NonNumericMathOperation {
354                lhs: F64(1.0),
355                operator: NumericBinaryOperator::Subtract,
356                rhs: Bool(true)
357            }
358            .into())
359        );
360    }
361
362    #[test]
363    fn try_multiply() {
364        let base = 1.0_f64;
365
366        assert!(matches!(base.try_multiply(&I8(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON ));
367        assert!(
368            matches!(base.try_multiply(&I16(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON )
369        );
370        assert!(
371            matches!(base.try_multiply(&I32(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON )
372        );
373        assert!(
374            matches!(base.try_multiply(&I64(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON )
375        );
376        assert!(
377            matches!(base.try_multiply(&I128(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON )
378        );
379        assert!(matches!(base.try_multiply(&U8(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON ));
380        assert!(
381            matches!(base.try_multiply(&U16(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON )
382        );
383        assert!(
384            matches!(base.try_multiply(&U32(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON )
385        );
386        assert!(
387            matches!(base.try_multiply(&U64(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON )
388        );
389        assert!(
390            matches!(base.try_multiply(&U128(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON )
391        );
392        assert!(
393            matches!(base.try_multiply(&F32(1.0_f32)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON )
394        );
395        assert!(
396            matches!(base.try_multiply(&F64(1.0)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON )
397        );
398        assert!(
399            matches!(base.try_multiply(&Decimal(Decimal::ONE)), Ok(Decimal(x)) if x == Decimal::ONE)
400        );
401
402        assert_eq!(
403            base.try_multiply(&Bool(true)),
404            Err(ValueError::NonNumericMathOperation {
405                lhs: F64(1.0),
406                operator: NumericBinaryOperator::Multiply,
407                rhs: Bool(true)
408            }
409            .into())
410        );
411    }
412
413    #[test]
414    fn try_divide() {
415        let base = 1.0_f64;
416
417        assert!(matches!(base.try_divide(&I8(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON ));
418        assert!(matches!(base.try_divide(&I16(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON ));
419        assert!(matches!(base.try_divide(&I32(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON ));
420        assert!(matches!(base.try_divide(&I64(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON ));
421        assert!(matches!(base.try_divide(&I128(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON ));
422        assert!(matches!(base.try_divide(&U8(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON ));
423        assert!(matches!(base.try_divide(&U16(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON ));
424        assert!(matches!(base.try_divide(&U32(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON ));
425        assert!(matches!(base.try_divide(&U64(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON ));
426        assert!(matches!(base.try_divide(&U128(1)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON ));
427
428        assert!(
429            matches!(base.try_divide(&F32(1.0_f32)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON )
430        );
431        assert!(
432            matches!(base.try_divide(&F64(1.0)), Ok(F64(x)) if (x - 1.0).abs() < f64::EPSILON )
433        );
434        assert!(
435            matches!(2.0_f64.try_divide(&Decimal(Decimal::TWO)), Ok(Decimal(x)) if x == Decimal::ONE)
436        );
437
438        assert_eq!(
439            base.try_divide(&Bool(true)),
440            Err(ValueError::NonNumericMathOperation {
441                lhs: F64(1.0),
442                operator: NumericBinaryOperator::Divide,
443                rhs: Bool(true)
444            }
445            .into())
446        );
447    }
448
449    #[test]
450    fn try_modulo() {
451        let base = 1.0_f64;
452
453        assert!(matches!(base.try_modulo(&I8(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON ));
454        assert!(matches!(base.try_modulo(&I16(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON ));
455        assert!(matches!(base.try_modulo(&I32(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON ));
456        assert!(matches!(base.try_modulo(&I64(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON ));
457        assert!(matches!(base.try_modulo(&I128(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON ));
458        assert!(matches!(base.try_modulo(&U8(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON ));
459        assert!(matches!(base.try_modulo(&U16(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON ));
460        assert!(matches!(base.try_modulo(&U32(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON ));
461        assert!(matches!(base.try_modulo(&U64(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON ));
462        assert!(matches!(base.try_modulo(&U128(1)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON ));
463
464        assert!(
465            matches!(base.try_modulo(&F32(1.0_f32)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON )
466        );
467        assert!(
468            matches!(base.try_modulo(&F64(1.0)), Ok(F64(x)) if (x - 0.0).abs() < f64::EPSILON )
469        );
470        assert!(
471            matches!(base.try_modulo(&Decimal(Decimal::ONE)), Ok(Decimal(x)) if x == Decimal::ZERO)
472        );
473        assert_eq!(
474            f64::MAX.try_modulo(&Decimal(Decimal::TWO)),
475            Err(ValueError::FloatToDecimalConversionFailure(f64::MAX).into())
476        );
477        assert_eq!(
478            base.try_modulo(&Decimal(Decimal::ZERO)),
479            Err(ValueError::BinaryOperationOverflow {
480                lhs: F64(base),
481                rhs: Decimal(Decimal::ZERO),
482                operator: NumericBinaryOperator::Modulo,
483            }
484            .into())
485        );
486
487        assert_eq!(
488            base.try_modulo(&Bool(true)),
489            Err(ValueError::NonNumericMathOperation {
490                lhs: F64(1.0),
491                operator: NumericBinaryOperator::Modulo,
492                rhs: Bool(true)
493            }
494            .into())
495        );
496    }
497}