137 lines
2.9 KiB
Zig
137 lines
2.9 KiB
Zig
|
const std = @import("../../index.zig");
|
||
|
const debug = std.debug;
|
||
|
const math = std.math;
|
||
|
const cmath = math.complex;
|
||
|
const Complex = cmath.Complex;
|
||
|
|
||
|
pub fn atan(z: var) Complex(@typeOf(z.re)) {
|
||
|
const T = @typeOf(z.re);
|
||
|
return switch (T) {
|
||
|
f32 => atan32(z),
|
||
|
f64 => atan64(z),
|
||
|
else => @compileError("atan not implemented for " ++ @typeName(z)),
|
||
|
};
|
||
|
}
|
||
|
|
||
|
fn redupif32(x: f32) f32 {
|
||
|
const DP1 = 3.140625;
|
||
|
const DP2 = 9.67502593994140625e-4;
|
||
|
const DP3 = 1.509957990978376432e-7;
|
||
|
|
||
|
var t = x / math.pi;
|
||
|
if (t >= 0.0) {
|
||
|
t += 0.5;
|
||
|
} else {
|
||
|
t -= 0.5;
|
||
|
}
|
||
|
|
||
|
const u = f32(i32(t));
|
||
|
return ((x - u * DP1) - u * DP2) - t * DP3;
|
||
|
}
|
||
|
|
||
|
fn atan32(z: &const Complex(f32)) Complex(f32) {
|
||
|
const maxnum = 1.0e38;
|
||
|
|
||
|
const x = z.re;
|
||
|
const y = z.im;
|
||
|
|
||
|
if ((x == 0.0) and (y > 1.0)) {
|
||
|
// overflow
|
||
|
return Complex(f32).new(maxnum, maxnum);
|
||
|
}
|
||
|
|
||
|
const x2 = x * x;
|
||
|
var a = 1.0 - x2 - (y * y);
|
||
|
if (a == 0.0) {
|
||
|
// overflow
|
||
|
return Complex(f32).new(maxnum, maxnum);
|
||
|
}
|
||
|
|
||
|
var t = 0.5 * math.atan2(f32, 2.0 * x, a);
|
||
|
var w = redupif32(t);
|
||
|
|
||
|
t = y - 1.0;
|
||
|
a = x2 + t * t;
|
||
|
if (a == 0.0) {
|
||
|
// overflow
|
||
|
return Complex(f32).new(maxnum, maxnum);
|
||
|
}
|
||
|
|
||
|
t = y + 1.0;
|
||
|
a = (x2 + (t * t)) / a;
|
||
|
return Complex(f32).new(w, 0.25 * math.ln(a));
|
||
|
}
|
||
|
|
||
|
fn redupif64(x: f64) f64 {
|
||
|
const DP1 = 3.14159265160560607910;
|
||
|
const DP2 = 1.98418714791870343106e-9;
|
||
|
const DP3 = 1.14423774522196636802e-17;
|
||
|
|
||
|
var t = x / math.pi;
|
||
|
if (t >= 0.0) {
|
||
|
t += 0.5;
|
||
|
} else {
|
||
|
t -= 0.5;
|
||
|
}
|
||
|
|
||
|
const u = f64(i64(t));
|
||
|
return ((x - u * DP1) - u * DP2) - t * DP3;
|
||
|
}
|
||
|
|
||
|
fn atan64(z: &const Complex(f64)) Complex(f64) {
|
||
|
const maxnum = 1.0e308;
|
||
|
|
||
|
const x = z.re;
|
||
|
const y = z.im;
|
||
|
|
||
|
if ((x == 0.0) and (y > 1.0)) {
|
||
|
// overflow
|
||
|
return Complex(f64).new(maxnum, maxnum);
|
||
|
}
|
||
|
|
||
|
const x2 = x * x;
|
||
|
var a = 1.0 - x2 - (y * y);
|
||
|
if (a == 0.0) {
|
||
|
// overflow
|
||
|
return Complex(f64).new(maxnum, maxnum);
|
||
|
}
|
||
|
|
||
|
var t = 0.5 * math.atan2(f64, 2.0 * x, a);
|
||
|
var w = redupif64(t);
|
||
|
|
||
|
t = y - 1.0;
|
||
|
a = x2 + t * t;
|
||
|
if (a == 0.0) {
|
||
|
// overflow
|
||
|
return Complex(f64).new(maxnum, maxnum);
|
||
|
}
|
||
|
|
||
|
t = y + 1.0;
|
||
|
a = (x2 + (t * t)) / a;
|
||
|
return Complex(f64).new(w, 0.25 * math.ln(a));
|
||
|
}
|
||
|
|
||
|
const epsilon = 0.0001;
|
||
|
|
||
|
test "complex.ctan32" {
|
||
|
const a = Complex(f32).new(5, 3);
|
||
|
const c = atan(a);
|
||
|
|
||
|
const re = c.re;
|
||
|
const im = c.im;
|
||
|
|
||
|
debug.assert(math.approxEq(f32, re, 1.423679, epsilon));
|
||
|
debug.assert(math.approxEq(f32, im, 0.086569, epsilon));
|
||
|
}
|
||
|
|
||
|
test "complex.ctan64" {
|
||
|
const a = Complex(f64).new(5, 3);
|
||
|
const c = atan(a);
|
||
|
|
||
|
const re = c.re;
|
||
|
const im = c.im;
|
||
|
|
||
|
debug.assert(math.approxEq(f64, re, 1.423679, epsilon));
|
||
|
debug.assert(math.approxEq(f64, im, 0.086569, epsilon));
|
||
|
}
|