diff options
| author | Zen1th <39484230+zenith391@users.noreply.github.com> | 2021-11-10 00:52:30 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-11-09 18:52:30 -0500 |
| commit | 0d7359ca9b7e1c88d62ce3ecc6542584fe5df489 (patch) | |
| tree | 259335fd862ce44db56c716e5de3080e26cbe80a /src/value.zig | |
| parent | c77698d69ea5c3e09b1b9404f634e512627ad321 (diff) | |
| download | zig-0d7359ca9b7e1c88d62ce3ecc6542584fe5df489.tar.gz zig-0d7359ca9b7e1c88d62ce3ecc6542584fe5df489.zip | |
stage2: Implement Sema.floatToInt (#10097)
Diffstat (limited to 'src/value.zig')
| -rw-r--r-- | src/value.zig | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/src/value.zig b/src/value.zig index 2e3f1bc4b8..4b571891f4 100644 --- a/src/value.zig +++ b/src/value.zig @@ -1929,6 +1929,52 @@ pub const Value = extern union { } } + pub fn floatToInt(val: Value, arena: *Allocator, dest_ty: Type, target: Target) error{ FloatCannotFit, OutOfMemory }!Value { + const Limb = std.math.big.Limb; + + var value = val.toFloat(f64); // TODO: f128 ? + if (std.math.isNan(value) or std.math.isInf(value)) { + return error.FloatCannotFit; + } + + const isNegative = std.math.signbit(value); + value = std.math.fabs(value); + + const floored = std.math.floor(value); + + var rational = try std.math.big.Rational.init(arena); + defer rational.deinit(); + rational.setFloat(f64, 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 bigOne = std.math.big.int.Const{ .limbs = &.{1}, .positive = true }; + assert(rational.q.toConst().eqAbs(bigOne)); + + const result_limbs = try arena.dupe(Limb, rational.p.toConst().limbs); + const result = if (isNegative) + try Value.Tag.int_big_negative.create(arena, result_limbs) + else + try Value.Tag.int_big_positive.create(arena, result_limbs); + + if (result.intFitsInType(dest_ty, target)) { + return result; + } else { + return error.FloatCannotFit; + } + } + + fn calcLimbLenFloat(scalar: anytype) usize { + if (scalar == 0) { + return 1; + } + + const w_value = std.math.fabs(scalar); + return @divFloor(@floatToInt(std.math.big.Limb, std.math.log2(w_value)), @typeInfo(std.math.big.Limb).Int.bits) + 1; + } + /// Supports both floats and ints; handles undefined. pub fn numberAddWrap( lhs: Value, |
