mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
Sema: add float128IntPartToBigInt to fix compare comptime float with int
This commit is contained in:
parent
3a9344d8fc
commit
d987bf859e
66
src/Sema.zig
66
src/Sema.zig
@ -27673,6 +27673,14 @@ fn cmpNumeric(
|
||||
if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
|
||||
if (lhs_val.isUndef())
|
||||
return sema.addConstUndef(Type.bool);
|
||||
if (lhs_val.isNan()) switch (op) {
|
||||
.neq => return Air.Inst.Ref.bool_true,
|
||||
else => return Air.Inst.Ref.bool_false,
|
||||
};
|
||||
if (lhs_val.isInf()) switch (op) {
|
||||
.gt, .neq => return Air.Inst.Ref.bool_true,
|
||||
.lt, .lte, .eq, .gte => return Air.Inst.Ref.bool_false,
|
||||
};
|
||||
if (!rhs_is_signed) {
|
||||
switch (lhs_val.orderAgainstZero()) {
|
||||
.gt => {},
|
||||
@ -27688,8 +27696,7 @@ fn cmpNumeric(
|
||||
}
|
||||
}
|
||||
if (lhs_is_float) {
|
||||
var bigint_space: Value.BigIntSpace = undefined;
|
||||
var bigint = try lhs_val.toBigInt(&bigint_space, target).toManaged(sema.gpa);
|
||||
var bigint = try float128IntPartToBigInt(sema.gpa, lhs_val.toFloat(f128));
|
||||
defer bigint.deinit();
|
||||
if (lhs_val.floatHasFraction()) {
|
||||
switch (op) {
|
||||
@ -27719,6 +27726,14 @@ fn cmpNumeric(
|
||||
if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
|
||||
if (rhs_val.isUndef())
|
||||
return sema.addConstUndef(Type.bool);
|
||||
if (rhs_val.isNan()) switch (op) {
|
||||
.neq => return Air.Inst.Ref.bool_true,
|
||||
else => return Air.Inst.Ref.bool_false,
|
||||
};
|
||||
if (rhs_val.isInf()) switch (op) {
|
||||
.lt, .neq => return Air.Inst.Ref.bool_true,
|
||||
.gt, .lte, .eq, .gte => return Air.Inst.Ref.bool_false,
|
||||
};
|
||||
if (!lhs_is_signed) {
|
||||
switch (rhs_val.orderAgainstZero()) {
|
||||
.gt => {},
|
||||
@ -27734,8 +27749,7 @@ fn cmpNumeric(
|
||||
}
|
||||
}
|
||||
if (rhs_is_float) {
|
||||
var bigint_space: Value.BigIntSpace = undefined;
|
||||
var bigint = try rhs_val.toBigInt(&bigint_space, target).toManaged(sema.gpa);
|
||||
var bigint = try float128IntPartToBigInt(sema.gpa, rhs_val.toFloat(f128));
|
||||
defer bigint.deinit();
|
||||
if (rhs_val.floatHasFraction()) {
|
||||
switch (op) {
|
||||
@ -31110,6 +31124,31 @@ fn floatToInt(
|
||||
return sema.floatToIntScalar(block, src, val, float_ty, int_ty);
|
||||
}
|
||||
|
||||
// float is expected to be finite and non-NaN
|
||||
fn float128IntPartToBigInt(
|
||||
arena: Allocator,
|
||||
float: f128,
|
||||
) !std.math.big.int.Managed {
|
||||
const is_negative = std.math.signbit(float);
|
||||
const floored = @floor(@fabs(float));
|
||||
|
||||
var rational = try std.math.big.Rational.init(arena);
|
||||
defer rational.q.deinit();
|
||||
rational.setFloat(f128, floored) catch |err| switch (err) {
|
||||
error.NonFiniteFloat => unreachable,
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
};
|
||||
|
||||
// The float is reduced in rational.setFloat, so we assert that denominator is equal to one
|
||||
const big_one = std.math.big.int.Const{ .limbs = &.{1}, .positive = true };
|
||||
assert(rational.q.toConst().eqAbs(big_one));
|
||||
|
||||
if (is_negative) {
|
||||
rational.negate();
|
||||
}
|
||||
return rational.p;
|
||||
}
|
||||
|
||||
fn floatToIntScalar(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
@ -31132,22 +31171,11 @@ fn floatToIntScalar(
|
||||
});
|
||||
}
|
||||
|
||||
const is_negative = std.math.signbit(float);
|
||||
const floored = @floor(@fabs(float));
|
||||
var big_int = try float128IntPartToBigInt(sema.arena, float);
|
||||
defer big_int.deinit();
|
||||
|
||||
var rational = try std.math.big.Rational.init(sema.arena);
|
||||
defer rational.deinit();
|
||||
rational.setFloat(f128, floored) catch |err| switch (err) {
|
||||
error.NonFiniteFloat => unreachable,
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
};
|
||||
|
||||
// The float is reduced in rational.setFloat, so we assert that denominator is equal to one
|
||||
const big_one = std.math.big.int.Const{ .limbs = &.{1}, .positive = true };
|
||||
assert(rational.q.toConst().eqAbs(big_one));
|
||||
|
||||
const result_limbs = try sema.arena.dupe(Limb, rational.p.toConst().limbs);
|
||||
const result = if (is_negative)
|
||||
const result_limbs = try sema.arena.dupe(Limb, big_int.toConst().limbs);
|
||||
const result = if (!big_int.isPositive())
|
||||
try Value.Tag.int_big_negative.create(sema.arena, result_limbs)
|
||||
else
|
||||
try Value.Tag.int_big_positive.create(sema.arena, result_limbs);
|
||||
|
||||
@ -1999,6 +1999,11 @@ pub const Value = extern union {
|
||||
}
|
||||
return true;
|
||||
},
|
||||
.float_16 => if (std.math.isNan(lhs.castTag(.float_16).?.data)) return op != .neq,
|
||||
.float_32 => if (std.math.isNan(lhs.castTag(.float_32).?.data)) return op != .neq,
|
||||
.float_64 => if (std.math.isNan(lhs.castTag(.float_64).?.data)) return op != .neq,
|
||||
.float_80 => if (std.math.isNan(lhs.castTag(.float_80).?.data)) return op != .neq,
|
||||
.float_128 => if (std.math.isNan(lhs.castTag(.float_128).?.data)) return op != .neq,
|
||||
else => {},
|
||||
}
|
||||
return (try orderAgainstZeroAdvanced(lhs, sema_kit)).compare(op);
|
||||
@ -3596,6 +3601,18 @@ pub const Value = extern union {
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns true if the value is a floating point type and is infinite. Returns false otherwise.
|
||||
pub fn isInf(val: Value) bool {
|
||||
return switch (val.tag()) {
|
||||
.float_16 => std.math.isInf(val.castTag(.float_16).?.data),
|
||||
.float_32 => std.math.isInf(val.castTag(.float_32).?.data),
|
||||
.float_64 => std.math.isInf(val.castTag(.float_64).?.data),
|
||||
.float_80 => std.math.isInf(val.castTag(.float_80).?.data),
|
||||
.float_128 => std.math.isInf(val.castTag(.float_128).?.data),
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn floatRem(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, target: Target) !Value {
|
||||
if (float_type.zigTypeTag() == .Vector) {
|
||||
const result_data = try arena.alloc(Value, float_type.vectorLen());
|
||||
|
||||
@ -96,6 +96,7 @@ test {
|
||||
_ = @import("behavior/bugs/12801-2.zig");
|
||||
_ = @import("behavior/bugs/12885.zig");
|
||||
_ = @import("behavior/bugs/12890.zig");
|
||||
_ = @import("behavior/bugs/12891.zig");
|
||||
_ = @import("behavior/bugs/12911.zig");
|
||||
_ = @import("behavior/bugs/12928.zig");
|
||||
_ = @import("behavior/bugs/12945.zig");
|
||||
|
||||
20
test/behavior/bugs/12891.zig
Normal file
20
test/behavior/bugs/12891.zig
Normal file
@ -0,0 +1,20 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
test "issue12891" {
|
||||
const f = 10.0;
|
||||
var i: usize = 0;
|
||||
try std.testing.expect(i < f);
|
||||
}
|
||||
test "nan" {
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
|
||||
const f = comptime std.math.nan(f64);
|
||||
var i: usize = 0;
|
||||
try std.testing.expect(!(f < i));
|
||||
}
|
||||
test "inf" {
|
||||
const f = comptime std.math.inf(f64);
|
||||
var i: usize = 0;
|
||||
try std.testing.expect(f > i);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user