authorgravatar for 40216616+hdert@users.noreply.github.comhdert <40216616+hdert@users.noreply.github.com> 2024-01-20 03:25:03+13:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-19 22:00:04-08:00
log314533c28bdb57f4cdc159fe376a10037e72d5f3
tree34c1992a436da19576e3ad71fedc4a7c60f30ad1
parent480a2f7f02f9dcb2e53f4515fc26fb72ad78ffd9

std/math/pow: Fix #18553, isOddInteger: Return false if float value is greater than 1 << 53 (see comment), add test cases


1 files changed, 16 insertions(+), 0 deletions(-)

lib/std/math/pow.zig+16
...@@ -178,10 +178,26 @@ pub fn pow(comptime T: type, x: T, y: T) T {...@@ -178,10 +178,26 @@ pub fn pow(comptime T: type, x: T, y: T) T {
178}178}
179179
180fn isOddInteger(x: f64) bool {180fn isOddInteger(x: f64) bool {
181 if (@abs(x) >= 1 << 53) {
182 // From https://golang.org/src/math/pow.go
183 // 1 << 53 is the largest exact integer in the float64 format.
184 // Any number outside this range will be truncated before the decimal point and therefore will always be
185 // an even integer.
186 // Without this check and if x overflows i64 the @intFromFloat(r.ipart) conversion below will panic
187 return false;
188 }
181 const r = math.modf(x);189 const r = math.modf(x);
182 return r.fpart == 0.0 and @as(i64, @intFromFloat(r.ipart)) & 1 == 1;190 return r.fpart == 0.0 and @as(i64, @intFromFloat(r.ipart)) & 1 == 1;
183}191}
184192
193test "math.pow.isOddInteger" {
194 try expect(isOddInteger(math.maxInt(i64) * 2) == false);
195 try expect(isOddInteger(math.maxInt(i64) * 2 + 1) == false);
196 try expect(isOddInteger(1 << 53) == false);
197 try expect(isOddInteger(12.0) == false);
198 try expect(isOddInteger(15.0) == true);
199}
200
185test "math.pow" {201test "math.pow" {
186 const epsilon = 0.000001;202 const epsilon = 0.000001;
187203