@@ -31,24 +31,20 @@ const expect = std.testing.expect;
3131/// - pow(-inf, y) = pow(-0, -y)
3232/// - pow(x, y) = nan for finite x < 0 and finite non-integer y
3333pub fn pow (comptime T : type , x : T , y : T ) T {
34- if (@typeInfo (T ) == .int ) {
34+ const info = @typeInfo (T );
35+ if (info == .int or info == .comptime_int )
3536 return math .powi (T , x , y ) catch unreachable ;
36- }
37-
38- if (T != f32 and T != f64 ) {
39- @compileError ("pow not implemented for " ++ @typeName (T ));
40- }
4137
4238 // pow(x, +-0) = 1 for all x
4339 // pow(1, y) = 1 for all y
44- if (y == 0 or x == 1 ) {
40+ if (y == 0 or x == 1 )
4541 return 1 ;
46- }
4742
4843 // pow(nan, y) = nan for all y
4944 // pow(x, nan) = nan for all x
5045 if (math .isNan (x ) or math .isNan (y )) {
5146 @branchHint (.unlikely );
47+ if (info == .comptime_float ) unreachable ;
5248 return math .nan (T );
5349 }
5450
@@ -60,15 +56,15 @@ pub fn pow(comptime T: type, x: T, y: T) T {
6056 if (x == 0 ) {
6157 if (y < 0 ) {
6258 // pow(+-0, y) = +-inf for y an odd integer
63- if (isOddInteger (y )) {
59+ if (isOddInteger (T , y )) {
6460 return math .copysign (math .inf (T ), x );
6561 }
6662 // pow(+-0, y) = +inf for y an even integer
6763 else {
6864 return math .inf (T );
6965 }
7066 } else {
71- if (isOddInteger (y )) {
67+ if (isOddInteger (T , y )) {
7268 return x ;
7369 } else {
7470 return 0 ;
@@ -77,6 +73,9 @@ pub fn pow(comptime T: type, x: T, y: T) T {
7773 }
7874
7975 if (math .isInf (y )) {
76+ @branchHint (.unlikely );
77+ if (info == .comptime_float ) unreachable ;
78+
8079 // pow(-1, inf) = 1 for all x
8180 if (x == -1 ) {
8281 return 1.0 ;
@@ -94,6 +93,9 @@ pub fn pow(comptime T: type, x: T, y: T) T {
9493 }
9594
9695 if (math .isInf (x )) {
96+ @branchHint (.unlikely );
97+ if (info == .comptime_float ) unreachable ;
98+
9799 if (math .isNegativeInf (x )) {
98100 return pow (T , 1 / x , - y );
99101 }
@@ -145,7 +147,12 @@ pub fn pow(comptime T: type, x: T, y: T) T {
145147 var xe = r2 .exponent ;
146148 var x1 = r2 .significand ;
147149
148- var i = @as (std .meta .Int (.signed , @typeInfo (T ).float .bits ), @intFromFloat (yi ));
150+ const Int = switch (info ) {
151+ .float = > | float | std .meta .Int (.signed , float .bits ),
152+ .comptime_float = > i128 ,
153+ else = > @compileError ("pow not implemented for " ++ @typeName (T )),
154+ };
155+ var i = @as (Int , @intFromFloat (yi ));
149156 while (i != 0 ) : (i >>= 1 ) {
150157 const overflow_shift = math .floatExponentBits (T ) + 1 ;
151158 if (xe < - (1 << overflow_shift ) or (1 << overflow_shift ) < xe ) {
@@ -178,25 +185,37 @@ pub fn pow(comptime T: type, x: T, y: T) T {
178185 return math .scalbn (a1 , ae );
179186}
180187
181- fn isOddInteger (x : f64 ) bool {
182- if (@abs (x ) >= 1 << 53 ) {
188+ fn isOddInteger (comptime T : type , x : T ) bool {
189+ // standard IEEE floats have an implicit 0.m or 1.m integer part
190+ // so the digits is the number of fractional bits + 1
191+ const digits = math .floatFractionalBits (T ) + 1 ;
192+ if (@abs (x ) >= digits ) {
183193 // From https://golang.org/src/math/pow.go
184- // 1 << 53 is the largest exact integer in the float64 format.
194+ // 1 << digits is the largest exact integer in the IEEE float format fN .
185195 // Any number outside this range will be truncated before the decimal point and therefore will always be
186196 // an even integer.
187- // Without this check and if x overflows i64 the @intFromFloat(r.ipart) conversion below will panic
197+ // Without this check and if x overflows iN the @intFromFloat(r.ipart) conversion below will panic
188198 return false ;
189199 }
190200 const r = math .modf (x );
191- return r .fpart == 0.0 and @as (i64 , @intFromFloat (r .ipart )) & 1 == 1 ;
201+
202+ const Int = switch (@typeInfo (T )) {
203+ .float = > | float | std .meta .Int (.signed , float .bits ),
204+ .comptime_float = > i128 ,
205+ else = > unreachable ,
206+ };
207+ const ipart : Int = @intFromFloat (r .ipart );
208+ return r .fpart == 0.0 and ipart & 1 == 1 ;
192209}
193210
194211test isOddInteger {
195- try expect (isOddInteger (@floatFromInt (math .maxInt (i64 ) * 2 )) == false );
196- try expect (isOddInteger (@floatFromInt (math .maxInt (i64 ) * 2 + 1 )) == false );
197- try expect (isOddInteger (1 << 53 ) == false );
198- try expect (isOddInteger (12.0 ) == false );
199- try expect (isOddInteger (15.0 ) == true );
212+ try expect (isOddInteger (f128 , @floatFromInt (math .maxInt (i64 ) * 2 )) == false );
213+ try expect (isOddInteger (comptime_float , @floatFromInt (math .maxInt (i64 ) * 2 + 1 )) == false );
214+ try expect (isOddInteger (f64 , 1 << 53 ) == false );
215+ try expect (isOddInteger (f80 , 12.0 ) == false );
216+ try expect (isOddInteger (f80 , 15.0 ) == true );
217+ try expect (isOddInteger (f32 , 5.0 ) == true );
218+ try expect (isOddInteger (f16 , -1.0 ) == true );
200219}
201220
202221test pow {
0 commit comments