diff options
| author | Jacob Young <jacobly0@users.noreply.github.com> | 2025-06-14 14:32:11 -0400 |
|---|---|---|
| committer | Jacob Young <jacobly0@users.noreply.github.com> | 2025-06-15 14:15:18 -0400 |
| commit | 6b41beb370ce62b4381396e0543e6eb7f70b18cf (patch) | |
| tree | 62ab8274799668635dc2f2fe236f081aea731eef /src/Sema | |
| parent | 13392ad33f25649159048757d54fd6d8cf6d1887 (diff) | |
| download | zig-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.zig | 31 |
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))), |
