Skip to content

Commit 06fca27

Browse files
committed
Updated ComplexFloat to be a bit more general and to have a few extra methods. Moved to a new module, and added a couple useful functions to Complex<T>.
1 parent 6fd3303 commit 06fca27

File tree

3 files changed

+340
-399
lines changed

3 files changed

+340
-399
lines changed

src/cast.rs

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -80,57 +80,6 @@ where
8080
}
8181
}
8282

83-
pub trait RealConsts<T: Copy> {
84-
#[cfg(has_assoc_const)]
85-
const LN_2: T;
86-
#[cfg(has_assoc_const)]
87-
const FRAC_LN_2: T;
88-
#[cfg(has_assoc_const)]
89-
const FRAC_LN_10: T;
90-
91-
fn ln_2() -> T;
92-
fn frac_ln_2() -> T;
93-
fn frac_ln_10() -> T;
94-
}
95-
96-
impl RealConsts<f32> for f32 {
97-
#[cfg(has_assoc_const)]
98-
const LN_2: f32 = 0.693147180559945309417232121458176568_f32;
99-
#[cfg(has_assoc_const)]
100-
const FRAC_LN_2: f32 = 1.442695040888963407359924681001892137_f32;
101-
#[cfg(has_assoc_const)]
102-
const FRAC_LN_10: f32 = 0.434294481903251827651128918916605082_f32;
103-
104-
fn ln_2() -> f32 {
105-
0.693147180559945309417232121458176568_f32
106-
}
107-
fn frac_ln_2() -> f32 {
108-
1.442695040888963407359924681001892137_f32
109-
}
110-
fn frac_ln_10() -> f32 {
111-
0.434294481903251827651128918916605082_f32
112-
}
113-
}
114-
115-
impl RealConsts<f64> for f64 {
116-
#[cfg(has_assoc_const)]
117-
const LN_2: f64 = 0.693147180559945309417232121458176568_f64;
118-
#[cfg(has_assoc_const)]
119-
const FRAC_LN_2: f64 = 1.442695040888963407359924681001892137_f64;
120-
#[cfg(has_assoc_const)]
121-
const FRAC_LN_10: f64 = 0.434294481903251827651128918916605082_f64;
122-
123-
fn ln_2() -> f64 {
124-
0.693147180559945309417232121458176568_f64
125-
}
126-
fn frac_ln_2() -> f64 {
127-
1.442695040888963407359924681001892137_f64
128-
}
129-
fn frac_ln_10() -> f64 {
130-
0.434294481903251827651128918916605082_f64
131-
}
132-
}
133-
13483
#[cfg(test)]
13584
mod test {
13685
use super::*;

src/complex_float.rs

Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
// Keeps us from accidentally creating a recursive impl rather than a real one.
2+
#![deny(unconditional_recursion)]
3+
4+
use num_traits::{float::FloatCore, Float, FloatConst};
5+
6+
use crate::Complex;
7+
8+
/// Generic trait for floating point complex numbers
9+
/// This trait defines methods which are common to complex floating point numbers and regular floating point numbers.
10+
#[cfg(any(feature = "std", feature = "libm"))]
11+
pub trait ComplexFloat {
12+
type Real;
13+
14+
/// Returns `true` if this value is `NaN` and false otherwise.
15+
fn is_nan(self) -> bool;
16+
17+
/// Returns `true` if this value is positive infinity or negative infinity and
18+
/// false otherwise.
19+
fn is_infinite(self) -> bool;
20+
21+
/// Returns `true` if this number is neither infinite nor `NaN`.
22+
fn is_finite(self) -> bool;
23+
24+
/// Returns `true` if the number is neither zero, infinite,
25+
/// [subnormal][subnormal], or `NaN`.
26+
/// [subnormal]: http://en.wikipedia.org/wiki/Denormal_number
27+
fn is_normal(self) -> bool;
28+
29+
/// Take the reciprocal (inverse) of a number, `1/x`.
30+
fn recip(self) -> Self;
31+
32+
/// Raises `self` to a signed integer power.
33+
fn powi(self, exp: i32) -> Self;
34+
35+
/// Raises `self` to a real power.
36+
fn powf(self, exp: Self::Real) -> Self;
37+
38+
/// Raises `self` to a complex power.
39+
fn powc(self, exp: Complex<Self::Real>) -> Complex<Self::Real>;
40+
41+
/// Take the square root of a number.
42+
fn sqrt(self) -> Self;
43+
44+
/// Returns `e^(self)`, (the exponential function).
45+
fn exp(self) -> Self;
46+
47+
/// Returns `2^(self)`.
48+
fn exp2(self) -> Self;
49+
50+
/// Returns the natural logarithm of the number.
51+
fn ln(self) -> Self;
52+
53+
/// Returns the logarithm of the number with respect to an arbitrary base.
54+
fn log(self, base: Self::Real) -> Self;
55+
56+
/// Returns the base 2 logarithm of the number.
57+
fn log2(self) -> Self;
58+
59+
/// Returns the base 10 logarithm of the number.
60+
fn log10(self) -> Self;
61+
62+
/// Take the cubic root of a number.
63+
fn cbrt(self) -> Self;
64+
65+
/// Computes the sine of a number (in radians).
66+
fn sin(self) -> Self;
67+
68+
/// Computes the cosine of a number (in radians).
69+
fn cos(self) -> Self;
70+
71+
/// Computes the tangent of a number (in radians).
72+
fn tan(self) -> Self;
73+
74+
/// Computes the arcsine of a number. Return value is in radians in
75+
/// the range [-pi/2, pi/2] or NaN if the number is outside the range
76+
/// [-1, 1].
77+
fn asin(self) -> Self;
78+
79+
/// Computes the arccosine of a number. Return value is in radians in
80+
/// the range [0, pi] or NaN if the number is outside the range
81+
/// [-1, 1].
82+
fn acos(self) -> Self;
83+
84+
/// Computes the arctangent of a number. Return value is in radians in the
85+
/// range [-pi/2, pi/2];
86+
fn atan(self) -> Self;
87+
88+
/// Hyperbolic sine function.
89+
fn sinh(self) -> Self;
90+
91+
/// Hyperbolic cosine function.
92+
fn cosh(self) -> Self;
93+
94+
/// Hyperbolic tangent function.
95+
fn tanh(self) -> Self;
96+
97+
/// Inverse hyperbolic sine function.
98+
fn asinh(self) -> Self;
99+
100+
/// Inverse hyperbolic cosine function.
101+
fn acosh(self) -> Self;
102+
103+
/// Inverse hyperbolic tangent function.
104+
fn atanh(self) -> Self;
105+
106+
/// Returns the real part of the number.
107+
fn re(self) -> Self::Real;
108+
109+
/// Returns the imaginary part of the number which equals to zero.
110+
fn im(self) -> Self::Real;
111+
112+
/// Returns the absolute value of the number.
113+
fn abs(self) -> Self::Real;
114+
115+
/// Computes the argument of the number.
116+
fn arg(self) -> Self::Real;
117+
118+
/// Comutes the complex conjugate of `self`.
119+
///
120+
/// Formula: `a+bi -> a-bi`
121+
fn conj(self) -> Self;
122+
}
123+
124+
macro_rules! forward {
125+
($( $base:ident :: $method:ident ( self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*)
126+
=> {$(
127+
#[inline]
128+
fn $method(self $( , $arg : $ty )* ) -> $ret {
129+
$base::$method(self $( , $arg )* )
130+
}
131+
)*};
132+
}
133+
134+
macro_rules! forward_ref {
135+
($( Self :: $method:ident ( & self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*)
136+
=> {$(
137+
#[inline]
138+
fn $method(self $( , $arg : $ty )* ) -> $ret {
139+
Self::$method(&self $( , $arg )* )
140+
}
141+
)*};
142+
}
143+
144+
#[cfg(any(feature = "std", feature = "libm"))]
145+
impl<T> ComplexFloat for T
146+
where
147+
T: Float + FloatConst,
148+
{
149+
type Real = T;
150+
151+
fn re(self) -> Self::Real {
152+
self
153+
}
154+
155+
fn im(self) -> Self::Real {
156+
T::zero()
157+
}
158+
159+
fn abs(self) -> Self::Real {
160+
self.abs()
161+
}
162+
163+
fn arg(self) -> Self::Real {
164+
if self > T::zero() {
165+
T::zero()
166+
} else if self < T::zero() {
167+
T::PI()
168+
} else {
169+
T::nan()
170+
}
171+
}
172+
173+
fn powc(self, exp: Complex<Self::Real>) -> Complex<Self::Real> {
174+
Complex::new(self, Self::Real::zero()).powc(exp)
175+
}
176+
177+
fn conj(self) -> Self {
178+
self
179+
}
180+
181+
forward! {
182+
Float::is_normal(self) -> bool;
183+
Float::is_infinite(self) -> bool;
184+
Float::is_finite(self) -> bool;
185+
Float::is_nan(self) -> bool;
186+
Float::recip(self) -> Self;
187+
Float::powi(self, n: i32) -> Self;
188+
Float::powf(self, f: Self) -> Self;
189+
Float::sqrt(self) -> Self;
190+
Float::cbrt(self) -> Self;
191+
Float::exp(self) -> Self;
192+
Float::exp2(self) -> Self;
193+
Float::ln(self) -> Self;
194+
Float::log(self, base: Self) -> Self;
195+
Float::log2(self) -> Self;
196+
Float::log10(self) -> Self;
197+
Float::sin(self) -> Self;
198+
Float::cos(self) -> Self;
199+
Float::tan(self) -> Self;
200+
Float::asin(self) -> Self;
201+
Float::acos(self) -> Self;
202+
Float::atan(self) -> Self;
203+
Float::sinh(self) -> Self;
204+
Float::cosh(self) -> Self;
205+
Float::tanh(self) -> Self;
206+
Float::asinh(self) -> Self;
207+
Float::acosh(self) -> Self;
208+
Float::atanh(self) -> Self;
209+
}
210+
}
211+
212+
#[cfg(any(feature = "std", feature = "libm"))]
213+
impl<T: Float + FloatCore + FloatConst> ComplexFloat for Complex<T> {
214+
type Real = T;
215+
216+
fn re(self) -> Self::Real {
217+
self.re
218+
}
219+
220+
fn im(self) -> Self::Real {
221+
self.im
222+
}
223+
224+
fn abs(self) -> Self::Real {
225+
self.norm()
226+
}
227+
228+
fn arg(self) -> Self::Real {
229+
Complex::arg(self)
230+
}
231+
232+
fn recip(self) -> Self {
233+
self.finv()
234+
}
235+
236+
fn powc(self, exp: Complex<Self::Real>) -> Complex<Self::Real> {
237+
self.powc(exp)
238+
}
239+
240+
forward! {
241+
Complex::exp2(self) -> Self;
242+
Complex::log(self, base: Self::Real) -> Self;
243+
Complex::log2(self) -> Self;
244+
Complex::log10(self) -> Self;
245+
Complex::is_normal(self) -> bool;
246+
Complex::is_infinite(self) -> bool;
247+
Complex::is_finite(self) -> bool;
248+
Complex::is_nan(self) -> bool;
249+
Complex::powf(self, f: Self::Real) -> Self;
250+
Complex::sqrt(self) -> Self;
251+
Complex::cbrt(self) -> Self;
252+
Complex::exp(self) -> Self;
253+
Complex::ln(self) -> Self;
254+
Complex::sin(self) -> Self;
255+
Complex::cos(self) -> Self;
256+
Complex::tan(self) -> Self;
257+
Complex::asin(self) -> Self;
258+
Complex::acos(self) -> Self;
259+
Complex::atan(self) -> Self;
260+
Complex::sinh(self) -> Self;
261+
Complex::cosh(self) -> Self;
262+
Complex::tanh(self) -> Self;
263+
Complex::asinh(self) -> Self;
264+
Complex::acosh(self) -> Self;
265+
Complex::atanh(self) -> Self;
266+
}
267+
268+
forward_ref! {
269+
Self::powi(&self, n: i32) -> Self;
270+
Self::conj(&self) -> Self;
271+
}
272+
}
273+
274+
#[cfg(test)]
275+
mod test {
276+
use crate::{complex_float::ComplexFloat, test::float::close, Complex, Complex64};
277+
278+
pub const _0_0i: Complex64 = Complex { re: 0.0, im: 0.0 };
279+
pub const _1_0i: Complex64 = Complex { re: 1.0, im: 0.0 };
280+
pub const _1_1i: Complex64 = Complex { re: 1.0, im: 1.0 };
281+
pub const _0_1i: Complex64 = Complex { re: 0.0, im: 1.0 };
282+
pub const _neg1_1i: Complex64 = Complex { re: -1.0, im: 1.0 };
283+
pub const _05_05i: Complex64 = Complex { re: 0.5, im: 0.5 };
284+
pub const all_consts: [Complex64; 5] = [_0_0i, _1_0i, _1_1i, _neg1_1i, _05_05i];
285+
pub const _4_2i: Complex64 = Complex { re: 4.0, im: 2.0 };
286+
287+
#[test]
288+
fn test_exp2() {
289+
assert!(close(ComplexFloat::exp2(_0_0i), _1_0i));
290+
}
291+
292+
#[test]
293+
fn test_powi() {
294+
assert!(close(ComplexFloat::powi(_0_1i, 4), _1_0i));
295+
}
296+
297+
#[test]
298+
fn test_powz() {
299+
assert!(close(_1_0i.powc(_0_1i), _1_0i));
300+
}
301+
302+
#[test]
303+
fn test_log2() {
304+
assert!(close(_1_0i.log2(), _0_0i));
305+
}
306+
307+
#[test]
308+
fn test_log10() {
309+
assert!(close(_1_0i.log10(), _0_0i));
310+
}
311+
}

0 commit comments

Comments
 (0)