arr_rs/math/operations/floating.rs
1use crate::{
2 core::prelude::*,
3 errors::prelude::*,
4 extensions::prelude::*,
5 numeric::prelude::*,
6};
7
8/// `ArrayTrait` - Array Floating functions
9pub trait ArrayFloating<N: Floating> where Self: Sized + Clone {
10
11 /// Returns element-wise True where signbit is set (less than zero)
12 ///
13 /// # Examples
14 ///
15 /// ```
16 /// use arr_rs::prelude::*;
17 ///
18 /// let arr = Array::flat(vec![1., -2., -3., 4.]);
19 /// assert_eq!(Array::flat(vec![false, true, true, false]), arr.signbit());
20 /// ```
21 ///
22 /// # Errors
23 ///
24 /// may returns `ArrayError`
25 fn signbit(&self) -> Result<Array<bool>, ArrayError>;
26
27 /// Change the sign of x1 to that of x2, element-wise
28 ///
29 /// # Arguments
30 ///
31 /// * `other` - array to copy sign from
32 ///
33 /// # Examples
34 ///
35 /// ```
36 /// use arr_rs::prelude::*;
37 ///
38 /// let arr = Array::flat(vec![1., -2., -3., 4.]);
39 /// let other = Array::flat(vec![-1., 2., -3., 4.]);
40 /// assert_eq!(Array::flat(vec![-1., 2., -3., 4.]), arr.copysign(&other.unwrap()));
41 /// ```
42 ///
43 /// # Errors
44 ///
45 /// may returns `ArrayError`
46 fn copysign(&self, other: &Array<N>) -> Result<Array<N>, ArrayError>;
47
48 /// Decompose the elements of x into man and twos exp
49 ///
50 /// # Examples
51 ///
52 /// ```
53 /// use arr_rs::prelude::*;
54 ///
55 /// let arr = Array::arange(0., 8., None);
56 /// let result = arr.frexp().unwrap();
57 /// assert_eq!(Array::flat(vec![0., 0.5, 0.5, 0.75, 0.5, 0.625, 0.75, 0.875, 0.5]).unwrap(), result.0);
58 /// assert_eq!(Array::flat(vec![0, 1, 2, 2, 3, 3, 3, 3, 4]).unwrap(), result.1);
59 /// ```
60 ///
61 /// # Errors
62 ///
63 /// may returns `ArrayError`
64 fn frexp(&self) -> Result<(Array<N>, Array<i32>), ArrayError>;
65
66 /// Returns x1 * 2**x2, element-wise. Inverse of frexp
67 ///
68 /// # Examples
69 ///
70 /// ```
71 /// use arr_rs::prelude::*;
72 ///
73 /// let arr = Array::flat(vec![0., 0.5, 0.5, 0.75, 0.5, 0.625, 0.75, 0.875, 0.5]);
74 /// let other = Array::flat(vec![0, 1, 2, 2, 3, 3, 3, 3, 4]);
75 /// assert_eq!(Array::arange(0., 8., None), arr.ldexp(&other.unwrap()));
76 /// ```
77 ///
78 /// # Errors
79 ///
80 /// may returns `ArrayError`
81 fn ldexp(&self, other: &Array<i32>) -> Result<Array<N>, ArrayError>;
82
83 /// Return the next floating-point value after x1 towards x2, element-wise
84 ///
85 /// # Examples
86 ///
87 /// ```
88 /// use arr_rs::prelude::*;
89 ///
90 /// let expected = Array::flat(vec![1. + f64::EPSILON, 2. - f64::EPSILON]);
91 /// assert_eq!(expected, Array::flat(vec![1., 2.]).nextafter(&Array::flat(vec![2., 1.]).unwrap()));
92 /// ```
93 ///
94 /// # Errors
95 ///
96 /// may returns `ArrayError`
97 fn nextafter(&self, other: &Array<N>) -> Result<Array<N>, ArrayError>;
98
99 /// Return the distance between x and the nearest adjacent number
100 ///
101 /// # Examples
102 ///
103 /// ```
104 /// use arr_rs::prelude::*;
105 ///
106 /// assert_eq!(Array::flat(vec![f64::EPSILON, f64::EPSILON * 2.]), Array::flat(vec![1., 2.]).spacing());
107 /// ```
108 ///
109 /// # Errors
110 ///
111 /// may returns `ArrayError`
112 fn spacing(&self) -> Result<Array<N>, ArrayError>;
113}
114
115impl <N: Floating> ArrayFloating<N> for Array<N> {
116
117 fn signbit(&self) -> Result<Array<bool>, ArrayError> {
118 self.map(|e| e.to_f64().is_sign_negative())
119 }
120
121 fn copysign(&self, other: &Self) -> Result<Self, ArrayError> {
122 self.zip(other)?
123 .map(|item| N::from(item.0.to_f64().copysign(item.1.to_f64())))
124 }
125
126 fn frexp(&self) -> Result<(Self, Array<i32>), ArrayError> {
127
128 fn _frexp(x: f64) -> (f64, i32) {
129 let sign = x.signum();
130 let mut x = x.abs();
131 let mut sig: f64 = 0.0;
132 let mut exp: i32 = 0;
133 if x == 0.0 { return (sig, exp); }
134
135 while x >= 1.0 { x /= 2.0; exp += 1; }
136 while x < 0.5 { x *= 2.0; exp -= 1; }
137
138 sig = x;
139 (sig * sign, exp)
140 }
141
142 let mut man = vec![];
143 let mut exp = vec![];
144
145 self.for_each(|item| {
146 let result = _frexp(item.to_f64());
147 man.push(N::from(result.0));
148 exp.push(result.1);
149 })?;
150
151 Ok((
152 man.to_array().reshape(&self.get_shape()?)?,
153 exp.to_array().reshape(&self.get_shape()?)?,
154 ))
155 }
156
157 fn ldexp(&self, other: &Array<i32>) -> Result<Self, ArrayError> {
158
159 fn _ldexp(x: f64, exp: i32) -> f64 {
160 if x == 0. { return x }
161 let mut exp = exp;
162 let mut sig = x;
163
164 while exp > 0 { sig *= 2.; exp -= 1; }
165 while exp < 0 { sig /= 2.; exp += 1; }
166
167 sig
168 }
169
170 self.zip(other)?
171 .map(|item| N::from(_ldexp(item.0.to_f64(), item.1)))
172 }
173
174 fn nextafter(&self, other: &Self) -> Result<Self, ArrayError> {
175
176 fn _nextafter(x: f64, y: f64) -> f64 {
177 if (x - y).abs() < 1e-24 { x }
178 else if x < y { x + f64::EPSILON }
179 else { x - f64::EPSILON }
180 }
181
182 self.zip(other)?
183 .map(|item| N::from(_nextafter(item.0.to_f64(), item.1.to_f64())))
184 }
185
186 fn spacing(&self) -> Result<Self, ArrayError> {
187
188 fn _spacing(x: f64) -> f64 {
189 let bits = x.to_bits();
190 let next =
191 if x.is_sign_negative() { bits - 1 }
192 else { bits + 1 };
193 f64::from_bits(next) - x
194 }
195
196 self.map(|item| N::from(_spacing(item.to_f64())))
197 }
198}
199
200impl <N: Floating> ArrayFloating<N> for Result<Array<N>, ArrayError> {
201
202 fn signbit(&self) -> Result<Array<bool>, ArrayError> {
203 self.clone()?.signbit()
204 }
205
206 fn copysign(&self, other: &Array<N>) -> Self {
207 self.clone()?.copysign(other)
208 }
209
210 fn frexp(&self) -> Result<(Array<N>, Array<i32>), ArrayError> {
211 self.clone()?.frexp()
212 }
213
214 fn ldexp(&self, other: &Array<i32>) -> Self {
215 self.clone()?.ldexp(other)
216 }
217
218 fn nextafter(&self, other: &Array<N>) -> Self {
219 self.clone()?.nextafter(other)
220 }
221
222 fn spacing(&self) -> Self {
223 self.clone()?.spacing()
224 }
225}