zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

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 }