mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
stage2: fix comptime fixed-width float division
This commit is contained in:
parent
615a983517
commit
60c2972c5d
@ -324,25 +324,42 @@ inline fn generic_fmod(comptime T: type, x: T, y: T) T {
|
||||
return @bitCast(T, ux);
|
||||
}
|
||||
|
||||
test "fmod, fmodf" {
|
||||
inline for ([_]type{ f32, f64 }) |T| {
|
||||
const nan_val = math.nan(T);
|
||||
const inf_val = math.inf(T);
|
||||
test "fmodf" {
|
||||
const nan_val = math.nan(f32);
|
||||
const inf_val = math.inf(f32);
|
||||
|
||||
try std.testing.expect(math.isNan(generic_fmod(T, nan_val, 1.0)));
|
||||
try std.testing.expect(math.isNan(generic_fmod(T, 1.0, nan_val)));
|
||||
try std.testing.expect(math.isNan(generic_fmod(T, inf_val, 1.0)));
|
||||
try std.testing.expect(math.isNan(generic_fmod(T, 0.0, 0.0)));
|
||||
try std.testing.expect(math.isNan(generic_fmod(T, 1.0, 0.0)));
|
||||
try std.testing.expect(math.isNan(fmodf(nan_val, 1.0)));
|
||||
try std.testing.expect(math.isNan(fmodf(1.0, nan_val)));
|
||||
try std.testing.expect(math.isNan(fmodf(inf_val, 1.0)));
|
||||
try std.testing.expect(math.isNan(fmodf(0.0, 0.0)));
|
||||
try std.testing.expect(math.isNan(fmodf(1.0, 0.0)));
|
||||
|
||||
try std.testing.expectEqual(@as(T, 0.0), generic_fmod(T, 0.0, 2.0));
|
||||
try std.testing.expectEqual(@as(T, -0.0), generic_fmod(T, -0.0, 2.0));
|
||||
try std.testing.expectEqual(@as(f32, 0.0), fmodf(0.0, 2.0));
|
||||
try std.testing.expectEqual(@as(f32, -0.0), fmodf(-0.0, 2.0));
|
||||
|
||||
try std.testing.expectEqual(@as(T, -2.0), generic_fmod(T, -32.0, 10.0));
|
||||
try std.testing.expectEqual(@as(T, -2.0), generic_fmod(T, -32.0, -10.0));
|
||||
try std.testing.expectEqual(@as(T, 2.0), generic_fmod(T, 32.0, 10.0));
|
||||
try std.testing.expectEqual(@as(T, 2.0), generic_fmod(T, 32.0, -10.0));
|
||||
}
|
||||
try std.testing.expectEqual(@as(f32, -2.0), fmodf(-32.0, 10.0));
|
||||
try std.testing.expectEqual(@as(f32, -2.0), fmodf(-32.0, -10.0));
|
||||
try std.testing.expectEqual(@as(f32, 2.0), fmodf(32.0, 10.0));
|
||||
try std.testing.expectEqual(@as(f32, 2.0), fmodf(32.0, -10.0));
|
||||
}
|
||||
|
||||
test "fmod" {
|
||||
const nan_val = math.nan(f64);
|
||||
const inf_val = math.inf(f64);
|
||||
|
||||
try std.testing.expect(math.isNan(fmod(nan_val, 1.0)));
|
||||
try std.testing.expect(math.isNan(fmod(1.0, nan_val)));
|
||||
try std.testing.expect(math.isNan(fmod(inf_val, 1.0)));
|
||||
try std.testing.expect(math.isNan(fmod(0.0, 0.0)));
|
||||
try std.testing.expect(math.isNan(fmod(1.0, 0.0)));
|
||||
|
||||
try std.testing.expectEqual(@as(f64, 0.0), fmod(0.0, 2.0));
|
||||
try std.testing.expectEqual(@as(f64, -0.0), fmod(-0.0, 2.0));
|
||||
|
||||
try std.testing.expectEqual(@as(f64, -2.0), fmod(-32.0, 10.0));
|
||||
try std.testing.expectEqual(@as(f64, -2.0), fmod(-32.0, -10.0));
|
||||
try std.testing.expectEqual(@as(f64, 2.0), fmod(32.0, 10.0));
|
||||
try std.testing.expectEqual(@as(f64, 2.0), fmod(32.0, -10.0));
|
||||
}
|
||||
|
||||
test {
|
||||
|
||||
44
src/Sema.zig
44
src/Sema.zig
@ -9847,25 +9847,37 @@ fn analyzeArithmetic(
|
||||
// TODO: emit runtime safety for division by zero
|
||||
//
|
||||
// For floats:
|
||||
// If the rhs is zero, compile error for division by zero.
|
||||
// If the rhs is undefined, compile error because there is a possible
|
||||
// value (zero) for which the division would be illegal behavior.
|
||||
// If the rhs is zero:
|
||||
// * comptime_float: compile error for division by zero.
|
||||
// * other float type:
|
||||
// * if the lhs is zero: QNaN
|
||||
// * otherwise: +Inf or -Inf depending on lhs sign
|
||||
// If the rhs is undefined:
|
||||
// * comptime_float: compile error because there is a possible
|
||||
// value (zero) for which the division would be illegal behavior.
|
||||
// * other float type: result is undefined
|
||||
// If the lhs is undefined, result is undefined.
|
||||
if (maybe_lhs_val) |lhs_val| {
|
||||
if (!lhs_val.isUndef()) {
|
||||
if (lhs_val.compareWithZero(.eq)) {
|
||||
return sema.addConstant(resolved_type, Value.zero);
|
||||
switch (scalar_tag) {
|
||||
.Int, .ComptimeInt, .ComptimeFloat => {
|
||||
if (maybe_lhs_val) |lhs_val| {
|
||||
if (!lhs_val.isUndef()) {
|
||||
if (lhs_val.compareWithZero(.eq)) {
|
||||
return sema.addConstant(resolved_type, Value.zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (maybe_rhs_val) |rhs_val| {
|
||||
if (rhs_val.isUndef()) {
|
||||
return sema.failWithUseOfUndef(block, rhs_src);
|
||||
}
|
||||
if (rhs_val.compareWithZero(.eq)) {
|
||||
return sema.failWithDivideByZero(block, rhs_src);
|
||||
}
|
||||
if (maybe_rhs_val) |rhs_val| {
|
||||
if (rhs_val.isUndef()) {
|
||||
return sema.failWithUseOfUndef(block, rhs_src);
|
||||
}
|
||||
if (rhs_val.compareWithZero(.eq)) {
|
||||
return sema.failWithDivideByZero(block, rhs_src);
|
||||
}
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
if (maybe_lhs_val) |lhs_val| {
|
||||
if (lhs_val.isUndef()) {
|
||||
if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
|
||||
|
||||
@ -687,3 +687,24 @@ test "f128 at compile time is lossy" {
|
||||
|
||||
try expect(@as(f128, 10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0);
|
||||
}
|
||||
|
||||
test "comptime fixed-width float zero divided by zero produces NaN" {
|
||||
inline for (.{ f16, f32, f64, f80, f128 }) |F| {
|
||||
try expect(math.isNan(@as(F, 0) / @as(F, 0)));
|
||||
}
|
||||
}
|
||||
|
||||
test "comptime fixed-width float non-zero divided by zero produces signed Inf" {
|
||||
inline for (.{ f16, f32, f64, f80, f128 }) |F| {
|
||||
const pos = @as(F, 1) / @as(F, 0);
|
||||
const neg = @as(F, -1) / @as(F, 0);
|
||||
try expect(math.isInf(pos));
|
||||
try expect(math.isInf(neg));
|
||||
try expect(pos > 0);
|
||||
try expect(neg < 0);
|
||||
}
|
||||
}
|
||||
|
||||
test "comptime_float zero divided by zero produces zero" {
|
||||
try expect((0.0 / 0.0) == 0.0);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user