1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use crate::{
    core::prelude::*,
    errors::prelude::*,
    numeric::prelude::*,
};
use crate::prelude::ArrayMathMisc;

/// ArrayTrait - Array Rational functions
pub trait ArrayRational<N: Numeric> where Self: Sized + Clone {

    /// Returns the lowest common multiple of |x1| and |x2|
    ///
    /// # Arguments
    ///
    /// * `other` - array to perform the operation with
    ///
    /// # Examples
    ///
    /// ```
    /// use arr_rs::prelude::*;
    ///
    /// assert_eq!(Array::single(60), Array::single(12).lcm(&Array::single(20).unwrap()));
    /// ```
    fn lcm(&self, other: &Array<N>) -> Result<Array<N>, ArrayError>;

    /// Returns the greatest common divisor of |x1| and |x2|
    ///
    /// # Arguments
    ///
    /// * `other` - array to perform the operation with
    ///
    /// # Examples
    ///
    /// ```
    /// use arr_rs::prelude::*;
    ///
    /// assert_eq!(Array::single(4), Array::single(12).gcd(&Array::single(20).unwrap()));
    /// ```
    fn gcd(&self, other: &Array<N>) -> Result<Array<N>, ArrayError>;
}

fn _gcd(x: i32, y: i32) -> i32 {
    if y == 0 { x }
    else { _gcd(y, x % y) }
}

impl <N: Numeric> ArrayRational<N> for Array<N> {

    fn lcm(&self, other: &Array<N>) -> Result<Array<N>, ArrayError> {
        self.abs()?.zip(&other.abs()?)?
            .map(|item| {
                let (x, y) = (item.0.to_i32(), item.1.to_i32());
                N::from(x * y / _gcd(x, y))
            })
    }

    fn gcd(&self, other: &Array<N>) -> Result<Array<N>, ArrayError> {
        self.abs()?.zip(&other.abs()?)?
            .map(|item| N::from(_gcd(item.0.to_i32(), item.1.to_i32())))
    }
}

impl <N: Numeric> ArrayRational<N> for Result<Array<N>, ArrayError> {

    fn lcm(&self, other: &Array<N>) -> Result<Array<N>, ArrayError> {
        self.clone()?.lcm(other)
    }

    fn gcd(&self, other: &Array<N>) -> Result<Array<N>, ArrayError> {
        self.clone()?.gcd(other)
    }
}