Skip to content

Commit 52a07ef

Browse files
committed
Add comptime_float support to std.math.ldexp
1 parent a518042 commit 52a07ef

File tree

1 file changed

+25
-10
lines changed

1 file changed

+25
-10
lines changed

lib/std/math/ldexp.zig

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ const expect = std.testing.expect;
77
/// Returns x * 2^n.
88
pub fn ldexp(x: anytype, n: i32) @TypeOf(x) {
99
const T = @TypeOf(x);
10-
const TBits = std.meta.Int(.unsigned, @typeInfo(T).float.bits);
10+
const TBits = switch (@typeInfo(T)) {
11+
.float => |float| std.meta.Int(.unsigned, float.bits),
12+
.comptime_float => u128,
13+
else => @compileError("unknown floating point type " ++ @typeName(T)),
14+
};
1115

1216
const exponent_bits = math.floatExponentBits(T);
1317
const mantissa_bits = math.floatMantissaBits(T);
@@ -16,11 +20,13 @@ pub fn ldexp(x: anytype, n: i32) @TypeOf(x) {
1620
const max_biased_exponent = 2 * math.floatExponentMax(T);
1721
const mantissa_mask = @as(TBits, (1 << mantissa_bits) - 1);
1822

19-
const repr = @as(TBits, @bitCast(x));
23+
const repr = bitCastAs(TBits, x);
2024
const sign_bit = repr & (1 << (exponent_bits + mantissa_bits));
2125

22-
if (math.isNan(x) or !math.isFinite(x))
26+
if (math.isNan(x) or !math.isFinite(x)) {
27+
if (T == comptime_float) unreachable;
2328
return x;
29+
}
2430

2531
var exponent: i32 = @as(i32, @intCast((repr << 1) >> (mantissa_bits + 1)));
2632
if (exponent == 0)
@@ -29,23 +35,23 @@ pub fn ldexp(x: anytype, n: i32) @TypeOf(x) {
2935
if (n >= 0) {
3036
if (n > max_biased_exponent - exponent) {
3137
// Overflow. Return +/- inf
32-
return @as(T, @bitCast(@as(TBits, @bitCast(math.inf(T))) | sign_bit));
38+
return bitCastAs(T, bitCastAs(TBits, math.inf(T)) | sign_bit);
3339
} else if (exponent + n <= 0) {
3440
// Result is subnormal
35-
return @as(T, @bitCast((repr << @as(Log2Int(TBits), @intCast(n))) | sign_bit));
41+
return bitCastAs(T, (repr << @as(Log2Int(TBits), @intCast(n))) | sign_bit);
3642
} else if (exponent <= 0) {
3743
// Result is normal, but needs shifting
3844
var result = @as(TBits, @intCast(n + exponent)) << mantissa_bits;
3945
result |= (repr << @as(Log2Int(TBits), @intCast(1 - exponent))) & mantissa_mask;
40-
return @as(T, @bitCast(result | sign_bit));
46+
return bitCastAs(T, result | sign_bit);
4147
}
4248

4349
// Result needs no shifting
44-
return @as(T, @bitCast(repr + (@as(TBits, @intCast(n)) << mantissa_bits)));
50+
return bitCastAs(T, repr + (@as(TBits, @intCast(n)) << mantissa_bits));
4551
} else {
4652
if (n <= -exponent) {
4753
if (n < -(mantissa_bits + exponent))
48-
return @as(T, @bitCast(sign_bit)); // Severe underflow. Return +/- 0
54+
return bitCastAs(T, sign_bit); // Severe underflow. Return +/- 0
4955

5056
// Result underflowed, we need to shift and round
5157
const shift = @as(Log2Int(TBits), @intCast(@min(-n, -(exponent + n) + 1)));
@@ -58,21 +64,30 @@ pub fn ldexp(x: anytype, n: i32) @TypeOf(x) {
5864

5965
// Round result, including round-to-even for exact ties
6066
result = ((result + 1) >> 1) & ~@as(TBits, @intFromBool(exact_tie));
61-
return @as(T, @bitCast(result | sign_bit));
67+
return bitCastAs(T, result | sign_bit);
6268
}
6369

6470
// Result is exact, and needs no shifting
65-
return @as(T, @bitCast(repr - (@as(TBits, @intCast(-n)) << mantissa_bits)));
71+
return bitCastAs(T, repr - (@as(TBits, @intCast(-n)) << mantissa_bits));
6672
}
6773
}
6874

75+
inline fn bitCastAs(comptime T: type, x: anytype) T {
76+
const y = if (@TypeOf(x) == comptime_float) @as(f128, x) else x;
77+
return switch (T) {
78+
comptime_float => @as(T, @as(f128, @bitCast(y))),
79+
else => @as(T, @bitCast(y)),
80+
};
81+
}
82+
6983
test ldexp {
7084
// subnormals
7185
try expect(ldexp(@as(f16, 0x1.1FFp14), -14 - 9 - 15) == math.floatTrueMin(f16));
7286
try expect(ldexp(@as(f32, 0x1.3FFFFFp-1), -126 - 22) == math.floatTrueMin(f32));
7387
try expect(ldexp(@as(f64, 0x1.7FFFFFFFFFFFFp-1), -1022 - 51) == math.floatTrueMin(f64));
7488
try expect(ldexp(@as(f80, 0x1.7FFFFFFFFFFFFFFEp-1), -16382 - 62) == math.floatTrueMin(f80));
7589
try expect(ldexp(@as(f128, 0x1.7FFFFFFFFFFFFFFFFFFFFFFFFFFFp-1), -16382 - 111) == math.floatTrueMin(f128));
90+
try expect(ldexp(@as(comptime_float, 0x1.7FFFFFFFFFFFFFFFFFFFFFFFFFFFp-1), -16382 - 111) == math.floatTrueMin(f128));
7691

7792
try expect(ldexp(math.floatMax(f32), -128 - 149) > 0.0);
7893
try expect(ldexp(math.floatMax(f32), -128 - 149 - 1) == 0.0);

0 commit comments

Comments
 (0)