mirror of
https://github.com/ziglang/zig.git
synced 2024-12-03 18:38:45 +00:00
05915b85dd
These are the standard complex multiplication/division functions required by the C standard (Annex G). Don't get me started on the standard's handling of complex-infinity...
80 lines
2.2 KiB
Zig
80 lines
2.2 KiB
Zig
const std = @import("std");
|
|
const isNan = std.math.isNan;
|
|
const isInf = std.math.isInf;
|
|
const copysign = std.math.copysign;
|
|
|
|
pub fn Complex(comptime T: type) type {
|
|
return extern struct {
|
|
real: T,
|
|
imag: T,
|
|
};
|
|
}
|
|
|
|
/// Implementation based on Annex G of C17 Standard (N2176)
|
|
pub inline fn mulc3(comptime T: type, a_in: T, b_in: T, c_in: T, d_in: T) Complex(T) {
|
|
var a = a_in;
|
|
var b = b_in;
|
|
var c = c_in;
|
|
var d = d_in;
|
|
|
|
const ac = a * c;
|
|
const bd = b * d;
|
|
const ad = a * d;
|
|
const bc = b * c;
|
|
|
|
const zero: T = 0.0;
|
|
const one: T = 1.0;
|
|
|
|
var z = Complex(T){
|
|
.real = ac - bd,
|
|
.imag = ad + bc,
|
|
};
|
|
if (isNan(z.real) and isNan(z.imag)) {
|
|
var recalc: bool = false;
|
|
|
|
if (isInf(a) or isInf(b)) { // (a + ib) is infinite
|
|
|
|
// "Box" the infinity (+/-inf goes to +/-1, all finite values go to 0)
|
|
a = copysign(if (isInf(a)) one else zero, a);
|
|
b = copysign(if (isInf(b)) one else zero, b);
|
|
|
|
// Replace NaNs in the other factor with (signed) 0
|
|
if (isNan(c)) c = copysign(zero, c);
|
|
if (isNan(d)) d = copysign(zero, d);
|
|
|
|
recalc = true;
|
|
}
|
|
|
|
if (isInf(c) or isInf(d)) { // (c + id) is infinite
|
|
|
|
// "Box" the infinity (+/-inf goes to +/-1, all finite values go to 0)
|
|
c = copysign(if (isInf(c)) one else zero, c);
|
|
d = copysign(if (isInf(d)) one else zero, d);
|
|
|
|
// Replace NaNs in the other factor with (signed) 0
|
|
if (isNan(a)) a = copysign(zero, a);
|
|
if (isNan(b)) b = copysign(zero, b);
|
|
|
|
recalc = true;
|
|
}
|
|
|
|
if (!recalc and (isInf(ac) or isInf(bd) or isInf(ad) or isInf(bc))) {
|
|
|
|
// Recover infinities from overflow by changing NaNs to 0
|
|
if (isNan(a)) a = copysign(zero, a);
|
|
if (isNan(b)) b = copysign(zero, b);
|
|
if (isNan(c)) c = copysign(zero, c);
|
|
if (isNan(d)) d = copysign(zero, d);
|
|
|
|
recalc = true;
|
|
}
|
|
if (recalc) {
|
|
return .{
|
|
.real = std.math.inf(T) * (a * c - b * d),
|
|
.imag = std.math.inf(T) * (a * d + b * c),
|
|
};
|
|
}
|
|
}
|
|
return z;
|
|
}
|