A complex number consisting of a real an imaginary part. T must be a floating-point value.
T: typere: TReal part.
im: TImaginary part.
pub fn init(re: T, im: T) SelfCreate a new Complex number from the given real and imaginary parts.
re: Tim: TReturns the sum of two complex numbers.
Returns the subtraction of two complex numbers.
Returns the product of two complex numbers.
Returns the quotient of two complex numbers.
pub fn Complex(comptime T: type) type {
return struct {
const Self = @This();
/// Real part.
re: T,
/// Imaginary part.
im: T,
/// Create a new Complex number from the given real and imaginary parts.
pub fn init(re: T, im: T) Self {
return Self{
.re = re,
.im = im,
};
}
/// Returns the sum of two complex numbers.
pub fn add(self: Self, other: Self) Self {
return Self{
.re = self.re + other.re,
.im = self.im + other.im,
};
}
/// Returns the subtraction of two complex numbers.
pub fn sub(self: Self, other: Self) Self {
return Self{
.re = self.re - other.re,
.im = self.im - other.im,
};
}
/// Returns the product of two complex numbers.
pub fn mul(self: Self, other: Self) Self {
return Self{
.re = self.re * other.re - self.im * other.im,
.im = self.im * other.re + self.re * other.im,
};
}
/// Returns the quotient of two complex numbers.
pub fn div(self: Self, other: Self) Self {
const re_num = self.re * other.re + self.im * other.im;
const im_num = self.im * other.re - self.re * other.im;
const den = other.re * other.re + other.im * other.im;
return Self{
.re = re_num / den,
.im = im_num / den,
};
}
/// Returns the complex conjugate of a number.
pub fn conjugate(self: Self) Self {
return Self{
.re = self.re,
.im = -self.im,
};
}
/// Returns the negation of a complex number.
pub fn neg(self: Self) Self {
return Self{
.re = -self.re,
.im = -self.im,
};
}
/// Returns the product of complex number and i=sqrt(-1)
pub fn mulbyi(self: Self) Self {
return Self{
.re = -self.im,
.im = self.re,
};
}
/// Returns the reciprocal of a complex number.
pub fn reciprocal(self: Self) Self {
const m = self.re * self.re + self.im * self.im;
return Self{
.re = self.re / m,
.im = -self.im / m,
};
}
/// Returns the magnitude of a complex number.
pub fn magnitude(self: Self) T {
return @sqrt(self.re * self.re + self.im * self.im);
}
pub fn squaredMagnitude(self: Self) T {
return self.re * self.re + self.im * self.im;
}
};
}pub fn abs(z: anytype) @TypeOf(z.re, z.im)Returns the absolute value (modulus) of z.
pub fn acosh(z: anytype) Complex(@TypeOf(z.re, z.im))Returns the hyperbolic arc-cosine of z.
test acosh {
const epsilon = math.floatEps(f32);
const a = Complex(f32).init(5, 3);
const c = acosh(a);
try testing.expectApproxEqAbs(2.4529128, c.re, epsilon);
try testing.expectApproxEqAbs(0.5469737, c.im, epsilon);
}pub fn acos(z: anytype) Complex(@TypeOf(z.re, z.im))Returns the arc-cosine of z.
test acos {
const epsilon = math.floatEps(f32);
const a = Complex(f32).init(5, 3);
const c = acos(a);
try testing.expectApproxEqAbs(0.5469737, c.re, epsilon);
try testing.expectApproxEqAbs(-2.4529128, c.im, epsilon);
}pub fn arg(z: anytype) @TypeOf(z.re, z.im)Returns the angular component (in radians) of z.
pub fn asinh(z: anytype) Complex(@TypeOf(z.re, z.im))Returns the hyperbolic arc-sine of z.
test asinh {
const epsilon = math.floatEps(f32);
const a = Complex(f32).init(5, 3);
const c = asinh(a);
try testing.expectApproxEqAbs(2.4598298, c.re, epsilon);
try testing.expectApproxEqAbs(0.5339993, c.im, epsilon);
}pub fn asin(z: anytype) Complex(@TypeOf(z.re, z.im))test asin {
const epsilon = math.floatEps(f32);
const a = Complex(f32).init(5, 3);
const c = asin(a);
try testing.expectApproxEqAbs(1.0238227, c.re, epsilon);
try testing.expectApproxEqAbs(2.4529128, c.im, epsilon);
}pub fn asin(z: anytype) Complex(@TypeOf(z.re, z.im)) {
const T = @TypeOf(z.re, z.im);
const x = z.re;
const y = z.im;
const p = Complex(T).init(1.0 - (x - y) * (x + y), -2.0 * x * y);
const q = Complex(T).init(-y, x);
const r = cmath.log(q.add(cmath.sqrt(p)));
return Complex(T).init(r.im, -r.re);
}pub fn atanh(z: anytype) Complex(@TypeOf(z.re, z.im))Returns the hyperbolic arc-tangent of z.
test atanh {
const epsilon = math.floatEps(f32);
const a = Complex(f32).init(5, 3);
const c = atanh(a);
try testing.expectApproxEqAbs(0.14694665, c.re, epsilon);
try testing.expectApproxEqAbs(1.4808695, c.im, epsilon);
}pub fn conj(z: anytype) Complex(@TypeOf(z.re, z.im))Returns the complex conjugate of z.
test conj {
const a = Complex(f32).init(5, 3);
const c = a.conjugate();
try testing.expectEqual(5, c.re);
try testing.expectEqual(-3, c.im);
}pub fn cosh(z: anytype) Complex(@TypeOf(z.re, z.im))Returns the hyperbolic arc-cosine of z.
pub fn cos(z: anytype) Complex(@TypeOf(z.re, z.im))Returns the cosine of z.
test cos {
const epsilon = math.floatEps(f32);
const a = Complex(f32).init(5, 3);
const c = cos(a);
try testing.expectApproxEqAbs(2.8558152, c.re, epsilon);
try testing.expectApproxEqAbs(9.606383, c.im, epsilon);
}pub fn exp(z: anytype) Complex(@TypeOf(z.re, z.im))Returns e raised to the power of z (e^z).
pub fn log(z: anytype) Complex(@TypeOf(z.re, z.im))Returns the natural logarithm of z.
test log {
const epsilon = math.floatEps(f32);
const a = Complex(f32).init(5, 3);
const c = log(a);
try testing.expectApproxEqAbs(1.7631803, c.re, epsilon);
try testing.expectApproxEqAbs(0.5404195, c.im, epsilon);
}pub fn pow(z: anytype, s: anytype) Complex(@TypeOf(z.re, z.im, s.re, s.im))Returns z raised to the complex power of c.
test pow {
const epsilon = math.floatEps(f32);
const a = Complex(f32).init(5, 3);
const b = Complex(f32).init(2.3, -1.3);
const c = pow(a, b);
try testing.expectApproxEqAbs(58.049110, c.re, epsilon);
try testing.expectApproxEqAbs(-101.003433, c.im, epsilon);
}pub fn proj(z: anytype) Complex(@TypeOf(z.re, z.im))Returns the projection of z onto the riemann sphere.
test proj {
const a = Complex(f32).init(5, 3);
const c = proj(a);
try testing.expectEqual(5, c.re);
try testing.expectEqual(3, c.im);
}pub fn sinh(z: anytype) Complex(@TypeOf(z.re, z.im))Returns the hyperbolic sine of z.
pub fn sin(z: anytype) Complex(@TypeOf(z.re, z.im))Returns the sine of z.
test sin {
const epsilon = math.floatEps(f32);
const a = Complex(f32).init(5, 3);
const c = sin(a);
try testing.expectApproxEqAbs(-9.654126, c.re, epsilon);
try testing.expectApproxEqAbs(2.8416924, c.im, epsilon);
}pub fn sqrt(z: anytype) Complex(@TypeOf(z.re, z.im))Returns the square root of z. The real and imaginary parts of the result have the same sign as the imaginary part of z.
pub fn tanh(z: anytype) Complex(@TypeOf(z.re, z.im))Returns the hyperbolic tangent of z.
pub fn tan(z: anytype) Complex(@TypeOf(z.re, z.im))Returns the tangent of z.
test tan {
const epsilon = math.floatEps(f32);
const a = Complex(f32).init(5, 3);
const c = tan(a);
try testing.expectApproxEqAbs(-0.002708233, c.re, epsilon);
try testing.expectApproxEqAbs(1.0041647, c.im, epsilon);
}const std = @import("../std.zig");
const testing = std.testing;
const math = std.math;
pub const abs = @import("complex/abs.zig").abs;
pub const acosh = @import("complex/acosh.zig").acosh;
pub const acos = @import("complex/acos.zig").acos;
pub const arg = @import("complex/arg.zig").arg;
pub const asinh = @import("complex/asinh.zig").asinh;
pub const asin = @import("complex/asin.zig").asin;
pub const atanh = @import("complex/atanh.zig").atanh;
pub const atan = @import("complex/atan.zig").atan;
pub const conj = @import("complex/conj.zig").conj;
pub const cosh = @import("complex/cosh.zig").cosh;
pub const cos = @import("complex/cos.zig").cos;
pub const exp = @import("complex/exp.zig").exp;
pub const log = @import("complex/log.zig").log;
pub const pow = @import("complex/pow.zig").pow;
pub const proj = @import("complex/proj.zig").proj;
pub const sinh = @import("complex/sinh.zig").sinh;
pub const sin = @import("complex/sin.zig").sin;
pub const sqrt = @import("complex/sqrt.zig").sqrt;
pub const tanh = @import("complex/tanh.zig").tanh;
pub const tan = @import("complex/tan.zig").tan;
/// A complex number consisting of a real an imaginary part. T must be a floating-point value.
pub fn Complex(comptime T: type) type {
return struct {
const Self = @This();
/// Real part.
re: T,
/// Imaginary part.
im: T,
/// Create a new Complex number from the given real and imaginary parts.
pub fn init(re: T, im: T) Self {
return Self{
.re = re,
.im = im,
};
}
/// Returns the sum of two complex numbers.
pub fn add(self: Self, other: Self) Self {
return Self{
.re = self.re + other.re,
.im = self.im + other.im,
};
}
/// Returns the subtraction of two complex numbers.
pub fn sub(self: Self, other: Self) Self {
return Self{
.re = self.re - other.re,
.im = self.im - other.im,
};
}
/// Returns the product of two complex numbers.
pub fn mul(self: Self, other: Self) Self {
return Self{
.re = self.re * other.re - self.im * other.im,
.im = self.im * other.re + self.re * other.im,
};
}
/// Returns the quotient of two complex numbers.
pub fn div(self: Self, other: Self) Self {
const re_num = self.re * other.re + self.im * other.im;
const im_num = self.im * other.re - self.re * other.im;
const den = other.re * other.re + other.im * other.im;
return Self{
.re = re_num / den,
.im = im_num / den,
};
}
/// Returns the complex conjugate of a number.
pub fn conjugate(self: Self) Self {
return Self{
.re = self.re,
.im = -self.im,
};
}
/// Returns the negation of a complex number.
pub fn neg(self: Self) Self {
return Self{
.re = -self.re,
.im = -self.im,
};
}
/// Returns the product of complex number and i=sqrt(-1)
pub fn mulbyi(self: Self) Self {
return Self{
.re = -self.im,
.im = self.re,
};
}
/// Returns the reciprocal of a complex number.
pub fn reciprocal(self: Self) Self {
const m = self.re * self.re + self.im * self.im;
return Self{
.re = self.re / m,
.im = -self.im / m,
};
}
/// Returns the magnitude of a complex number.
pub fn magnitude(self: Self) T {
return @sqrt(self.re * self.re + self.im * self.im);
}
pub fn squaredMagnitude(self: Self) T {
return self.re * self.re + self.im * self.im;
}
};
}
const epsilon = 0.0001;
test "add" {
const a = Complex(f32).init(5, 3);
const b = Complex(f32).init(2, 7);
const c = a.add(b);
try testing.expect(c.re == 7 and c.im == 10);
}
test "sub" {
const a = Complex(f32).init(5, 3);
const b = Complex(f32).init(2, 7);
const c = a.sub(b);
try testing.expect(c.re == 3 and c.im == -4);
}
test "mul" {
const a = Complex(f32).init(5, 3);
const b = Complex(f32).init(2, 7);
const c = a.mul(b);
try testing.expect(c.re == -11 and c.im == 41);
}
test "div" {
const a = Complex(f32).init(5, 3);
const b = Complex(f32).init(2, 7);
const c = a.div(b);
try testing.expect(math.approxEqAbs(f32, c.re, @as(f32, 31) / 53, epsilon) and
math.approxEqAbs(f32, c.im, @as(f32, -29) / 53, epsilon));
}
test "conjugate" {
const a = Complex(f32).init(5, 3);
const c = a.conjugate();
try testing.expect(c.re == 5 and c.im == -3);
}
test "neg" {
const a = Complex(f32).init(5, 3);
const c = a.neg();
try testing.expect(c.re == -5 and c.im == -3);
}
test "mulbyi" {
const a = Complex(f32).init(5, 3);
const c = a.mulbyi();
try testing.expect(c.re == -3 and c.im == 5);
}
test "reciprocal" {
const a = Complex(f32).init(5, 3);
const c = a.reciprocal();
try testing.expect(math.approxEqAbs(f32, c.re, @as(f32, 5) / 34, epsilon) and
math.approxEqAbs(f32, c.im, @as(f32, -3) / 34, epsilon));
}
test "magnitude" {
const a = Complex(f32).init(5, 3);
const c = a.magnitude();
try testing.expect(math.approxEqAbs(f32, c, 5.83095, epsilon));
}
test "squaredMagnitude" {
const a = Complex(f32).init(5, 3);
const c = a.squaredMagnitude();
try testing.expect(math.approxEqAbs(f32, c, math.pow(f32, a.magnitude(), 2), epsilon));
}
test {
_ = @import("complex/abs.zig");
_ = @import("complex/acosh.zig");
_ = @import("complex/acos.zig");
_ = @import("complex/arg.zig");
_ = @import("complex/asinh.zig");
_ = @import("complex/asin.zig");
_ = @import("complex/atanh.zig");
_ = @import("complex/atan.zig");
_ = @import("complex/conj.zig");
_ = @import("complex/cosh.zig");
_ = @import("complex/cos.zig");
_ = @import("complex/exp.zig");
_ = @import("complex/log.zig");
_ = @import("complex/pow.zig");
_ = @import("complex/proj.zig");
_ = @import("complex/sinh.zig");
_ = @import("complex/sin.zig");
_ = @import("complex/sqrt.zig");
_ = @import("complex/tanh.zig");
_ = @import("complex/tan.zig");
}