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}