aboutsummaryrefslogtreecommitdiff
path: root/src/Sema
diff options
context:
space:
mode:
authorJacob Young <jacobly0@users.noreply.github.com>2025-06-14 14:32:11 -0400
committerJacob Young <jacobly0@users.noreply.github.com>2025-06-15 14:15:18 -0400
commit6b41beb370ce62b4381396e0543e6eb7f70b18cf (patch)
tree62ab8274799668635dc2f2fe236f081aea731eef /src/Sema
parent13392ad33f25649159048757d54fd6d8cf6d1887 (diff)
downloadzig-6b41beb370ce62b4381396e0543e6eb7f70b18cf.tar.gz
zig-6b41beb370ce62b4381396e0543e6eb7f70b18cf.zip
big.int: implement float conversions
These conversion routines accept a `round` argument to control how the result is rounded and return whether the result is exact. Most callers wanted this functionality and had hacks around it being missing. Also delete `std.math.big.rational` because it was only being used for float conversion, and using rationals for that is a lot more complex than necessary. It also required an allocator, whereas the new integer routines only need to be passed enough memory to store the result.
Diffstat (limited to 'src/Sema')
-rw-r--r--src/Sema/LowerZon.zig31
1 files changed, 12 insertions, 19 deletions
diff --git a/src/Sema/LowerZon.zig b/src/Sema/LowerZon.zig
index 8dfb710ac0..9bd876082f 100644
--- a/src/Sema/LowerZon.zig
+++ b/src/Sema/LowerZon.zig
@@ -509,30 +509,23 @@ fn lowerInt(
},
},
.float_literal => |val| {
- // Check for fractional components
- if (@rem(val, 1) != 0) {
- return self.fail(
+ var big_int: std.math.big.int.Mutable = .{
+ .limbs = try self.sema.arena.alloc(std.math.big.Limb, std.math.big.int.calcLimbLen(val)),
+ .len = undefined,
+ .positive = undefined,
+ };
+ switch (big_int.setFloat(val, .trunc)) {
+ .inexact => return self.fail(
node,
"fractional component prevents float value '{}' from coercion to type '{}'",
.{ val, res_ty.fmt(self.sema.pt) },
- );
+ ),
+ .exact => {},
}
- // Create a rational representation of the float
- var rational = try std.math.big.Rational.init(self.sema.arena);
- rational.setFloat(f128, val) 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().eqlAbs(big_one));
-
// Check that the result is in range of the result type
const int_info = res_ty.intInfo(self.sema.pt.zcu);
- if (!rational.p.fitsInTwosComp(int_info.signedness, int_info.bits)) {
+ if (!big_int.toConst().fitsInTwosComp(int_info.signedness, int_info.bits)) {
return self.fail(
node,
"type '{}' cannot represent integer value '{}'",
@@ -543,7 +536,7 @@ fn lowerInt(
return self.sema.pt.intern(.{
.int = .{
.ty = res_ty.toIntern(),
- .storage = .{ .big_int = rational.p.toConst() },
+ .storage = .{ .big_int = big_int.toConst() },
},
});
},
@@ -584,7 +577,7 @@ fn lowerFloat(
const value = switch (node.get(self.file.zoir.?)) {
.int_literal => |int| switch (int) {
.small => |val| try self.sema.pt.floatValue(res_ty, @as(f128, @floatFromInt(val))),
- .big => |val| try self.sema.pt.floatValue(res_ty, val.toFloat(f128)),
+ .big => |val| try self.sema.pt.floatValue(res_ty, val.toFloat(f128, .nearest_even)[0]),
},
.float_literal => |val| try self.sema.pt.floatValue(res_ty, val),
.char_literal => |val| try self.sema.pt.floatValue(res_ty, @as(f128, @floatFromInt(val))),