authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-03-16 23:40:43+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-03-16 23:40:43+01:00
log2d237da50b38a242e31d95adee18b4e1dcfa67b7
treeb7a3f610fbea6d0bd1c0a5cf7a7b5ddae888d2e8
parent8a8e4a1f04da36258b322aee128f95b9010464c9
parente4985509520445e3fb7c765149863b4ce6121738

Merge pull request 'std.math.pow: fix wrong answer for large even exponents' (#31537) from TemariVirus/zig:master into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31537 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

1 files changed, 80 insertions(+), 33 deletions(-)

lib/std/math/pow.zig+80-33
......@@ -13,13 +13,13 @@ const expect = std.testing.expect;
1313/// - pow(x, +-0) = 1 for any x
1414/// - pow(1, y) = 1 for any y
1515/// - pow(x, 1) = x for any x
16/// - pow(nan, y) = nan
17/// - pow(x, nan) = nan
16/// - pow(nan, y) = nan for any y != 0
17/// - pow(x, nan) = nan for any x != 1
1818/// - pow(+-0, y) = +-inf for y an odd integer < 0
1919/// - pow(+-0, -inf) = +inf
2020/// - pow(+-0, +inf) = +0
2121/// - pow(+-0, y) = +inf for finite y < 0 and not an odd integer
22/// - pow(+-0, y) = +-0 for y an odd integer > 0
22/// - pow(+-0, y) = +-0 for finite y an odd integer > 0
2323/// - pow(+-0, y) = +0 for finite y > 0 and not an odd integer
2424/// - pow(-1, +-inf) = 1
2525/// - pow(x, +inf) = +inf for |x| > 1
......@@ -39,20 +39,20 @@ pub fn pow(comptime T: type, x: T, y: T) T {
3939 @compileError("pow not implemented for " ++ @typeName(T));
4040 }
4141
42 // pow(x, +-0) = 1 for all x
43 // pow(1, y) = 1 for all y
42 // pow(x, +-0) = 1 for any x
43 // pow(1, y) = 1 for any y
4444 if (y == 0 or x == 1) {
4545 return 1;
4646 }
4747
48 // pow(nan, y) = nan for all y
49 // pow(x, nan) = nan for all x
48 // pow(nan, y) = nan for any y != 0
49 // pow(x, nan) = nan for any x != 1
5050 if (math.isNan(x) or math.isNan(y)) {
5151 @branchHint(.unlikely);
5252 return math.nan(T);
5353 }
5454
55 // pow(x, 1) = x for all x
55 // pow(x, 1) = x for any x
5656 if (y == 1) {
5757 return x;
5858 }
......@@ -77,7 +77,7 @@ pub fn pow(comptime T: type, x: T, y: T) T {
7777 }
7878
7979 if (math.isInf(y)) {
80 // pow(-1, inf) = 1 for all x
80 // pow(-1, inf) = 1
8181 if (x == -1) {
8282 return 1.0;
8383 }
......@@ -124,7 +124,9 @@ pub fn pow(comptime T: type, x: T, y: T) T {
124124 return math.nan(T);
125125 }
126126 if (yi >= 1 << (@typeInfo(T).float.bits - 1)) {
127 return @exp(y * @log(x));
127 // yi is a large even int, so the result is always positive
128 // and the sign of x doesn't matter
129 return @exp(y * @log(@abs(x)));
128130 }
129131
130132 // a = a1 * 2^ae
......@@ -208,6 +210,7 @@ test pow {
208210 try expect(math.approxEqAbs(f32, pow(f32, 1.5, 3.3), 3.811546, epsilon));
209211 try expect(math.approxEqAbs(f32, pow(f32, 37.45, 3.3), 155736.703125, epsilon));
210212 try expect(math.approxEqAbs(f32, pow(f32, 89.123, 3.3), 2722489.5, epsilon));
213 try expect(math.approxEqAbs(f32, pow(f32, -1.0, 1e10), 1.0, epsilon));
211214
212215 try expect(math.approxEqAbs(f64, pow(f64, 0.0, 3.3), 0.0, epsilon));
213216 try expect(math.approxEqAbs(f64, pow(f64, 0.8923, 3.3), 0.686572, epsilon));
......@@ -215,48 +218,90 @@ test pow {
215218 try expect(math.approxEqAbs(f64, pow(f64, 1.5, 3.3), 3.811546, epsilon));
216219 try expect(math.approxEqAbs(f64, pow(f64, 37.45, 3.3), 155736.7160616, epsilon));
217220 try expect(math.approxEqAbs(f64, pow(f64, 89.123, 3.3), 2722490.231436, epsilon));
221 try expect(math.approxEqAbs(f64, pow(f64, -1.0, 1e20), 1.0, epsilon));
218222}
219223
220224test "special" {
221 const epsilon = 0.000001;
222
225 // pow(x, +-0) = 1 for any x
223226 try expect(pow(f32, 4, 0.0) == 1.0);
224227 try expect(pow(f32, 7, -0.0) == 1.0);
228 try expect(pow(f32, math.nan(f32), -0.0) == 1.0);
229 // pow(1, y) = 1 for any y
230 try expect(pow(f32, 1.0, 4) == 1.0);
231 try expect(pow(f32, 1.0, 7) == 1.0);
232 try expect(pow(f32, 1.0, -math.inf(f32)) == 1.0);
233 try expect(pow(f32, 1.0, math.nan(f32)) == 1.0);
234 // pow(x, 1) = x for any x
225235 try expect(pow(f32, 45, 1.0) == 45);
226236 try expect(pow(f32, -45, 1.0) == -45);
237 try expect(math.isPositiveZero(pow(f32, 0.0, 1.0)));
238 try expect(math.isNegativeZero(pow(f32, -0.0, 1.0)));
239 try expect(math.isPositiveInf(pow(f32, math.inf(f32), 1.0)));
240 try expect(math.isNan(pow(f32, math.nan(f32), 1.0)));
241 // pow(nan, y) = nan for any y != 0
227242 try expect(math.isNan(pow(f32, math.nan(f32), 5.0)));
228 try expect(math.isPositiveInf(pow(f32, -math.inf(f32), 0.5)));
229 try expect(math.isPositiveInf(pow(f32, -0.0, -0.5)));
230 try expect(pow(f32, -0.0, 0.5) == 0);
243 // pow(x, nan) = nan for any x != 1
231244 try expect(math.isNan(pow(f32, 5.0, math.nan(f32))));
245 // pow(+-0, y) = +-inf for y an odd integer < 0
232246 try expect(math.isPositiveInf(pow(f32, 0.0, -1.0)));
233 //expect(math.isNegativeInf(pow(f32, -0.0, -3.0))); TODO is this required?
247 try expect(math.isNegativeInf(pow(f32, -0.0, -5.0)));
248 // pow(+-0, -inf) = +inf
234249 try expect(math.isPositiveInf(pow(f32, 0.0, -math.inf(f32))));
235250 try expect(math.isPositiveInf(pow(f32, -0.0, -math.inf(f32))));
236 try expect(pow(f32, 0.0, math.inf(f32)) == 0.0);
237 try expect(pow(f32, -0.0, math.inf(f32)) == 0.0);
251 // pow(+-0, +inf) = +0
252 try expect(math.isPositiveZero(pow(f32, 0.0, math.inf(f32))));
253 try expect(math.isPositiveZero(pow(f32, -0.0, math.inf(f32))));
254 // pow(+-0, y) = +inf for finite y < 0 and not an odd integer
238255 try expect(math.isPositiveInf(pow(f32, 0.0, -2.0)));
239256 try expect(math.isPositiveInf(pow(f32, -0.0, -2.0)));
240 try expect(pow(f32, 0.0, 1.0) == 0.0);
241 try expect(pow(f32, -0.0, 1.0) == -0.0);
242 try expect(pow(f32, 0.0, 2.0) == 0.0);
243 try expect(pow(f32, -0.0, 2.0) == 0.0);
244 try expect(math.approxEqAbs(f32, pow(f32, -1.0, math.inf(f32)), 1.0, epsilon));
245 try expect(math.approxEqAbs(f32, pow(f32, -1.0, -math.inf(f32)), 1.0, epsilon));
257 try expect(math.isPositiveInf(pow(f32, 0.0, -5.2)));
258 try expect(math.isPositiveInf(pow(f32, -0.0, -0.5)));
259 // pow(+-0, y) = +-0 for finite y an odd integer > 0
260 try expect(math.isPositiveZero(pow(f32, 0.0, 3.0)));
261 try expect(math.isNegativeZero(pow(f32, -0.0, 5.0)));
262 // pow(+-0, y) = +0 for finite y > 0 and not an odd integer
263 try expect(math.isPositiveZero(pow(f32, 0.0, 2.0)));
264 try expect(math.isPositiveZero(pow(f32, -0.0, 2.0)));
265 try expect(math.isPositiveZero(pow(f32, 0.0, 5.2)));
266 try expect(math.isPositiveZero(pow(f32, -0.0, 0.5)));
267 // pow(-1, +-inf) = 1
268 try expect(pow(f32, -1.0, math.inf(f32)) == 1.0);
269 try expect(pow(f32, -1.0, -math.inf(f32)) == 1.0);
270 // pow(x, +inf) = +inf for |x| > 1
246271 try expect(math.isPositiveInf(pow(f32, 1.2, math.inf(f32))));
247272 try expect(math.isPositiveInf(pow(f32, -1.2, math.inf(f32))));
248 try expect(pow(f32, 1.2, -math.inf(f32)) == 0.0);
249 try expect(pow(f32, -1.2, -math.inf(f32)) == 0.0);
250 try expect(pow(f32, 0.2, math.inf(f32)) == 0.0);
251 try expect(pow(f32, -0.2, math.inf(f32)) == 0.0);
273 // pow(x, -inf) = +0 for |x| > 1
274 try expect(math.isPositiveZero(pow(f32, 1.2, -math.inf(f32))));
275 try expect(math.isPositiveZero(pow(f32, -1.2, -math.inf(f32))));
276 // pow(x, +inf) = +0 for |x| < 1
277 try expect(math.isPositiveZero(pow(f32, 0.2, math.inf(f32))));
278 try expect(math.isPositiveZero(pow(f32, -0.2, math.inf(f32))));
279 // pow(x, -inf) = +inf for |x| < 1
252280 try expect(math.isPositiveInf(pow(f32, 0.2, -math.inf(f32))));
253281 try expect(math.isPositiveInf(pow(f32, -0.2, -math.inf(f32))));
254 try expect(math.isPositiveInf(pow(f32, math.inf(f32), 1.0)));
255 try expect(pow(f32, math.inf(f32), -1.0) == 0.0);
256 //expect(pow(f32, -math.inf(f32), 5.0) == pow(f32, -0.0, -5.0)); TODO support negative 0?
257 try expect(pow(f32, -math.inf(f32), -5.2) == pow(f32, -0.0, 5.2));
282 // pow(+inf, y) = +inf for y > 0
283 try expect(math.isPositiveInf(pow(f32, math.inf(f32), 2.0)));
284 try expect(math.isPositiveInf(pow(f32, math.inf(f32), 0.2)));
285 // pow(+inf, y) = +0 for y < 0
286 try expect(math.isPositiveZero(pow(f32, math.inf(f32), -2.0)));
287 try expect(math.isPositiveZero(pow(f32, math.inf(f32), -0.2)));
288 // pow(-inf, y) = -inf for y an odd integer > 0
289 try expect(math.isNegativeInf(pow(f32, -math.inf(f32), 5.0)));
290 // pow(-inf, +inf) = +inf
291 try expect(math.isPositiveInf(pow(f32, -math.inf(f32), math.inf(f32))));
292 // pow(-inf, -inf) = +0
293 try expect(math.isPositiveZero(pow(f32, -math.inf(f32), -math.inf(f32))));
294 // pow(-inf, y) = +inf for finite y > 0 and not an odd integer
295 try expect(math.isPositiveInf(pow(f32, -math.inf(f32), 4.0)));
296 try expect(math.isPositiveInf(pow(f32, -math.inf(f32), 0.5)));
297 // pow(-inf, y) = -0 for finite y an odd integer < 0
298 try expect(math.isNegativeZero(pow(f32, -math.inf(f32), -3.0)));
299 // pow(-inf, y) = +0 for finite y < 0 and not an odd integer
300 try expect(math.isPositiveZero(pow(f32, -math.inf(f32), -2.0)));
301 try expect(math.isPositiveZero(pow(f32, -math.inf(f32), -5.2)));
302 // pow(x, y) = nan for finite x < 0 and finite non-integer y
258303 try expect(math.isNan(pow(f32, -1.0, 1.2)));
259 try expect(math.isNan(pow(f32, -12.4, 78.5)));
304 try expect(math.isNan(pow(f32, -12.4, -78.5)));
260305}
261306
262307test "overflow" {
......@@ -265,4 +310,6 @@ test "overflow" {
265310 try expect(math.isNegativeInf(pow(f64, -2, (1 << 32) + 1)));
266311 try expect(pow(f64, 0.5, 1 << 45) == 0);
267312 try expect(math.isPositiveInf(pow(f64, 0.5, -(1 << 45))));
313 try expect(math.isPositiveInf(pow(f64, -2, 1 << 64)));
314 try expect(pow(f64, 0.5, 1 << 64) == 0);
268315}