From 0d7359ca9b7e1c88d62ce3ecc6542584fe5df489 Mon Sep 17 00:00:00 2001 From: Zen1th <39484230+zenith391@users.noreply.github.com> Date: Wed, 10 Nov 2021 00:52:30 +0100 Subject: stage2: Implement Sema.floatToInt (#10097) --- src/value.zig | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'src/value.zig') 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, -- cgit v1.2.3