master
  1// Ported from musl, which is MIT licensed.
  2// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
  3//
  4// https://git.musl-libc.org/cgit/musl/tree/src/math/ilogbl.c
  5// https://git.musl-libc.org/cgit/musl/tree/src/math/ilogbf.c
  6// https://git.musl-libc.org/cgit/musl/tree/src/math/ilogb.c
  7
  8const std = @import("../std.zig");
  9const math = std.math;
 10const expect = std.testing.expect;
 11const maxInt = std.math.maxInt;
 12const minInt = std.math.minInt;
 13
 14/// Returns the binary exponent of x as an integer.
 15///
 16/// Special Cases:
 17///  - ilogb(+-inf) = maxInt(i32)
 18///  - ilogb(+-0)   = minInt(i32)
 19///  - ilogb(nan)   = minInt(i32)
 20pub fn ilogb(x: anytype) i32 {
 21    const T = @TypeOf(x);
 22    return ilogbX(T, x);
 23}
 24
 25pub const fp_ilogbnan = minInt(i32);
 26pub const fp_ilogb0 = minInt(i32);
 27
 28fn ilogbX(comptime T: type, x: T) i32 {
 29    const typeWidth = @typeInfo(T).float.bits;
 30    const significandBits = math.floatMantissaBits(T);
 31    const exponentBits = math.floatExponentBits(T);
 32
 33    const Z = std.meta.Int(.unsigned, typeWidth);
 34
 35    const signBit = (@as(Z, 1) << (significandBits + exponentBits));
 36    const maxExponent = ((1 << exponentBits) - 1);
 37    const exponentBias = (maxExponent >> 1);
 38
 39    const absMask = signBit - 1;
 40
 41    const u = @as(Z, @bitCast(x)) & absMask;
 42    const e: i32 = @intCast(u >> significandBits);
 43
 44    if (e == 0) {
 45        if (u == 0) {
 46            math.raiseInvalid();
 47            return fp_ilogb0;
 48        }
 49
 50        // offset sign bit, exponent bits, and integer bit (if present) + bias
 51        const offset = 1 + exponentBits + @as(comptime_int, @intFromBool(T == f80)) - exponentBias;
 52        return offset - @as(i32, @intCast(@clz(u)));
 53    }
 54
 55    if (e == maxExponent) {
 56        math.raiseInvalid();
 57        if (u > @as(Z, @bitCast(math.inf(T)))) {
 58            return fp_ilogbnan; // u is a NaN
 59        } else return maxInt(i32);
 60    }
 61
 62    return e - exponentBias;
 63}
 64
 65test "type dispatch" {
 66    try expect(ilogb(@as(f32, 0.2)) == ilogbX(f32, 0.2));
 67    try expect(ilogb(@as(f64, 0.2)) == ilogbX(f64, 0.2));
 68}
 69
 70test "16" {
 71    try expect(ilogbX(f16, 0.0) == fp_ilogb0);
 72    try expect(ilogbX(f16, 0.5) == -1);
 73    try expect(ilogbX(f16, 0.8923) == -1);
 74    try expect(ilogbX(f16, 10.0) == 3);
 75    try expect(ilogbX(f16, -65504) == 15);
 76    try expect(ilogbX(f16, 2398.23) == 11);
 77
 78    try expect(ilogbX(f16, 0x1p-1) == -1);
 79    try expect(ilogbX(f16, 0x1p-17) == -17);
 80    try expect(ilogbX(f16, 0x1p-24) == -24);
 81}
 82
 83test "32" {
 84    try expect(ilogbX(f32, 0.0) == fp_ilogb0);
 85    try expect(ilogbX(f32, 0.5) == -1);
 86    try expect(ilogbX(f32, 0.8923) == -1);
 87    try expect(ilogbX(f32, 10.0) == 3);
 88    try expect(ilogbX(f32, -123984) == 16);
 89    try expect(ilogbX(f32, 2398.23) == 11);
 90
 91    try expect(ilogbX(f32, 0x1p-1) == -1);
 92    try expect(ilogbX(f32, 0x1p-122) == -122);
 93    try expect(ilogbX(f32, 0x1p-127) == -127);
 94}
 95
 96test "64" {
 97    try expect(ilogbX(f64, 0.0) == fp_ilogb0);
 98    try expect(ilogbX(f64, 0.5) == -1);
 99    try expect(ilogbX(f64, 0.8923) == -1);
100    try expect(ilogbX(f64, 10.0) == 3);
101    try expect(ilogbX(f64, -123984) == 16);
102    try expect(ilogbX(f64, 2398.23) == 11);
103
104    try expect(ilogbX(f64, 0x1p-1) == -1);
105    try expect(ilogbX(f64, 0x1p-127) == -127);
106    try expect(ilogbX(f64, 0x1p-1012) == -1012);
107    try expect(ilogbX(f64, 0x1p-1023) == -1023);
108}
109
110test "80" {
111    try expect(ilogbX(f80, 0.0) == fp_ilogb0);
112    try expect(ilogbX(f80, 0.5) == -1);
113    try expect(ilogbX(f80, 0.8923) == -1);
114    try expect(ilogbX(f80, 10.0) == 3);
115    try expect(ilogbX(f80, -123984) == 16);
116    try expect(ilogbX(f80, 2398.23) == 11);
117
118    try expect(ilogbX(f80, 0x1p-1) == -1);
119    try expect(ilogbX(f80, 0x1p-127) == -127);
120    try expect(ilogbX(f80, 0x1p-1023) == -1023);
121    try expect(ilogbX(f80, 0x1p-16383) == -16383);
122}
123
124test "128" {
125    try expect(ilogbX(f128, 0.0) == fp_ilogb0);
126    try expect(ilogbX(f128, 0.5) == -1);
127    try expect(ilogbX(f128, 0.8923) == -1);
128    try expect(ilogbX(f128, 10.0) == 3);
129    try expect(ilogbX(f128, -123984) == 16);
130    try expect(ilogbX(f128, 2398.23) == 11);
131
132    try expect(ilogbX(f128, 0x1p-1) == -1);
133    try expect(ilogbX(f128, 0x1p-127) == -127);
134    try expect(ilogbX(f128, 0x1p-1023) == -1023);
135    try expect(ilogbX(f128, 0x1p-16383) == -16383);
136}
137
138test "16 special" {
139    try expect(ilogbX(f16, math.inf(f16)) == maxInt(i32));
140    try expect(ilogbX(f16, -math.inf(f16)) == maxInt(i32));
141    try expect(ilogbX(f16, 0.0) == minInt(i32));
142    try expect(ilogbX(f16, math.nan(f16)) == fp_ilogbnan);
143}
144
145test "32 special" {
146    try expect(ilogbX(f32, math.inf(f32)) == maxInt(i32));
147    try expect(ilogbX(f32, -math.inf(f32)) == maxInt(i32));
148    try expect(ilogbX(f32, 0.0) == minInt(i32));
149    try expect(ilogbX(f32, math.nan(f32)) == fp_ilogbnan);
150}
151
152test "64 special" {
153    try expect(ilogbX(f64, math.inf(f64)) == maxInt(i32));
154    try expect(ilogbX(f64, -math.inf(f64)) == maxInt(i32));
155    try expect(ilogbX(f64, 0.0) == minInt(i32));
156    try expect(ilogbX(f64, math.nan(f64)) == fp_ilogbnan);
157}
158
159test "80 special" {
160    try expect(ilogbX(f80, math.inf(f80)) == maxInt(i32));
161    try expect(ilogbX(f80, -math.inf(f80)) == maxInt(i32));
162    try expect(ilogbX(f80, 0.0) == minInt(i32));
163    try expect(ilogbX(f80, math.nan(f80)) == fp_ilogbnan);
164}
165
166test "128 special" {
167    try expect(ilogbX(f128, math.inf(f128)) == maxInt(i32));
168    try expect(ilogbX(f128, -math.inf(f128)) == maxInt(i32));
169    try expect(ilogbX(f128, 0.0) == minInt(i32));
170    try expect(ilogbX(f128, math.nan(f128)) == fp_ilogbnan);
171}