Skip to content

Commit 6f8fe98

Browse files
math: add f16, f80, f128, c_longdouble support to pow
Generalizes math.pow to accept f16, f80, and f128 types.
1 parent f01833e commit 6f8fe98

File tree

1 file changed

+37
-15
lines changed

1 file changed

+37
-15
lines changed

lib/std/math/pow.zig

+37-15
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ pub fn pow(comptime T: type, x: T, y: T) T {
3535
return math.powi(T, x, y) catch unreachable;
3636
}
3737

38-
if (T != f32 and T != f64) {
39-
@compileError("pow not implemented for " ++ @typeName(T));
38+
if (@typeInfo(T) == .comptime_float) {
39+
@compileError("pow not implemented for comptime_float");
4040
}
4141

4242
// pow(x, +-0) = 1 for all x
@@ -60,15 +60,15 @@ pub fn pow(comptime T: type, x: T, y: T) T {
6060
if (x == 0) {
6161
if (y < 0) {
6262
// pow(+-0, y) = +-inf for y an odd integer
63-
if (isOddInteger(y)) {
63+
if (isOddInteger(T, y)) {
6464
return math.copysign(math.inf(T), x);
6565
}
6666
// pow(+-0, y) = +inf for y an even integer
6767
else {
6868
return math.inf(T);
6969
}
7070
} else {
71-
if (isOddInteger(y)) {
71+
if (isOddInteger(T, y)) {
7272
return x;
7373
} else {
7474
return 0;
@@ -178,29 +178,37 @@ pub fn pow(comptime T: type, x: T, y: T) T {
178178
return math.scalbn(a1, ae);
179179
}
180180

181-
fn isOddInteger(x: f64) bool {
182-
if (@abs(x) >= 1 << 53) {
183-
// From https://golang.org/src/math/pow.go
184-
// 1 << 53 is the largest exact integer in the float64 format.
181+
fn isOddInteger(comptime T: type, x: T) bool {
182+
if (@abs(x) >= 1 << (math.floatFractionalBits(T) + 1)) {
183+
// From https://golang.org/src/math/pow.go (adapted for generic type T)
184+
// 1 << (floatFractionalBits(T) + 1) is the largest exact integer in the floating point format.
185185
// Any number outside this range will be truncated before the decimal point and therefore will always be
186186
// an even integer.
187-
// Without this check and if x overflows i64 the @intFromFloat(r.ipart) conversion below will panic
187+
// Without this check and if x overflows i128 the @intFromFloat(r.ipart) conversion below will panic
188188
return false;
189189
}
190190
const r = math.modf(x);
191-
return r.fpart == 0.0 and @as(i64, @intFromFloat(r.ipart)) & 1 == 1;
191+
return r.fpart == 0.0 and @as(i128, @intFromFloat(r.ipart)) & 1 == 1;
192192
}
193193

194194
test isOddInteger {
195-
try expect(isOddInteger(math.maxInt(i64) * 2) == false);
196-
try expect(isOddInteger(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);
195+
try expect(isOddInteger(f64, math.maxInt(i64) * 2) == false);
196+
try expect(isOddInteger(f64, math.maxInt(i64) * 2 + 1) == false);
197+
try expect(isOddInteger(f64, 1 << 53) == false);
198+
try expect(isOddInteger(f64, 12.0) == false);
199+
try expect(isOddInteger(f64, 15.0) == true);
200200
}
201201

202202
test pow {
203203
const epsilon = 0.000001;
204+
const epsilon16 = 0.01;
205+
206+
try expect(math.approxEqAbs(f16, pow(f16, 0.0, 3.3), 0.0, epsilon16));
207+
try expect(math.approxEqAbs(f16, pow(f16, 0.8923, 3.3), 0.686572, epsilon16));
208+
try expect(math.approxEqAbs(f16, pow(f16, 0.2, 3.3), 0.004936, epsilon16));
209+
try expect(math.approxEqAbs(f16, pow(f16, 1.5, 3.3), 3.811546, epsilon16));
210+
try expect(math.approxEqAbs(f16, pow(f16, 37.45, 3.3), 155736.7160616, epsilon16));
211+
try expect(math.approxEqAbs(f16, pow(f16, 89.123, 3.3), 2722490.231436, epsilon16));
204212

205213
try expect(math.approxEqAbs(f32, pow(f32, 0.0, 3.3), 0.0, epsilon));
206214
try expect(math.approxEqAbs(f32, pow(f32, 0.8923, 3.3), 0.686572, epsilon));
@@ -215,6 +223,20 @@ test pow {
215223
try expect(math.approxEqAbs(f64, pow(f64, 1.5, 3.3), 3.811546, epsilon));
216224
try expect(math.approxEqAbs(f64, pow(f64, 37.45, 3.3), 155736.7160616, epsilon));
217225
try expect(math.approxEqAbs(f64, pow(f64, 89.123, 3.3), 2722490.231436, epsilon));
226+
227+
try expect(math.approxEqAbs(f80, pow(f80, 0.0, 3.3), 0.0, epsilon));
228+
try expect(math.approxEqAbs(f80, pow(f80, 0.8923, 3.3), 0.686572, epsilon));
229+
try expect(math.approxEqAbs(f80, pow(f80, 0.2, 3.3), 0.004936, epsilon));
230+
try expect(math.approxEqAbs(f80, pow(f80, 1.5, 3.3), 3.811546, epsilon));
231+
try expect(math.approxEqAbs(f80, pow(f80, 37.45, 3.3), 155736.7160616, epsilon));
232+
try expect(math.approxEqAbs(f80, pow(f80, 89.123, 3.3), 2722490.231436, epsilon));
233+
234+
try expect(math.approxEqAbs(f128, pow(f128, 0.0, 3.3), 0.0, epsilon));
235+
try expect(math.approxEqAbs(f128, pow(f128, 0.8923, 3.3), 0.686572, epsilon));
236+
try expect(math.approxEqAbs(f128, pow(f128, 0.2, 3.3), 0.004936, epsilon));
237+
try expect(math.approxEqAbs(f128, pow(f128, 1.5, 3.3), 3.811546, epsilon));
238+
try expect(math.approxEqAbs(f128, pow(f128, 37.45, 3.3), 155736.7160616, epsilon));
239+
try expect(math.approxEqAbs(f128, pow(f128, 89.123, 3.3), 2722490.231436, epsilon));
218240
}
219241

220242
test "special" {

0 commit comments

Comments
 (0)