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}