Skip to content

Commit b963afd

Browse files
committed
---
yaml --- r: 71806 b: refs/heads/dist-snap c: bdd2439 h: refs/heads/master v: v3
1 parent 015b62b commit b963afd

File tree

5 files changed

+832
-1
lines changed

5 files changed

+832
-1
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
88
refs/heads/try2: 147ecfdd8221e4a4d4e090486829a06da1e0ca3c
99
refs/heads/incoming: b50030718cf28f2a5a81857a26b57442734fe854
10-
refs/heads/dist-snap: f678d63507a779d81810c342dd1bdc828fb983ba
10+
refs/heads/dist-snap: bdd2439529c23b4fcd2676d7427c45ca223385ce
1111
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1212
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503
1313
refs/heads/try3: 9387340aab40a73e8424c48fd42f0c521a4875c0
Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
12+
//! Complex numbers.
13+
14+
use core::num::{Zero,One,ToStrRadix};
15+
use core::prelude::*;
16+
17+
// FIXME #1284: handle complex NaN & infinity etc. This
18+
// probably doesn't map to C's _Complex correctly.
19+
20+
// FIXME #5734:: Need generic sin/cos for .to/from_polar().
21+
// FIXME #5735: Need generic sqrt to implement .norm().
22+
23+
24+
/// A complex number in Cartesian form.
25+
#[deriving(Eq,Clone)]
26+
pub struct Cmplx<T> {
27+
re: T,
28+
im: T
29+
}
30+
31+
pub type Complex = Cmplx<float>;
32+
pub type Complex32 = Cmplx<f32>;
33+
pub type Complex64 = Cmplx<f64>;
34+
35+
impl<T: Copy + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T>>
36+
Cmplx<T> {
37+
/// Create a new Cmplx
38+
#[inline]
39+
pub fn new(re: T, im: T) -> Cmplx<T> {
40+
Cmplx { re: re, im: im }
41+
}
42+
43+
/**
44+
Returns the square of the norm (since `T` doesn't necessarily
45+
have a sqrt function), i.e. `re^2 + im^2`.
46+
*/
47+
#[inline]
48+
pub fn norm_sqr(&self) -> T {
49+
self.re * self.re + self.im * self.im
50+
}
51+
52+
53+
/// Returns the complex conjugate. i.e. `re - i im`
54+
#[inline]
55+
pub fn conj(&self) -> Cmplx<T> {
56+
Cmplx::new(self.re, -self.im)
57+
}
58+
59+
60+
/// Multiplies `self` by the scalar `t`.
61+
#[inline]
62+
pub fn scale(&self, t: T) -> Cmplx<T> {
63+
Cmplx::new(self.re * t, self.im * t)
64+
}
65+
66+
/// Divides `self` by the scalar `t`.
67+
#[inline]
68+
pub fn unscale(&self, t: T) -> Cmplx<T> {
69+
Cmplx::new(self.re / t, self.im / t)
70+
}
71+
72+
/// Returns `1/self`
73+
#[inline]
74+
pub fn inv(&self) -> Cmplx<T> {
75+
let norm_sqr = self.norm_sqr();
76+
Cmplx::new(self.re / norm_sqr,
77+
-self.im / norm_sqr)
78+
}
79+
}
80+
81+
/* arithmetic */
82+
// (a + i b) + (c + i d) == (a + c) + i (b + d)
83+
impl<T: Copy + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T>>
84+
Add<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
85+
#[inline]
86+
fn add(&self, other: &Cmplx<T>) -> Cmplx<T> {
87+
Cmplx::new(self.re + other.re, self.im + other.im)
88+
}
89+
}
90+
// (a + i b) - (c + i d) == (a - c) + i (b - d)
91+
impl<T: Copy + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T>>
92+
Sub<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
93+
#[inline]
94+
fn sub(&self, other: &Cmplx<T>) -> Cmplx<T> {
95+
Cmplx::new(self.re - other.re, self.im - other.im)
96+
}
97+
}
98+
// (a + i b) * (c + i d) == (a*c - b*d) + i (a*d + b*c)
99+
impl<T: Copy + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T>>
100+
Mul<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
101+
#[inline]
102+
fn mul(&self, other: &Cmplx<T>) -> Cmplx<T> {
103+
Cmplx::new(self.re*other.re - self.im*other.im,
104+
self.re*other.im + self.im*other.re)
105+
}
106+
}
107+
108+
// (a + i b) / (c + i d) == [(a + i b) * (c - i d)] / (c*c + d*d)
109+
// == [(a*c + b*d) / (c*c + d*d)] + i [(b*c - a*d) / (c*c + d*d)]
110+
impl<T: Copy + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T>>
111+
Div<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
112+
#[inline]
113+
fn div(&self, other: &Cmplx<T>) -> Cmplx<T> {
114+
let norm_sqr = other.norm_sqr();
115+
Cmplx::new((self.re*other.re + self.im*other.im) / norm_sqr,
116+
(self.im*other.re - self.re*other.im) / norm_sqr)
117+
}
118+
}
119+
120+
impl<T: Copy + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T>>
121+
Neg<Cmplx<T>> for Cmplx<T> {
122+
#[inline]
123+
fn neg(&self) -> Cmplx<T> {
124+
Cmplx::new(-self.re, -self.im)
125+
}
126+
}
127+
128+
/* constants */
129+
impl<T: Copy + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T> + Zero>
130+
Zero for Cmplx<T> {
131+
#[inline]
132+
fn zero() -> Cmplx<T> {
133+
Cmplx::new(Zero::zero(), Zero::zero())
134+
}
135+
}
136+
137+
impl<T: Copy + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T> + Zero + One>
138+
One for Cmplx<T> {
139+
#[inline]
140+
fn one() -> Cmplx<T> {
141+
Cmplx::new(One::one(), Zero::zero())
142+
}
143+
}
144+
145+
/* string conversions */
146+
impl<T: ToStr + Zero + Ord + Neg<T>> ToStr for Cmplx<T> {
147+
fn to_str(&self) -> ~str {
148+
if self.im < Zero::zero() {
149+
fmt!("%s-%si", self.re.to_str(), (-self.im).to_str())
150+
} else {
151+
fmt!("%s+%si", self.re.to_str(), self.im.to_str())
152+
}
153+
}
154+
}
155+
156+
impl<T: ToStrRadix + Zero + Ord + Neg<T>> ToStrRadix for Cmplx<T> {
157+
fn to_str_radix(&self, radix: uint) -> ~str {
158+
if self.im < Zero::zero() {
159+
fmt!("%s-%si", self.re.to_str_radix(radix), (-self.im).to_str_radix(radix))
160+
} else {
161+
fmt!("%s+%si", self.re.to_str_radix(radix), self.im.to_str_radix(radix))
162+
}
163+
}
164+
}
165+
166+
#[cfg(test)]
167+
mod test {
168+
use core::prelude::*;
169+
use super::*;
170+
use core::num::{Zero,One};
171+
172+
pub static _0_0i : Complex = Cmplx { re: 0f, im: 0f };
173+
pub static _1_0i : Complex = Cmplx { re: 1f, im: 0f };
174+
pub static _1_1i : Complex = Cmplx { re: 1f, im: 1f };
175+
pub static _0_1i : Complex = Cmplx { re: 0f, im: 1f };
176+
pub static _neg1_1i : Complex = Cmplx { re: -1f, im: 1f };
177+
pub static _05_05i : Complex = Cmplx { re: 0.5f, im: 0.5f };
178+
pub static all_consts : [Complex, .. 5] = [_0_0i, _1_0i, _1_1i, _neg1_1i, _05_05i];
179+
180+
#[test]
181+
fn test_consts() {
182+
// check our constants are what Cmplx::new creates
183+
fn test(c : Complex, r : float, i: float) {
184+
assert_eq!(c, Cmplx::new(r,i));
185+
}
186+
test(_0_0i, 0f, 0f);
187+
test(_1_0i, 1f, 0f);
188+
test(_1_1i, 1f, 1f);
189+
test(_neg1_1i, -1f, 1f);
190+
test(_05_05i, 0.5f, 0.5f);
191+
192+
assert_eq!(_0_0i, Zero::zero());
193+
assert_eq!(_1_0i, One::one());
194+
}
195+
196+
#[test]
197+
fn test_norm_sqr() {
198+
fn test(c: Complex, ns: float) {
199+
assert_eq!(c.norm_sqr(), ns);
200+
}
201+
test(_0_0i, 0f);
202+
test(_1_0i, 1f);
203+
test(_1_1i, 2f);
204+
test(_neg1_1i, 2f);
205+
test(_05_05i, 0.5f);
206+
}
207+
208+
#[test]
209+
fn test_scale_unscale() {
210+
assert_eq!(_05_05i.scale(2f), _1_1i);
211+
assert_eq!(_1_1i.unscale(2f), _05_05i);
212+
for all_consts.each |&c| {
213+
assert_eq!(c.scale(2f).unscale(2f), c);
214+
}
215+
}
216+
217+
#[test]
218+
fn test_conj() {
219+
for all_consts.each |&c| {
220+
assert_eq!(c.conj(), Cmplx::new(c.re, -c.im));
221+
assert_eq!(c.conj().conj(), c);
222+
}
223+
}
224+
225+
#[test]
226+
fn test_inv() {
227+
assert_eq!(_1_1i.inv(), _05_05i.conj());
228+
assert_eq!(_1_0i.inv(), _1_0i.inv());
229+
}
230+
231+
#[test]
232+
#[should_fail]
233+
#[ignore]
234+
fn test_inv_zero() {
235+
// FIXME #5736: should this really fail, or just NaN?
236+
_0_0i.inv();
237+
}
238+
239+
240+
mod arith {
241+
use super::*;
242+
use super::super::*;
243+
use core::num::Zero;
244+
245+
#[test]
246+
fn test_add() {
247+
assert_eq!(_05_05i + _05_05i, _1_1i);
248+
assert_eq!(_0_1i + _1_0i, _1_1i);
249+
assert_eq!(_1_0i + _neg1_1i, _0_1i);
250+
251+
for all_consts.each |&c| {
252+
assert_eq!(_0_0i + c, c);
253+
assert_eq!(c + _0_0i, c);
254+
}
255+
}
256+
257+
#[test]
258+
fn test_sub() {
259+
assert_eq!(_05_05i - _05_05i, _0_0i);
260+
assert_eq!(_0_1i - _1_0i, _neg1_1i);
261+
assert_eq!(_0_1i - _neg1_1i, _1_0i);
262+
263+
for all_consts.each |&c| {
264+
assert_eq!(c - _0_0i, c);
265+
assert_eq!(c - c, _0_0i);
266+
}
267+
}
268+
269+
#[test]
270+
fn test_mul() {
271+
assert_eq!(_05_05i * _05_05i, _0_1i.unscale(2f));
272+
assert_eq!(_1_1i * _0_1i, _neg1_1i);
273+
274+
// i^2 & i^4
275+
assert_eq!(_0_1i * _0_1i, -_1_0i);
276+
assert_eq!(_0_1i * _0_1i * _0_1i * _0_1i, _1_0i);
277+
278+
for all_consts.each |&c| {
279+
assert_eq!(c * _1_0i, c);
280+
assert_eq!(_1_0i * c, c);
281+
}
282+
}
283+
#[test]
284+
fn test_div() {
285+
assert_eq!(_neg1_1i / _0_1i, _1_1i);
286+
for all_consts.each |&c| {
287+
if c != Zero::zero() {
288+
assert_eq!(c / c, _1_0i);
289+
}
290+
}
291+
}
292+
#[test]
293+
fn test_neg() {
294+
assert_eq!(-_1_0i + _0_1i, _neg1_1i);
295+
assert_eq!((-_0_1i) * _0_1i, _1_0i);
296+
for all_consts.each |&c| {
297+
assert_eq!(-(-c), c);
298+
}
299+
}
300+
}
301+
302+
#[test]
303+
fn test_to_str() {
304+
fn test(c : Complex, s: ~str) {
305+
assert_eq!(c.to_str(), s);
306+
}
307+
test(_0_0i, ~"0+0i");
308+
test(_1_0i, ~"1+0i");
309+
test(_0_1i, ~"0+1i");
310+
test(_1_1i, ~"1+1i");
311+
test(_neg1_1i, ~"-1+1i");
312+
test(-_neg1_1i, ~"1-1i");
313+
test(_05_05i, ~"0.5+0.5i");
314+
}
315+
}

0 commit comments

Comments
 (0)