divc3.zig (2280B) - Raw
1 const std = @import("std"); 2 const isNan = std.math.isNan; 3 const isInf = std.math.isInf; 4 const scalbn = std.math.scalbn; 5 const ilogb = std.math.ilogb; 6 const maxInt = std.math.maxInt; 7 const minInt = std.math.minInt; 8 const isFinite = std.math.isFinite; 9 const copysign = std.math.copysign; 10 const Complex = @import("mulc3.zig").Complex; 11 12 /// Implementation based on Annex G of C17 Standard (N2176) 13 pub inline fn divc3(comptime T: type, a: T, b: T, c_in: T, d_in: T) Complex(T) { 14 var c = c_in; 15 var d = d_in; 16 17 // logbw used to prevent under/over-flow 18 const logbw = ilogb(@max(@abs(c), @abs(d))); 19 const logbw_finite = logbw != maxInt(i32) and logbw != minInt(i32); 20 const ilogbw = if (logbw_finite) b: { 21 c = scalbn(c, -logbw); 22 d = scalbn(d, -logbw); 23 break :b logbw; 24 } else 0; 25 const denom = c * c + d * d; 26 const result = Complex(T){ 27 .real = scalbn((a * c + b * d) / denom, -ilogbw), 28 .imag = scalbn((b * c - a * d) / denom, -ilogbw), 29 }; 30 31 // Recover infinities and zeros that computed as NaN+iNaN; 32 // the only cases are non-zero/zero, infinite/finite, and finite/infinite, ... 33 if (isNan(result.real) and isNan(result.imag)) { 34 const zero: T = 0.0; 35 const one: T = 1.0; 36 37 if ((denom == 0.0) and (!isNan(a) or !isNan(b))) { 38 return .{ 39 .real = copysign(std.math.inf(T), c) * a, 40 .imag = copysign(std.math.inf(T), c) * b, 41 }; 42 } else if ((isInf(a) or isInf(b)) and isFinite(c) and isFinite(d)) { 43 const boxed_a = copysign(if (isInf(a)) one else zero, a); 44 const boxed_b = copysign(if (isInf(b)) one else zero, b); 45 return .{ 46 .real = std.math.inf(T) * (boxed_a * c - boxed_b * d), 47 .imag = std.math.inf(T) * (boxed_b * c - boxed_a * d), 48 }; 49 } else if (logbw == maxInt(i32) and isFinite(a) and isFinite(b)) { 50 const boxed_c = copysign(if (isInf(c)) one else zero, c); 51 const boxed_d = copysign(if (isInf(d)) one else zero, d); 52 return .{ 53 .real = 0.0 * (a * boxed_c + b * boxed_d), 54 .imag = 0.0 * (b * boxed_c - a * boxed_d), 55 }; 56 } 57 } 58 59 return result; 60 }