@@ -7,7 +7,11 @@ const expect = std.testing.expect;
77/// Returns x * 2^n.
88pub 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+
6983test 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