arr_rs/math/operations/
rounding.rs

1use crate::{
2    core::prelude::*,
3    errors::prelude::*,
4    numeric::prelude::*,
5};
6
7/// `ArrayTrait` - Array Rounding functions
8pub trait ArrayRounding<N: Numeric> where Self: Sized + Clone {
9
10    /// Evenly round to the given number of decimals
11    ///
12    /// # Arguments
13    ///
14    /// * `decimals` - Number of decimal places to round to (default: 0). If decimals is negative, it specifies the number of positions to the left of the decimal point
15    ///
16    /// # Examples
17    ///
18    /// ```
19    /// use arr_rs::prelude::*;
20    ///
21    /// let arr = Array::flat(vec![2.01, 4.6, 8.0010, 22.234]);
22    /// assert_eq!(Array::flat(vec![2., 4.6, 8.001, 20.]), arr.round(&Array::flat(vec![0, 1, 3, -1]).unwrap()));
23    /// ```
24    ///
25    /// # Errors
26    ///
27    /// may returns `ArrayError`
28    fn round(&self, decimals: &Array<isize>) -> Result<Array<N>, ArrayError>;
29
30    /// Evenly round to the given number of decimals. alias on `round`
31    ///
32    /// # Arguments
33    ///
34    /// * `decimals` - Number of decimal places to round to (default: 0). If decimals is negative, it specifies the number of positions to the left of the decimal point
35    ///
36    /// # Examples
37    ///
38    /// ```
39    /// use arr_rs::prelude::*;
40    ///
41    /// let arr = Array::flat(vec![2.01, 4.6, 8.0010, 22.234]);
42    /// assert_eq!(Array::flat(vec![2., 4.6, 8.001, 20.]), arr.around(&Array::flat(vec![0, 1, 3, -1]).unwrap()));
43    /// ```
44    ///
45    /// # Errors
46    ///
47    /// may returns `ArrayError`
48    fn around(&self, decimals: &Array<isize>) -> Result<Array<N>, ArrayError>;
49
50    /// Round elements of the array to the nearest integer
51    ///
52    /// # Examples
53    ///
54    /// ```
55    /// use arr_rs::prelude::*;
56    ///
57    /// let arr = Array::flat(vec![2.01, 4.6, 8.0010, 22.234]);
58    /// assert_eq!(Array::flat(vec![2., 5., 8., 22.]), arr.rint());
59    /// ```
60    ///
61    /// # Errors
62    ///
63    /// may returns `ArrayError`
64    fn rint(&self) -> Result<Array<N>, ArrayError>;
65
66    /// Round to nearest integer towards zero
67    ///
68    /// # Examples
69    ///
70    /// ```
71    /// use arr_rs::prelude::*;
72    ///
73    /// let arr = Array::flat(vec![2.01, 4.6, -1.6, -2.2]);
74    /// assert_eq!(Array::flat(vec![2., 4., -1., -2.]), arr.fix());
75    /// ```
76    ///
77    /// # Errors
78    ///
79    /// may returns `ArrayError`
80    fn fix(&self) -> Result<Array<N>, ArrayError>;
81
82    /// Round to nearest integer towards zero
83    ///
84    /// # Examples
85    ///
86    /// ```
87    /// use arr_rs::prelude::*;
88    ///
89    /// let arr = Array::flat(vec![2.01, 4.6, -1.6, -2.2]);
90    /// assert_eq!(Array::flat(vec![2., 4., -1., -2.]), arr.fix());
91    /// ```
92    ///
93    /// # Errors
94    ///
95    /// may returns `ArrayError`
96    fn trunc(&self) -> Result<Array<N>, ArrayError>;
97
98    /// Return the floor of the input, element-wise
99    ///
100    /// # Examples
101    ///
102    /// ```
103    /// use arr_rs::prelude::*;
104    ///
105    /// let arr = Array::flat(vec![2.01, 4.6, -1.6, -2.2]);
106    /// assert_eq!(Array::flat(vec![2., 4., -2., -3.]), arr.floor());
107    /// ```
108    ///
109    /// # Errors
110    ///
111    /// may returns `ArrayError`
112    fn floor(&self) -> Result<Array<N>, ArrayError>;
113
114    /// Return the ceil of the input, element-wise
115    ///
116    /// # Examples
117    ///
118    /// ```
119    /// use arr_rs::prelude::*;
120    ///
121    /// let arr = Array::flat(vec![2.01, 4.6, -1.6, -2.2]);
122    /// assert_eq!(Array::flat(vec![3., 5., -1., -2.]), arr.ceil());
123    /// ```
124    ///
125    /// # Errors
126    ///
127    /// may returns `ArrayError`
128    fn ceil(&self) -> Result<Array<N>, ArrayError>;
129}
130
131impl <N: Numeric> ArrayRounding<N> for Array<N> {
132
133    fn round(&self, decimals: &Array<isize>) -> Result<Self, ArrayError> {
134        let (array, other) = self.broadcast_h2(decimals)?;
135        let elements = array.clone().into_iter().zip(&other)
136            .map(|tuple| {
137                let multiplier = 10_f64.powi(tuple.1.to_i32());
138                N::from((tuple.0.to_f64() * multiplier).round() / multiplier)
139            })
140            .collect();
141        Self::new(elements, array.get_shape()?)
142    }
143
144    fn around(&self, decimals: &Array<isize>) -> Result<Self, ArrayError> {
145        self.round(decimals)
146    }
147
148    fn rint(&self) -> Result<Self, ArrayError> {
149        self.round(&Array::single(0).unwrap())
150    }
151
152    fn fix(&self) -> Result<Self, ArrayError> {
153        self.map(|i|
154            if *i >= N::zero() { N::from(i.to_f64().floor()) }
155            else { N::from(i.to_f64().ceil()) }
156        )
157    }
158
159    fn trunc(&self) -> Result<Self, ArrayError> {
160        self.map(|i| N::from(i.to_f64().trunc()))
161    }
162
163    fn floor(&self) -> Result<Self, ArrayError> {
164        self.map(|i| N::from(i.to_f64().floor()))
165    }
166
167    fn ceil(&self) -> Result<Self, ArrayError> {
168        self.map(|i| N::from(i.to_f64().ceil()))
169    }
170}
171
172impl <N: Numeric> ArrayRounding<N> for Result<Array<N>, ArrayError> {
173
174    fn round(&self, decimals: &Array<isize>) -> Self {
175        self.clone()?.round(decimals)
176    }
177
178    fn around(&self, decimals: &Array<isize>) -> Self {
179        self.clone()?.around(decimals)
180    }
181
182    fn rint(&self) -> Self {
183        self.clone()?.rint()
184    }
185
186    fn fix(&self) -> Self {
187        self.clone()?.fix()
188    }
189
190    fn trunc(&self) -> Self {
191        self.clone()?.trunc()
192    }
193
194    fn floor(&self) -> Self {
195        self.clone()?.floor()
196    }
197
198    fn ceil(&self) -> Self {
199        self.clone()?.ceil()
200    }
201}