mirror of
https://github.com/ziglang/zig.git
synced 2026-02-20 00:08:56 +00:00
Use math.Order for comparing bigints instead of i8 (#4791)
This commit is contained in:
parent
dc44fe053c
commit
5acc8afb5f
@ -534,13 +534,14 @@ pub const Int = struct {
|
||||
return out_stream.writeAll(str);
|
||||
}
|
||||
|
||||
/// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.
|
||||
pub fn cmpAbs(a: Int, b: Int) i8 {
|
||||
/// Returns math.Order.lt, math.Order.eq, math.Order.gt if |a| < |b|, |a| ==
|
||||
/// |b| or |a| > |b| respectively.
|
||||
pub fn cmpAbs(a: Int, b: Int) math.Order {
|
||||
if (a.len() < b.len()) {
|
||||
return -1;
|
||||
return .lt;
|
||||
}
|
||||
if (a.len() > b.len()) {
|
||||
return 1;
|
||||
return .gt;
|
||||
}
|
||||
|
||||
var i: usize = a.len() - 1;
|
||||
@ -551,21 +552,26 @@ pub const Int = struct {
|
||||
}
|
||||
|
||||
if (a.limbs[i] < b.limbs[i]) {
|
||||
return -1;
|
||||
return .lt;
|
||||
} else if (a.limbs[i] > b.limbs[i]) {
|
||||
return 1;
|
||||
return .gt;
|
||||
} else {
|
||||
return 0;
|
||||
return .eq;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns -1, 0, 1 if a < b, a == b or a > b respectively.
|
||||
pub fn cmp(a: Int, b: Int) i8 {
|
||||
/// Returns math.Order.lt, math.Order.eq, math.Order.gt if a < b, a == b or a
|
||||
/// > b respectively.
|
||||
pub fn cmp(a: Int, b: Int) math.Order {
|
||||
if (a.isPositive() != b.isPositive()) {
|
||||
return if (a.isPositive()) @as(i8, 1) else -1;
|
||||
return if (a.isPositive()) .gt else .lt;
|
||||
} else {
|
||||
const r = cmpAbs(a, b);
|
||||
return if (a.isPositive()) r else -r;
|
||||
return if (a.isPositive()) r else switch (r) {
|
||||
.lt => math.Order.gt,
|
||||
.eq => math.Order.eq,
|
||||
.gt => math.Order.lt,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -576,12 +582,12 @@ pub const Int = struct {
|
||||
|
||||
/// Returns true if |a| == |b|.
|
||||
pub fn eqAbs(a: Int, b: Int) bool {
|
||||
return cmpAbs(a, b) == 0;
|
||||
return cmpAbs(a, b) == .eq;
|
||||
}
|
||||
|
||||
/// Returns true if a == b.
|
||||
pub fn eq(a: Int, b: Int) bool {
|
||||
return cmp(a, b) == 0;
|
||||
return cmp(a, b) == .eq;
|
||||
}
|
||||
|
||||
// Normalize a possible sequence of leading zeros.
|
||||
@ -694,7 +700,7 @@ pub const Int = struct {
|
||||
} else {
|
||||
if (a.isPositive()) {
|
||||
// (a) - (b) => a - b
|
||||
if (a.cmp(b) >= 0) {
|
||||
if (a.cmp(b) != .lt) {
|
||||
try r.ensureCapacity(a.len() + 1);
|
||||
llsub(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]);
|
||||
r.normalize(a.len());
|
||||
@ -707,7 +713,7 @@ pub const Int = struct {
|
||||
}
|
||||
} else {
|
||||
// (-a) - (-b) => -(a - b)
|
||||
if (a.cmp(b) < 0) {
|
||||
if (a.cmp(b) == .lt) {
|
||||
try r.ensureCapacity(a.len() + 1);
|
||||
llsub(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]);
|
||||
r.normalize(a.len());
|
||||
@ -1010,7 +1016,7 @@ pub const Int = struct {
|
||||
@panic("quo and rem cannot be same variable");
|
||||
}
|
||||
|
||||
if (a.cmpAbs(b) < 0) {
|
||||
if (a.cmpAbs(b) == .lt) {
|
||||
// quo may alias a so handle rem first
|
||||
try rem.copy(a);
|
||||
rem.setSign(a.isPositive() == b.isPositive());
|
||||
@ -1133,7 +1139,7 @@ pub const Int = struct {
|
||||
|
||||
// 2.
|
||||
try tmp.shiftLeft(y.*, Limb.bit_count * (n - t));
|
||||
while (x.cmp(tmp) >= 0) {
|
||||
while (x.cmp(tmp) != .lt) {
|
||||
q.limbs[n - t] += 1;
|
||||
try x.sub(x.*, tmp);
|
||||
}
|
||||
@ -1164,7 +1170,7 @@ pub const Int = struct {
|
||||
r.limbs[2] = carry;
|
||||
r.normalize(3);
|
||||
|
||||
if (r.cmpAbs(tmp) <= 0) {
|
||||
if (r.cmpAbs(tmp) != .gt) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1719,8 +1725,8 @@ test "big.int compare" {
|
||||
var b = try Int.initSet(testing.allocator, 10);
|
||||
defer b.deinit();
|
||||
|
||||
testing.expect(a.cmpAbs(b) == 1);
|
||||
testing.expect(a.cmp(b) == -1);
|
||||
testing.expect(a.cmpAbs(b) == .gt);
|
||||
testing.expect(a.cmp(b) == .lt);
|
||||
}
|
||||
|
||||
test "big.int compare similar" {
|
||||
@ -1729,8 +1735,8 @@ test "big.int compare similar" {
|
||||
var b = try Int.initSet(testing.allocator, 0xffffffffeeeeeeeeffffffffeeeeeeef);
|
||||
defer b.deinit();
|
||||
|
||||
testing.expect(a.cmpAbs(b) == -1);
|
||||
testing.expect(b.cmpAbs(a) == 1);
|
||||
testing.expect(a.cmpAbs(b) == .lt);
|
||||
testing.expect(b.cmpAbs(a) == .gt);
|
||||
}
|
||||
|
||||
test "big.int compare different limb size" {
|
||||
@ -1739,8 +1745,8 @@ test "big.int compare different limb size" {
|
||||
var b = try Int.initSet(testing.allocator, 1);
|
||||
defer b.deinit();
|
||||
|
||||
testing.expect(a.cmpAbs(b) == 1);
|
||||
testing.expect(b.cmpAbs(a) == -1);
|
||||
testing.expect(a.cmpAbs(b) == .gt);
|
||||
testing.expect(b.cmpAbs(a) == .lt);
|
||||
}
|
||||
|
||||
test "big.int compare multi-limb" {
|
||||
@ -1749,8 +1755,8 @@ test "big.int compare multi-limb" {
|
||||
var b = try Int.initSet(testing.allocator, 0x7777777799999999ffffeeeeffffeeeeffffeeeee);
|
||||
defer b.deinit();
|
||||
|
||||
testing.expect(a.cmpAbs(b) == 1);
|
||||
testing.expect(a.cmp(b) == -1);
|
||||
testing.expect(a.cmpAbs(b) == .gt);
|
||||
testing.expect(a.cmp(b) == .lt);
|
||||
}
|
||||
|
||||
test "big.int equality" {
|
||||
@ -2726,9 +2732,9 @@ test "big.int var args" {
|
||||
|
||||
const c = try Int.initSet(testing.allocator, 11);
|
||||
defer c.deinit();
|
||||
testing.expect(a.cmp(c) == 0);
|
||||
testing.expect(a.cmp(c) == .eq);
|
||||
|
||||
const d = try Int.initSet(testing.allocator, 14);
|
||||
defer d.deinit();
|
||||
testing.expect(a.cmp(d) <= 0);
|
||||
testing.expect(a.cmp(d) != .gt);
|
||||
}
|
||||
|
||||
@ -326,18 +326,20 @@ pub const Rational = struct {
|
||||
r.q.swap(&other.q);
|
||||
}
|
||||
|
||||
/// Returns -1, 0, 1 if a < b, a == b or a > b respectively.
|
||||
pub fn cmp(a: Rational, b: Rational) !i8 {
|
||||
/// Returns math.Order.lt, math.Order.eq, math.Order.gt if a < b, a == b or a
|
||||
/// > b respectively.
|
||||
pub fn cmp(a: Rational, b: Rational) !math.Order {
|
||||
return cmpInternal(a, b, true);
|
||||
}
|
||||
|
||||
/// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.
|
||||
pub fn cmpAbs(a: Rational, b: Rational) !i8 {
|
||||
/// Returns math.Order.lt, math.Order.eq, math.Order.gt if |a| < |b|, |a| ==
|
||||
/// |b| or |a| > |b| respectively.
|
||||
pub fn cmpAbs(a: Rational, b: Rational) !math.Order {
|
||||
return cmpInternal(a, b, false);
|
||||
}
|
||||
|
||||
// p/q > x/y iff p*y > x*q
|
||||
fn cmpInternal(a: Rational, b: Rational, is_abs: bool) !i8 {
|
||||
fn cmpInternal(a: Rational, b: Rational, is_abs: bool) !math.Order {
|
||||
// TODO: Would a div compare algorithm of sorts be viable and quicker? Can we avoid
|
||||
// the memory allocations here?
|
||||
var q = try Int.init(a.p.allocator.?);
|
||||
@ -450,7 +452,7 @@ pub const Rational = struct {
|
||||
r.p.setSign(sign);
|
||||
|
||||
const one = Int.initFixed(([_]Limb{1})[0..]);
|
||||
if (a.cmp(one) != 0) {
|
||||
if (a.cmp(one) != .eq) {
|
||||
var unused = try Int.init(r.p.allocator.?);
|
||||
defer unused.deinit();
|
||||
|
||||
@ -505,7 +507,7 @@ fn gcdLehmer(r: *Int, xa: Int, ya: Int) !void {
|
||||
y.abs();
|
||||
defer y.deinit();
|
||||
|
||||
if (x.cmp(y) < 0) {
|
||||
if (x.cmp(y) == .lt) {
|
||||
x.swap(&y);
|
||||
}
|
||||
|
||||
@ -573,7 +575,7 @@ fn gcdLehmer(r: *Int, xa: Int, ya: Int) !void {
|
||||
}
|
||||
|
||||
// euclidean algorithm
|
||||
debug.assert(x.cmp(y) >= 0);
|
||||
debug.assert(x.cmp(y) != .lt);
|
||||
|
||||
while (!y.eqZero()) {
|
||||
try Int.divTrunc(&T, r, x, y);
|
||||
@ -874,11 +876,11 @@ test "big.rational cmp" {
|
||||
|
||||
try a.setRatio(500, 231);
|
||||
try b.setRatio(18903, 8584);
|
||||
testing.expect((try a.cmp(b)) < 0);
|
||||
testing.expect((try a.cmp(b)) == .lt);
|
||||
|
||||
try a.setRatio(890, 10);
|
||||
try b.setRatio(89, 1);
|
||||
testing.expect((try a.cmp(b)) == 0);
|
||||
testing.expect((try a.cmp(b)) == .eq);
|
||||
}
|
||||
|
||||
test "big.rational add single-limb" {
|
||||
@ -889,11 +891,11 @@ test "big.rational add single-limb" {
|
||||
|
||||
try a.setRatio(500, 231);
|
||||
try b.setRatio(18903, 8584);
|
||||
testing.expect((try a.cmp(b)) < 0);
|
||||
testing.expect((try a.cmp(b)) == .lt);
|
||||
|
||||
try a.setRatio(890, 10);
|
||||
try b.setRatio(89, 1);
|
||||
testing.expect((try a.cmp(b)) == 0);
|
||||
testing.expect((try a.cmp(b)) == .eq);
|
||||
}
|
||||
|
||||
test "big.rational add" {
|
||||
@ -909,7 +911,7 @@ test "big.rational add" {
|
||||
try a.add(a, b);
|
||||
|
||||
try r.setRatio(984786924199, 290395044174);
|
||||
testing.expect((try a.cmp(r)) == 0);
|
||||
testing.expect((try a.cmp(r)) == .eq);
|
||||
}
|
||||
|
||||
test "big.rational sub" {
|
||||
@ -925,7 +927,7 @@ test "big.rational sub" {
|
||||
try a.sub(a, b);
|
||||
|
||||
try r.setRatio(979040510045, 290395044174);
|
||||
testing.expect((try a.cmp(r)) == 0);
|
||||
testing.expect((try a.cmp(r)) == .eq);
|
||||
}
|
||||
|
||||
test "big.rational mul" {
|
||||
@ -941,7 +943,7 @@ test "big.rational mul" {
|
||||
try a.mul(a, b);
|
||||
|
||||
try r.setRatio(571481443, 17082061422);
|
||||
testing.expect((try a.cmp(r)) == 0);
|
||||
testing.expect((try a.cmp(r)) == .eq);
|
||||
}
|
||||
|
||||
test "big.rational div" {
|
||||
@ -957,7 +959,7 @@ test "big.rational div" {
|
||||
try a.div(a, b);
|
||||
|
||||
try r.setRatio(75531824394, 221015929);
|
||||
testing.expect((try a.cmp(r)) == 0);
|
||||
testing.expect((try a.cmp(r)) == .eq);
|
||||
}
|
||||
|
||||
test "big.rational div" {
|
||||
@ -970,11 +972,11 @@ test "big.rational div" {
|
||||
a.invert();
|
||||
|
||||
try r.setRatio(23341, 78923);
|
||||
testing.expect((try a.cmp(r)) == 0);
|
||||
testing.expect((try a.cmp(r)) == .eq);
|
||||
|
||||
try a.setRatio(-78923, 23341);
|
||||
a.invert();
|
||||
|
||||
try r.setRatio(-23341, 78923);
|
||||
testing.expect((try a.cmp(r)) == 0);
|
||||
testing.expect((try a.cmp(r)) == .eq);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user