qfall_math/rational/q/
distance.rs

1// Copyright © 2023 Niklas Siemer
2//
3// This file is part of qFALL-math.
4//
5// qFALL-math is free software: you can redistribute it and/or modify it under
6// the terms of the Mozilla Public License Version 2.0 as published by the
7// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.
8
9//! This module contains the implementation of the [`Distance`] trait for [`Q`].
10
11use super::Q;
12use crate::traits::Distance;
13
14impl<Rational: Into<Q>> Distance<Rational> for Q {
15    type Output = Q;
16
17    /// Computes the absolute distance between a [`Q`] instance and a value that
18    /// implements [`Into<Q>`].
19    ///
20    /// Parameters:
21    /// - `other`: specifies one of the [`Q`] values whose distance
22    ///   is calculated to `self`
23    ///
24    /// Returns the absolute difference, i.e. distance between the two given [`Q`]
25    /// instances as a new [`Q`] instance.
26    ///
27    /// # Examples
28    /// ```
29    /// use qfall_math::rational::Q;
30    /// use qfall_math::traits::*;
31    ///
32    /// let a = Q::from(1);
33    ///
34    /// let distance_0 = a.distance(5);
35    /// let distance_1 = a.distance(10);
36    ///
37    /// # assert_eq!(Q::from(4), distance_0);
38    /// # assert_eq!(Q::from(9), distance_1);
39    /// ```
40    fn distance(&self, other: Rational) -> Self::Output {
41        let other = other.into();
42        let difference = other - self;
43        difference.abs()
44    }
45}
46
47#[cfg(test)]
48mod test_distance {
49    use super::{Distance, Q};
50
51    /// Checks if distance is correctly computed for small [`Q`] values
52    /// and whether distance(a, b) == distance(b, a), distance(a, a) == 0
53    #[test]
54    fn small_values() {
55        let a = Q::ONE;
56        let b = Q::from((5, -15));
57        let zero = Q::ZERO;
58
59        assert_eq!(Q::ONE, a.distance(&zero));
60        assert_eq!(Q::ONE, zero.distance(&a));
61        assert_eq!(Q::from((4, 3)), a.distance(&b));
62        assert_eq!(Q::from((4, 3)), b.distance(&a));
63        assert_eq!(Q::from((1, 3)), b.distance(&zero));
64        assert_eq!(Q::from((1, 3)), zero.distance(&b));
65        assert_eq!(Q::ZERO, b.distance(&b));
66    }
67
68    /// Checks if distance is correctly computed for large [`Q`] values
69    /// and whether distance(a, b) == distance(b, a), distance(a, a) == 0
70    #[test]
71    fn large_values() {
72        let a = Q::from(i64::MAX);
73        let b = Q::from(i64::MIN);
74        let zero = Q::ZERO;
75
76        assert_eq!(&a - &b, a.distance(&b));
77        assert_eq!(&a - &b, b.distance(&a));
78        assert_eq!(a, a.distance(&zero));
79        assert_eq!(a, zero.distance(&a));
80        assert_eq!(&a + Q::ONE, b.distance(&zero));
81        assert_eq!(&a + Q::ONE, zero.distance(&b));
82        assert_eq!(Q::ZERO, a.distance(&a));
83    }
84
85    /// Check whether distance is available for owned [`Q`] and other types
86    #[test]
87    fn availability() {
88        let a = Q::ZERO;
89
90        let u_0 = a.distance(0_u8);
91        let u_1 = a.distance(15_u16);
92        let u_2 = a.distance(35_u32);
93        let u_3 = a.distance(u64::MAX);
94        let i_0 = a.distance(0_i8);
95        let i_1 = a.distance(-15_i16);
96        let i_2 = a.distance(35_i32);
97        let i_3 = a.distance(i64::MIN);
98        let f_0 = a.distance(4.25_f32);
99        let f_1 = a.distance(0.66015625_f64);
100
101        assert_eq!(Q::ZERO, u_0);
102        assert_eq!(Q::from(15), u_1);
103        assert_eq!(Q::from(35), u_2);
104        assert_eq!(Q::from(u64::MAX), u_3);
105        assert_eq!(Q::ZERO, i_0);
106        assert_eq!(Q::from(15), i_1);
107        assert_eq!(Q::from(35), i_2);
108        assert_eq!(Q::from(i64::MIN).abs(), i_3);
109        assert_eq!(Q::from((425, 100)), f_0);
110        assert_eq!(Q::from((169, 256)), f_1);
111    }
112}