aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-10-21 19:05:26 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-10-21 19:05:26 -0700
commit7f70c27e9d57c8234545120da81861e2cfb354b5 (patch)
tree47948dcf37e5e5767db2b428a8ef8177ef8eee86 /lib/std
parenta3c9bfef301e0a4675fcea57356653334e07df45 (diff)
downloadzig-7f70c27e9d57c8234545120da81861e2cfb354b5.tar.gz
zig-7f70c27e9d57c8234545120da81861e2cfb354b5.zip
stage2: more division support
AIR: * div is renamed to div_trunc. * Add div_float, div_floor, div_exact. - Implemented in Sema and LLVM codegen. C backend has a stub. Improvements to std.math.big.Int: * Add `eqZero` function to `Mutable`. * Fix incorrect results for `divFloor`. Compiler-rt: * Add muloti4 to the stage2 section.
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/math/big/int.zig18
-rw-r--r--lib/std/math/big/int_test.zig57
-rw-r--r--lib/std/special/compiler_rt.zig9
3 files changed, 75 insertions, 9 deletions
diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig
index 68a0c7f740..7bcd76b221 100644
--- a/lib/std/math/big/int.zig
+++ b/lib/std/math/big/int.zig
@@ -135,6 +135,11 @@ pub const Mutable = struct {
};
}
+ /// Returns true if `a == 0`.
+ pub fn eqZero(self: Mutable) bool {
+ return self.toConst().eqZero();
+ }
+
/// Asserts that the allocator owns the limbs memory. If this is not the case,
/// use `toConst().toManaged()`.
pub fn toManaged(self: Mutable, allocator: *Allocator) Managed {
@@ -773,12 +778,15 @@ pub const Mutable = struct {
div(q, r, a, b, limbs_buffer, allocator);
// Trunc -> Floor.
- if (!q.positive) {
+ if (a.positive and b.positive) return;
+
+ if ((!q.positive or q.eqZero()) and !r.eqZero()) {
const one: Const = .{ .limbs = &[_]Limb{1}, .positive = true };
q.sub(q.toConst(), one);
- r.add(q.toConst(), one);
}
- r.positive = b.positive;
+
+ r.mulNoAlias(q.toConst(), b, allocator);
+ r.sub(a, r.toConst());
}
/// q = a / b (rem r)
@@ -1220,12 +1228,12 @@ pub const Mutable = struct {
var x: Mutable = .{
.limbs = x_limbs,
- .positive = a.positive,
+ .positive = true,
.len = a.limbs.len - ab_zero_limb_count,
};
var y: Mutable = .{
.limbs = y_limbs,
- .positive = b.positive,
+ .positive = true,
.len = b.limbs.len - ab_zero_limb_count,
};
diff --git a/lib/std/math/big/int_test.zig b/lib/std/math/big/int_test.zig
index 00594b640f..2ca7b253e0 100644
--- a/lib/std/math/big/int_test.zig
+++ b/lib/std/math/big/int_test.zig
@@ -1399,6 +1399,63 @@ test "big.int div floor single-single -/-" {
try testing.expect((try r.to(i32)) == er);
}
+test "big.int div floor no remainder negative quotient" {
+ const u: i32 = -0x80000000;
+ const v: i32 = 1;
+
+ var a = try Managed.initSet(testing.allocator, u);
+ defer a.deinit();
+ var b = try Managed.initSet(testing.allocator, v);
+ defer b.deinit();
+
+ var q = try Managed.init(testing.allocator);
+ defer q.deinit();
+ var r = try Managed.init(testing.allocator);
+ defer r.deinit();
+ try Managed.divFloor(&q, &r, a.toConst(), b.toConst());
+
+ try testing.expect((try q.to(i32)) == -0x80000000);
+ try testing.expect((try r.to(i32)) == 0);
+}
+
+test "big.int div floor negative close to zero" {
+ const u: i32 = -2;
+ const v: i32 = 12;
+
+ var a = try Managed.initSet(testing.allocator, u);
+ defer a.deinit();
+ var b = try Managed.initSet(testing.allocator, v);
+ defer b.deinit();
+
+ var q = try Managed.init(testing.allocator);
+ defer q.deinit();
+ var r = try Managed.init(testing.allocator);
+ defer r.deinit();
+ try Managed.divFloor(&q, &r, a.toConst(), b.toConst());
+
+ try testing.expect((try q.to(i32)) == -1);
+ try testing.expect((try r.to(i32)) == 10);
+}
+
+test "big.int div floor positive close to zero" {
+ const u: i32 = 10;
+ const v: i32 = 12;
+
+ var a = try Managed.initSet(testing.allocator, u);
+ defer a.deinit();
+ var b = try Managed.initSet(testing.allocator, v);
+ defer b.deinit();
+
+ var q = try Managed.init(testing.allocator);
+ defer q.deinit();
+ var r = try Managed.init(testing.allocator);
+ defer r.deinit();
+ try Managed.divFloor(&q, &r, a.toConst(), b.toConst());
+
+ try testing.expect((try q.to(i32)) == 0);
+ try testing.expect((try r.to(i32)) == 10);
+}
+
test "big.int div multi-multi with rem" {
var a = try Managed.initSet(testing.allocator, 0x8888999911110000ffffeeeeddddccccbbbbaaaa9999);
defer a.deinit();
diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig
index 3582b93070..caf43ded19 100644
--- a/lib/std/special/compiler_rt.zig
+++ b/lib/std/special/compiler_rt.zig
@@ -74,6 +74,11 @@ comptime {
@export(__getf2, .{ .name = "__gttf2", .linkage = linkage });
@export(__extendhfsf2, .{ .name = "__gnu_h2f_ieee", .linkage = linkage });
+
+ const __muloti4 = @import("compiler_rt/muloti4.zig").__muloti4;
+ @export(__muloti4, .{ .name = "__muloti4", .linkage = linkage });
+ const __mulodi4 = @import("compiler_rt/mulodi4.zig").__mulodi4;
+ @export(__mulodi4, .{ .name = "__mulodi4", .linkage = linkage });
}
if (!builtin.zig_is_stage2) {
@@ -621,10 +626,6 @@ comptime {
const __umodti3 = @import("compiler_rt/umodti3.zig").__umodti3;
@export(__umodti3, .{ .name = "__umodti3", .linkage = linkage });
}
- const __muloti4 = @import("compiler_rt/muloti4.zig").__muloti4;
- @export(__muloti4, .{ .name = "__muloti4", .linkage = linkage });
- const __mulodi4 = @import("compiler_rt/mulodi4.zig").__mulodi4;
- @export(__mulodi4, .{ .name = "__mulodi4", .linkage = linkage });
_ = @import("compiler_rt/atomics.zig");