aboutsummaryrefslogtreecommitdiff
path: root/src/value.zig
diff options
context:
space:
mode:
authorZen1th <39484230+zenith391@users.noreply.github.com>2021-11-10 00:52:30 +0100
committerGitHub <noreply@github.com>2021-11-09 18:52:30 -0500
commit0d7359ca9b7e1c88d62ce3ecc6542584fe5df489 (patch)
tree259335fd862ce44db56c716e5de3080e26cbe80a /src/value.zig
parentc77698d69ea5c3e09b1b9404f634e512627ad321 (diff)
downloadzig-0d7359ca9b7e1c88d62ce3ecc6542584fe5df489.tar.gz
zig-0d7359ca9b7e1c88d62ce3ecc6542584fe5df489.zip
stage2: Implement Sema.floatToInt (#10097)
Diffstat (limited to 'src/value.zig')
-rw-r--r--src/value.zig46
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,