master
  1const std = @import("../std.zig");
  2const testing = std.testing;
  3const math = std.math;
  4
  5pub const abs = @import("complex/abs.zig").abs;
  6pub const acosh = @import("complex/acosh.zig").acosh;
  7pub const acos = @import("complex/acos.zig").acos;
  8pub const arg = @import("complex/arg.zig").arg;
  9pub const asinh = @import("complex/asinh.zig").asinh;
 10pub const asin = @import("complex/asin.zig").asin;
 11pub const atanh = @import("complex/atanh.zig").atanh;
 12pub const atan = @import("complex/atan.zig").atan;
 13pub const conj = @import("complex/conj.zig").conj;
 14pub const cosh = @import("complex/cosh.zig").cosh;
 15pub const cos = @import("complex/cos.zig").cos;
 16pub const exp = @import("complex/exp.zig").exp;
 17pub const log = @import("complex/log.zig").log;
 18pub const pow = @import("complex/pow.zig").pow;
 19pub const proj = @import("complex/proj.zig").proj;
 20pub const sinh = @import("complex/sinh.zig").sinh;
 21pub const sin = @import("complex/sin.zig").sin;
 22pub const sqrt = @import("complex/sqrt.zig").sqrt;
 23pub const tanh = @import("complex/tanh.zig").tanh;
 24pub const tan = @import("complex/tan.zig").tan;
 25
 26/// A complex number consisting of a real an imaginary part. T must be a floating-point value.
 27pub fn Complex(comptime T: type) type {
 28    return struct {
 29        const Self = @This();
 30
 31        /// Real part.
 32        re: T,
 33
 34        /// Imaginary part.
 35        im: T,
 36
 37        /// Create a new Complex number from the given real and imaginary parts.
 38        pub fn init(re: T, im: T) Self {
 39            return Self{
 40                .re = re,
 41                .im = im,
 42            };
 43        }
 44
 45        /// Returns the sum of two complex numbers.
 46        pub fn add(self: Self, other: Self) Self {
 47            return Self{
 48                .re = self.re + other.re,
 49                .im = self.im + other.im,
 50            };
 51        }
 52
 53        /// Returns the subtraction of two complex numbers.
 54        pub fn sub(self: Self, other: Self) Self {
 55            return Self{
 56                .re = self.re - other.re,
 57                .im = self.im - other.im,
 58            };
 59        }
 60
 61        /// Returns the product of two complex numbers.
 62        pub fn mul(self: Self, other: Self) Self {
 63            return Self{
 64                .re = self.re * other.re - self.im * other.im,
 65                .im = self.im * other.re + self.re * other.im,
 66            };
 67        }
 68
 69        /// Returns the quotient of two complex numbers.
 70        pub fn div(self: Self, other: Self) Self {
 71            const re_num = self.re * other.re + self.im * other.im;
 72            const im_num = self.im * other.re - self.re * other.im;
 73            const den = other.re * other.re + other.im * other.im;
 74
 75            return Self{
 76                .re = re_num / den,
 77                .im = im_num / den,
 78            };
 79        }
 80
 81        /// Returns the complex conjugate of a number.
 82        pub fn conjugate(self: Self) Self {
 83            return Self{
 84                .re = self.re,
 85                .im = -self.im,
 86            };
 87        }
 88
 89        /// Returns the negation of a complex number.
 90        pub fn neg(self: Self) Self {
 91            return Self{
 92                .re = -self.re,
 93                .im = -self.im,
 94            };
 95        }
 96
 97        /// Returns the product of complex number and i=sqrt(-1)
 98        pub fn mulbyi(self: Self) Self {
 99            return Self{
100                .re = -self.im,
101                .im = self.re,
102            };
103        }
104
105        /// Returns the reciprocal of a complex number.
106        pub fn reciprocal(self: Self) Self {
107            const m = self.re * self.re + self.im * self.im;
108            return Self{
109                .re = self.re / m,
110                .im = -self.im / m,
111            };
112        }
113
114        /// Returns the magnitude of a complex number.
115        pub fn magnitude(self: Self) T {
116            return @sqrt(self.re * self.re + self.im * self.im);
117        }
118
119        pub fn squaredMagnitude(self: Self) T {
120            return self.re * self.re + self.im * self.im;
121        }
122    };
123}
124
125const epsilon = 0.0001;
126
127test "add" {
128    const a = Complex(f32).init(5, 3);
129    const b = Complex(f32).init(2, 7);
130    const c = a.add(b);
131
132    try testing.expect(c.re == 7 and c.im == 10);
133}
134
135test "sub" {
136    const a = Complex(f32).init(5, 3);
137    const b = Complex(f32).init(2, 7);
138    const c = a.sub(b);
139
140    try testing.expect(c.re == 3 and c.im == -4);
141}
142
143test "mul" {
144    const a = Complex(f32).init(5, 3);
145    const b = Complex(f32).init(2, 7);
146    const c = a.mul(b);
147
148    try testing.expect(c.re == -11 and c.im == 41);
149}
150
151test "div" {
152    const a = Complex(f32).init(5, 3);
153    const b = Complex(f32).init(2, 7);
154    const c = a.div(b);
155
156    try testing.expect(math.approxEqAbs(f32, c.re, @as(f32, 31) / 53, epsilon) and
157        math.approxEqAbs(f32, c.im, @as(f32, -29) / 53, epsilon));
158}
159
160test "conjugate" {
161    const a = Complex(f32).init(5, 3);
162    const c = a.conjugate();
163
164    try testing.expect(c.re == 5 and c.im == -3);
165}
166
167test "neg" {
168    const a = Complex(f32).init(5, 3);
169    const c = a.neg();
170
171    try testing.expect(c.re == -5 and c.im == -3);
172}
173
174test "mulbyi" {
175    const a = Complex(f32).init(5, 3);
176    const c = a.mulbyi();
177
178    try testing.expect(c.re == -3 and c.im == 5);
179}
180
181test "reciprocal" {
182    const a = Complex(f32).init(5, 3);
183    const c = a.reciprocal();
184
185    try testing.expect(math.approxEqAbs(f32, c.re, @as(f32, 5) / 34, epsilon) and
186        math.approxEqAbs(f32, c.im, @as(f32, -3) / 34, epsilon));
187}
188
189test "magnitude" {
190    const a = Complex(f32).init(5, 3);
191    const c = a.magnitude();
192
193    try testing.expect(math.approxEqAbs(f32, c, 5.83095, epsilon));
194}
195
196test "squaredMagnitude" {
197    const a = Complex(f32).init(5, 3);
198    const c = a.squaredMagnitude();
199
200    try testing.expect(math.approxEqAbs(f32, c, math.pow(f32, a.magnitude(), 2), epsilon));
201}
202
203test {
204    _ = @import("complex/abs.zig");
205    _ = @import("complex/acosh.zig");
206    _ = @import("complex/acos.zig");
207    _ = @import("complex/arg.zig");
208    _ = @import("complex/asinh.zig");
209    _ = @import("complex/asin.zig");
210    _ = @import("complex/atanh.zig");
211    _ = @import("complex/atan.zig");
212    _ = @import("complex/conj.zig");
213    _ = @import("complex/cosh.zig");
214    _ = @import("complex/cos.zig");
215    _ = @import("complex/exp.zig");
216    _ = @import("complex/log.zig");
217    _ = @import("complex/pow.zig");
218    _ = @import("complex/proj.zig");
219    _ = @import("complex/sinh.zig");
220    _ = @import("complex/sin.zig");
221    _ = @import("complex/sqrt.zig");
222    _ = @import("complex/tanh.zig");
223    _ = @import("complex/tan.zig");
224}