master
1const std = @import("std");
2const isNan = std.math.isNan;
3const isInf = std.math.isInf;
4const copysign = std.math.copysign;
5
6pub fn Complex(comptime T: type) type {
7 return extern struct {
8 real: T,
9 imag: T,
10 };
11}
12
13/// Implementation based on Annex G of C17 Standard (N2176)
14pub inline fn mulc3(comptime T: type, a_in: T, b_in: T, c_in: T, d_in: T) Complex(T) {
15 var a = a_in;
16 var b = b_in;
17 var c = c_in;
18 var d = d_in;
19
20 const ac = a * c;
21 const bd = b * d;
22 const ad = a * d;
23 const bc = b * c;
24
25 const zero: T = 0.0;
26 const one: T = 1.0;
27
28 const z: Complex(T) = .{
29 .real = ac - bd,
30 .imag = ad + bc,
31 };
32 if (isNan(z.real) and isNan(z.imag)) {
33 var recalc: bool = false;
34
35 if (isInf(a) or isInf(b)) { // (a + ib) is infinite
36
37 // "Box" the infinity (+/-inf goes to +/-1, all finite values go to 0)
38 a = copysign(if (isInf(a)) one else zero, a);
39 b = copysign(if (isInf(b)) one else zero, b);
40
41 // Replace NaNs in the other factor with (signed) 0
42 if (isNan(c)) c = copysign(zero, c);
43 if (isNan(d)) d = copysign(zero, d);
44
45 recalc = true;
46 }
47
48 if (isInf(c) or isInf(d)) { // (c + id) is infinite
49
50 // "Box" the infinity (+/-inf goes to +/-1, all finite values go to 0)
51 c = copysign(if (isInf(c)) one else zero, c);
52 d = copysign(if (isInf(d)) one else zero, d);
53
54 // Replace NaNs in the other factor with (signed) 0
55 if (isNan(a)) a = copysign(zero, a);
56 if (isNan(b)) b = copysign(zero, b);
57
58 recalc = true;
59 }
60
61 if (!recalc and (isInf(ac) or isInf(bd) or isInf(ad) or isInf(bc))) {
62
63 // Recover infinities from overflow by changing NaNs to 0
64 if (isNan(a)) a = copysign(zero, a);
65 if (isNan(b)) b = copysign(zero, b);
66 if (isNan(c)) c = copysign(zero, c);
67 if (isNan(d)) d = copysign(zero, d);
68
69 recalc = true;
70 }
71 if (recalc) {
72 return .{
73 .real = std.math.inf(T) * (a * c - b * d),
74 .imag = std.math.inf(T) * (a * d + b * c),
75 };
76 }
77 }
78 return z;
79}