num_complex/
complex_float.rs1#![deny(unconditional_recursion)]
3
4use core::ops::Neg;
5
6use num_traits::{Float, FloatConst, Num, NumCast};
7
8use crate::Complex;
9
10mod private {
11 use num_traits::{Float, FloatConst};
12
13 use crate::Complex;
14
15 pub trait Seal {}
16
17 impl<T> Seal for T where T: Float + FloatConst {}
18 impl<T: Float + FloatConst> Seal for Complex<T> {}
19}
20
21pub trait ComplexFloat: Num + NumCast + Copy + Neg<Output = Self> + private::Seal {
29 type Real: Float + FloatConst;
31
32 fn is_nan(self) -> bool;
34
35 fn is_infinite(self) -> bool;
38
39 fn is_finite(self) -> bool;
41
42 fn is_normal(self) -> bool;
45
46 fn recip(self) -> Self;
48
49 fn powi(self, exp: i32) -> Self;
51
52 fn powf(self, exp: Self::Real) -> Self;
54
55 fn powc(self, exp: Complex<Self::Real>) -> Complex<Self::Real>;
57
58 fn sqrt(self) -> Self;
60
61 fn exp(self) -> Self;
63
64 fn exp2(self) -> Self;
66
67 fn expf(self, base: Self::Real) -> Self;
69
70 fn ln(self) -> Self;
72
73 fn log(self, base: Self::Real) -> Self;
75
76 fn log2(self) -> Self;
78
79 fn log10(self) -> Self;
81
82 fn cbrt(self) -> Self;
84
85 fn sin(self) -> Self;
87
88 fn cos(self) -> Self;
90
91 fn tan(self) -> Self;
93
94 fn asin(self) -> Self;
98
99 fn acos(self) -> Self;
103
104 fn atan(self) -> Self;
107
108 fn sinh(self) -> Self;
110
111 fn cosh(self) -> Self;
113
114 fn tanh(self) -> Self;
116
117 fn asinh(self) -> Self;
119
120 fn acosh(self) -> Self;
122
123 fn atanh(self) -> Self;
125
126 fn re(self) -> Self::Real;
128
129 fn im(self) -> Self::Real;
131
132 fn abs(self) -> Self::Real;
134
135 fn l1_norm(&self) -> Self::Real;
139
140 fn arg(self) -> Self::Real;
142
143 fn conj(self) -> Self;
147}
148
149macro_rules! forward {
150 ($( $base:ident :: $method:ident ( self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*)
151 => {$(
152 #[inline]
153 fn $method(self $( , $arg : $ty )* ) -> $ret {
154 $base::$method(self $( , $arg )* )
155 }
156 )*};
157}
158
159macro_rules! forward_ref {
160 ($( Self :: $method:ident ( & self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*)
161 => {$(
162 #[inline]
163 fn $method(self $( , $arg : $ty )* ) -> $ret {
164 Self::$method(&self $( , $arg )* )
165 }
166 )*};
167}
168
169impl<T> ComplexFloat for T
170where
171 T: Float + FloatConst,
172{
173 type Real = T;
174
175 fn re(self) -> Self::Real {
176 self
177 }
178
179 fn im(self) -> Self::Real {
180 T::zero()
181 }
182
183 fn l1_norm(&self) -> Self::Real {
184 self.abs()
185 }
186
187 fn arg(self) -> Self::Real {
188 if self.is_nan() {
189 self
190 } else if self.is_sign_negative() {
191 T::PI()
192 } else {
193 T::zero()
194 }
195 }
196
197 fn powc(self, exp: Complex<Self::Real>) -> Complex<Self::Real> {
198 Complex::new(self, T::zero()).powc(exp)
199 }
200
201 fn conj(self) -> Self {
202 self
203 }
204
205 fn expf(self, base: Self::Real) -> Self {
206 base.powf(self)
207 }
208
209 forward! {
210 Float::is_normal(self) -> bool;
211 Float::is_infinite(self) -> bool;
212 Float::is_finite(self) -> bool;
213 Float::is_nan(self) -> bool;
214 Float::recip(self) -> Self;
215 Float::powi(self, n: i32) -> Self;
216 Float::powf(self, f: Self) -> Self;
217 Float::sqrt(self) -> Self;
218 Float::cbrt(self) -> Self;
219 Float::exp(self) -> Self;
220 Float::exp2(self) -> Self;
221 Float::ln(self) -> Self;
222 Float::log(self, base: Self) -> Self;
223 Float::log2(self) -> Self;
224 Float::log10(self) -> Self;
225 Float::sin(self) -> Self;
226 Float::cos(self) -> Self;
227 Float::tan(self) -> Self;
228 Float::asin(self) -> Self;
229 Float::acos(self) -> Self;
230 Float::atan(self) -> Self;
231 Float::sinh(self) -> Self;
232 Float::cosh(self) -> Self;
233 Float::tanh(self) -> Self;
234 Float::asinh(self) -> Self;
235 Float::acosh(self) -> Self;
236 Float::atanh(self) -> Self;
237 Float::abs(self) -> Self;
238 }
239}
240
241impl<T: Float + FloatConst> ComplexFloat for Complex<T> {
242 type Real = T;
243
244 fn re(self) -> Self::Real {
245 self.re
246 }
247
248 fn im(self) -> Self::Real {
249 self.im
250 }
251
252 fn abs(self) -> Self::Real {
253 self.norm()
254 }
255
256 fn recip(self) -> Self {
257 self.finv()
258 }
259
260 fn l1_norm(&self) -> Self::Real {
263 self.re.abs() + self.im.abs()
264 }
265
266 fn is_nan(self) -> bool {
269 self.re.is_nan() || self.im.is_nan()
270 }
271
272 fn is_infinite(self) -> bool {
273 !self.is_nan() && (self.re.is_infinite() || self.im.is_infinite())
274 }
275
276 fn is_finite(self) -> bool {
277 self.re.is_finite() && self.im.is_finite()
278 }
279
280 fn is_normal(self) -> bool {
281 self.re.is_normal() && self.im.is_normal()
282 }
283
284 forward! {
285 Complex::arg(self) -> Self::Real;
286 Complex::powc(self, exp: Complex<Self::Real>) -> Complex<Self::Real>;
287 Complex::exp2(self) -> Self;
288 Complex::log(self, base: Self::Real) -> Self;
289 Complex::log2(self) -> Self;
290 Complex::log10(self) -> Self;
291 Complex::powf(self, f: Self::Real) -> Self;
292 Complex::sqrt(self) -> Self;
293 Complex::cbrt(self) -> Self;
294 Complex::exp(self) -> Self;
295 Complex::expf(self, base: Self::Real) -> Self;
296 Complex::ln(self) -> Self;
297 Complex::sin(self) -> Self;
298 Complex::cos(self) -> Self;
299 Complex::tan(self) -> Self;
300 Complex::asin(self) -> Self;
301 Complex::acos(self) -> Self;
302 Complex::atan(self) -> Self;
303 Complex::sinh(self) -> Self;
304 Complex::cosh(self) -> Self;
305 Complex::tanh(self) -> Self;
306 Complex::asinh(self) -> Self;
307 Complex::acosh(self) -> Self;
308 Complex::atanh(self) -> Self;
309 }
310
311 forward_ref! {
312 Self::powi(&self, n: i32) -> Self;
313 Self::conj(&self) -> Self;
314 }
315}
316
317#[cfg(test)]
318mod test {
319 use crate::{
320 complex_float::ComplexFloat,
321 test::{_0_0i, _0_1i, _1_0i, _1_1i, float::close},
322 Complex,
323 };
324 use std::f64; fn closef(a: f64, b: f64) -> bool {
327 close_to_tolf(a, b, 1e-10)
328 }
329
330 fn close_to_tolf(a: f64, b: f64, tol: f64) -> bool {
331 let close = (a == b) || (a - b).abs() < tol;
333 if !close {
334 println!("{:?} != {:?}", a, b);
335 }
336 close
337 }
338
339 #[test]
340 fn test_exp2() {
341 assert!(close(ComplexFloat::exp2(_0_0i), _1_0i));
342 assert!(closef(<f64 as ComplexFloat>::exp2(0.), 1.));
343 }
344
345 #[test]
346 fn test_exp() {
347 assert!(close(ComplexFloat::exp(_0_0i), _1_0i));
348 assert!(closef(ComplexFloat::exp(0.), 1.));
349 }
350
351 #[test]
352 fn test_powi() {
353 assert!(close(ComplexFloat::powi(_0_1i, 4), _1_0i));
354 assert!(closef(ComplexFloat::powi(-1., 4), 1.));
355 }
356
357 #[test]
358 fn test_powz() {
359 assert!(close(ComplexFloat::powc(_1_0i, _0_1i), _1_0i));
360 assert!(close(ComplexFloat::powc(1., _0_1i), _1_0i));
361 }
362
363 #[test]
364 fn test_log2() {
365 assert!(close(ComplexFloat::log2(_1_0i), _0_0i));
366 assert!(closef(ComplexFloat::log2(1.), 0.));
367 }
368
369 #[test]
370 fn test_log10() {
371 assert!(close(ComplexFloat::log10(_1_0i), _0_0i));
372 assert!(closef(ComplexFloat::log10(1.), 0.));
373 }
374
375 #[test]
376 fn test_conj() {
377 assert_eq!(ComplexFloat::conj(_0_1i), Complex::new(0., -1.));
378 assert_eq!(ComplexFloat::conj(1.), 1.);
379 }
380
381 #[test]
382 fn test_is_nan() {
383 assert!(!ComplexFloat::is_nan(_1_0i));
384 assert!(!ComplexFloat::is_nan(1.));
385
386 assert!(ComplexFloat::is_nan(Complex::new(f64::NAN, f64::NAN)));
387 assert!(ComplexFloat::is_nan(f64::NAN));
388 }
389
390 #[test]
391 fn test_is_infinite() {
392 assert!(!ComplexFloat::is_infinite(_1_0i));
393 assert!(!ComplexFloat::is_infinite(1.));
394
395 assert!(ComplexFloat::is_infinite(Complex::new(
396 f64::INFINITY,
397 f64::INFINITY
398 )));
399 assert!(ComplexFloat::is_infinite(f64::INFINITY));
400 }
401
402 #[test]
403 fn test_is_finite() {
404 assert!(ComplexFloat::is_finite(_1_0i));
405 assert!(ComplexFloat::is_finite(1.));
406
407 assert!(!ComplexFloat::is_finite(Complex::new(
408 f64::INFINITY,
409 f64::INFINITY
410 )));
411 assert!(!ComplexFloat::is_finite(f64::INFINITY));
412 }
413
414 #[test]
415 fn test_is_normal() {
416 assert!(ComplexFloat::is_normal(_1_1i));
417 assert!(ComplexFloat::is_normal(1.));
418
419 assert!(!ComplexFloat::is_normal(Complex::new(
420 f64::INFINITY,
421 f64::INFINITY
422 )));
423 assert!(!ComplexFloat::is_normal(f64::INFINITY));
424 }
425
426 #[test]
427 fn test_arg() {
428 assert!(closef(
429 ComplexFloat::arg(_0_1i),
430 core::f64::consts::FRAC_PI_2
431 ));
432
433 assert!(closef(ComplexFloat::arg(-1.), core::f64::consts::PI));
434 assert!(closef(ComplexFloat::arg(-0.), core::f64::consts::PI));
435 assert!(closef(ComplexFloat::arg(0.), 0.));
436 assert!(closef(ComplexFloat::arg(1.), 0.));
437 assert!(ComplexFloat::arg(f64::NAN).is_nan());
438 }
439}