authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2020-03-24 04:16:57+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-03-23 23:16:57-04:00
log5acc8afb5f9674b9b7b290635e9c2837872b8a93
tree43e6271ad868abb6cc09dbb0df314ddd089bf76c
parentdc44fe053c609f389e375f6857f96b6bb3794897
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Use math.Order for comparing bigints instead of i8 (#4791)


2 files changed, 54 insertions(+), 46 deletions(-)

lib/std/math/big/int.zig+34-28
...@@ -534,13 +534,14 @@ pub const Int = struct {...@@ -534,13 +534,14 @@ pub const Int = struct {
534 return out_stream.writeAll(str);534 return out_stream.writeAll(str);
535 }535 }
536536
537 /// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.537 /// Returns math.Order.lt, math.Order.eq, math.Order.gt if |a| < |b|, |a| ==
538 pub fn cmpAbs(a: Int, b: Int) i8 {538 /// |b| or |a| > |b| respectively.
539 pub fn cmpAbs(a: Int, b: Int) math.Order {
539 if (a.len() < b.len()) {540 if (a.len() < b.len()) {
540 return -1;541 return .lt;
541 }542 }
542 if (a.len() > b.len()) {543 if (a.len() > b.len()) {
543 return 1;544 return .gt;
544 }545 }
545546
546 var i: usize = a.len() - 1;547 var i: usize = a.len() - 1;
...@@ -551,21 +552,26 @@ pub const Int = struct {...@@ -551,21 +552,26 @@ pub const Int = struct {
551 }552 }
552553
553 if (a.limbs[i] < b.limbs[i]) {554 if (a.limbs[i] < b.limbs[i]) {
554 return -1;555 return .lt;
555 } else if (a.limbs[i] > b.limbs[i]) {556 } else if (a.limbs[i] > b.limbs[i]) {
556 return 1;557 return .gt;
557 } else {558 } else {
558 return 0;559 return .eq;
559 }560 }
560 }561 }
561562
562 /// Returns -1, 0, 1 if a < b, a == b or a > b respectively.563 /// Returns math.Order.lt, math.Order.eq, math.Order.gt if a < b, a == b or a
563 pub fn cmp(a: Int, b: Int) i8 {564 /// > b respectively.
565 pub fn cmp(a: Int, b: Int) math.Order {
564 if (a.isPositive() != b.isPositive()) {566 if (a.isPositive() != b.isPositive()) {
565 return if (a.isPositive()) @as(i8, 1) else -1;567 return if (a.isPositive()) .gt else .lt;
566 } else {568 } else {
567 const r = cmpAbs(a, b);569 const r = cmpAbs(a, b);
568 return if (a.isPositive()) r else -r;570 return if (a.isPositive()) r else switch (r) {
571 .lt => math.Order.gt,
572 .eq => math.Order.eq,
573 .gt => math.Order.lt,
574 };
569 }575 }
570 }576 }
571577
...@@ -576,12 +582,12 @@ pub const Int = struct {...@@ -576,12 +582,12 @@ pub const Int = struct {
576582
577 /// Returns true if |a| == |b|.583 /// Returns true if |a| == |b|.
578 pub fn eqAbs(a: Int, b: Int) bool {584 pub fn eqAbs(a: Int, b: Int) bool {
579 return cmpAbs(a, b) == 0;585 return cmpAbs(a, b) == .eq;
580 }586 }
581587
582 /// Returns true if a == b.588 /// Returns true if a == b.
583 pub fn eq(a: Int, b: Int) bool {589 pub fn eq(a: Int, b: Int) bool {
584 return cmp(a, b) == 0;590 return cmp(a, b) == .eq;
585 }591 }
586592
587 // Normalize a possible sequence of leading zeros.593 // Normalize a possible sequence of leading zeros.
...@@ -694,7 +700,7 @@ pub const Int = struct {...@@ -694,7 +700,7 @@ pub const Int = struct {
694 } else {700 } else {
695 if (a.isPositive()) {701 if (a.isPositive()) {
696 // (a) - (b) => a - b702 // (a) - (b) => a - b
697 if (a.cmp(b) >= 0) {703 if (a.cmp(b) != .lt) {
698 try r.ensureCapacity(a.len() + 1);704 try r.ensureCapacity(a.len() + 1);
699 llsub(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]);705 llsub(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]);
700 r.normalize(a.len());706 r.normalize(a.len());
...@@ -707,7 +713,7 @@ pub const Int = struct {...@@ -707,7 +713,7 @@ pub const Int = struct {
707 }713 }
708 } else {714 } else {
709 // (-a) - (-b) => -(a - b)715 // (-a) - (-b) => -(a - b)
710 if (a.cmp(b) < 0) {716 if (a.cmp(b) == .lt) {
711 try r.ensureCapacity(a.len() + 1);717 try r.ensureCapacity(a.len() + 1);
712 llsub(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]);718 llsub(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]);
713 r.normalize(a.len());719 r.normalize(a.len());
...@@ -1010,7 +1016,7 @@ pub const Int = struct {...@@ -1010,7 +1016,7 @@ pub const Int = struct {
1010 @panic("quo and rem cannot be same variable");1016 @panic("quo and rem cannot be same variable");
1011 }1017 }
10121018
1013 if (a.cmpAbs(b) < 0) {1019 if (a.cmpAbs(b) == .lt) {
1014 // quo may alias a so handle rem first1020 // quo may alias a so handle rem first
1015 try rem.copy(a);1021 try rem.copy(a);
1016 rem.setSign(a.isPositive() == b.isPositive());1022 rem.setSign(a.isPositive() == b.isPositive());
...@@ -1133,7 +1139,7 @@ pub const Int = struct {...@@ -1133,7 +1139,7 @@ pub const Int = struct {
11331139
1134 // 2.1140 // 2.
1135 try tmp.shiftLeft(y.*, Limb.bit_count * (n - t));1141 try tmp.shiftLeft(y.*, Limb.bit_count * (n - t));
1136 while (x.cmp(tmp) >= 0) {1142 while (x.cmp(tmp) != .lt) {
1137 q.limbs[n - t] += 1;1143 q.limbs[n - t] += 1;
1138 try x.sub(x.*, tmp);1144 try x.sub(x.*, tmp);
1139 }1145 }
...@@ -1164,7 +1170,7 @@ pub const Int = struct {...@@ -1164,7 +1170,7 @@ pub const Int = struct {
1164 r.limbs[2] = carry;1170 r.limbs[2] = carry;
1165 r.normalize(3);1171 r.normalize(3);
11661172
1167 if (r.cmpAbs(tmp) <= 0) {1173 if (r.cmpAbs(tmp) != .gt) {
1168 break;1174 break;
1169 }1175 }
11701176
...@@ -1719,8 +1725,8 @@ test "big.int compare" {...@@ -1719,8 +1725,8 @@ test "big.int compare" {
1719 var b = try Int.initSet(testing.allocator, 10);1725 var b = try Int.initSet(testing.allocator, 10);
1720 defer b.deinit();1726 defer b.deinit();
17211727
1722 testing.expect(a.cmpAbs(b) == 1);1728 testing.expect(a.cmpAbs(b) == .gt);
1723 testing.expect(a.cmp(b) == -1);1729 testing.expect(a.cmp(b) == .lt);
1724}1730}
17251731
1726test "big.int compare similar" {1732test "big.int compare similar" {
...@@ -1729,8 +1735,8 @@ test "big.int compare similar" {...@@ -1729,8 +1735,8 @@ test "big.int compare similar" {
1729 var b = try Int.initSet(testing.allocator, 0xffffffffeeeeeeeeffffffffeeeeeeef);1735 var b = try Int.initSet(testing.allocator, 0xffffffffeeeeeeeeffffffffeeeeeeef);
1730 defer b.deinit();1736 defer b.deinit();
17311737
1732 testing.expect(a.cmpAbs(b) == -1);1738 testing.expect(a.cmpAbs(b) == .lt);
1733 testing.expect(b.cmpAbs(a) == 1);1739 testing.expect(b.cmpAbs(a) == .gt);
1734}1740}
17351741
1736test "big.int compare different limb size" {1742test "big.int compare different limb size" {
...@@ -1739,8 +1745,8 @@ test "big.int compare different limb size" {...@@ -1739,8 +1745,8 @@ test "big.int compare different limb size" {
1739 var b = try Int.initSet(testing.allocator, 1);1745 var b = try Int.initSet(testing.allocator, 1);
1740 defer b.deinit();1746 defer b.deinit();
17411747
1742 testing.expect(a.cmpAbs(b) == 1);1748 testing.expect(a.cmpAbs(b) == .gt);
1743 testing.expect(b.cmpAbs(a) == -1);1749 testing.expect(b.cmpAbs(a) == .lt);
1744}1750}
17451751
1746test "big.int compare multi-limb" {1752test "big.int compare multi-limb" {
...@@ -1749,8 +1755,8 @@ test "big.int compare multi-limb" {...@@ -1749,8 +1755,8 @@ test "big.int compare multi-limb" {
1749 var b = try Int.initSet(testing.allocator, 0x7777777799999999ffffeeeeffffeeeeffffeeeee);1755 var b = try Int.initSet(testing.allocator, 0x7777777799999999ffffeeeeffffeeeeffffeeeee);
1750 defer b.deinit();1756 defer b.deinit();
17511757
1752 testing.expect(a.cmpAbs(b) == 1);1758 testing.expect(a.cmpAbs(b) == .gt);
1753 testing.expect(a.cmp(b) == -1);1759 testing.expect(a.cmp(b) == .lt);
1754}1760}
17551761
1756test "big.int equality" {1762test "big.int equality" {
...@@ -2726,9 +2732,9 @@ test "big.int var args" {...@@ -2726,9 +2732,9 @@ test "big.int var args" {
27262732
2727 const c = try Int.initSet(testing.allocator, 11);2733 const c = try Int.initSet(testing.allocator, 11);
2728 defer c.deinit();2734 defer c.deinit();
2729 testing.expect(a.cmp(c) == 0);2735 testing.expect(a.cmp(c) == .eq);
27302736
2731 const d = try Int.initSet(testing.allocator, 14);2737 const d = try Int.initSet(testing.allocator, 14);
2732 defer d.deinit();2738 defer d.deinit();
2733 testing.expect(a.cmp(d) <= 0);2739 testing.expect(a.cmp(d) != .gt);
2734}2740}
lib/std/math/big/rational.zig+20-18
...@@ -326,18 +326,20 @@ pub const Rational = struct {...@@ -326,18 +326,20 @@ pub const Rational = struct {
326 r.q.swap(&other.q);326 r.q.swap(&other.q);
327 }327 }
328328
329 /// Returns -1, 0, 1 if a < b, a == b or a > b respectively.329 /// Returns math.Order.lt, math.Order.eq, math.Order.gt if a < b, a == b or a
330 pub fn cmp(a: Rational, b: Rational) !i8 {330 /// > b respectively.
331 pub fn cmp(a: Rational, b: Rational) !math.Order {
331 return cmpInternal(a, b, true);332 return cmpInternal(a, b, true);
332 }333 }
333334
334 /// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.335 /// Returns math.Order.lt, math.Order.eq, math.Order.gt if |a| < |b|, |a| ==
335 pub fn cmpAbs(a: Rational, b: Rational) !i8 {336 /// |b| or |a| > |b| respectively.
337 pub fn cmpAbs(a: Rational, b: Rational) !math.Order {
336 return cmpInternal(a, b, false);338 return cmpInternal(a, b, false);
337 }339 }
338340
339 // p/q > x/y iff p*y > x*q341 // p/q > x/y iff p*y > x*q
340 fn cmpInternal(a: Rational, b: Rational, is_abs: bool) !i8 {342 fn cmpInternal(a: Rational, b: Rational, is_abs: bool) !math.Order {
341 // TODO: Would a div compare algorithm of sorts be viable and quicker? Can we avoid343 // TODO: Would a div compare algorithm of sorts be viable and quicker? Can we avoid
342 // the memory allocations here?344 // the memory allocations here?
343 var q = try Int.init(a.p.allocator.?);345 var q = try Int.init(a.p.allocator.?);
...@@ -450,7 +452,7 @@ pub const Rational = struct {...@@ -450,7 +452,7 @@ pub const Rational = struct {
450 r.p.setSign(sign);452 r.p.setSign(sign);
451453
452 const one = Int.initFixed(([_]Limb{1})[0..]);454 const one = Int.initFixed(([_]Limb{1})[0..]);
453 if (a.cmp(one) != 0) {455 if (a.cmp(one) != .eq) {
454 var unused = try Int.init(r.p.allocator.?);456 var unused = try Int.init(r.p.allocator.?);
455 defer unused.deinit();457 defer unused.deinit();
456458
...@@ -505,7 +507,7 @@ fn gcdLehmer(r: *Int, xa: Int, ya: Int) !void {...@@ -505,7 +507,7 @@ fn gcdLehmer(r: *Int, xa: Int, ya: Int) !void {
505 y.abs();507 y.abs();
506 defer y.deinit();508 defer y.deinit();
507509
508 if (x.cmp(y) < 0) {510 if (x.cmp(y) == .lt) {
509 x.swap(&y);511 x.swap(&y);
510 }512 }
511513
...@@ -573,7 +575,7 @@ fn gcdLehmer(r: *Int, xa: Int, ya: Int) !void {...@@ -573,7 +575,7 @@ fn gcdLehmer(r: *Int, xa: Int, ya: Int) !void {
573 }575 }
574576
575 // euclidean algorithm577 // euclidean algorithm
576 debug.assert(x.cmp(y) >= 0);578 debug.assert(x.cmp(y) != .lt);
577579
578 while (!y.eqZero()) {580 while (!y.eqZero()) {
579 try Int.divTrunc(&T, r, x, y);581 try Int.divTrunc(&T, r, x, y);
...@@ -874,11 +876,11 @@ test "big.rational cmp" {...@@ -874,11 +876,11 @@ test "big.rational cmp" {
874876
875 try a.setRatio(500, 231);877 try a.setRatio(500, 231);
876 try b.setRatio(18903, 8584);878 try b.setRatio(18903, 8584);
877 testing.expect((try a.cmp(b)) < 0);879 testing.expect((try a.cmp(b)) == .lt);
878880
879 try a.setRatio(890, 10);881 try a.setRatio(890, 10);
880 try b.setRatio(89, 1);882 try b.setRatio(89, 1);
881 testing.expect((try a.cmp(b)) == 0);883 testing.expect((try a.cmp(b)) == .eq);
882}884}
883885
884test "big.rational add single-limb" {886test "big.rational add single-limb" {
...@@ -889,11 +891,11 @@ test "big.rational add single-limb" {...@@ -889,11 +891,11 @@ test "big.rational add single-limb" {
889891
890 try a.setRatio(500, 231);892 try a.setRatio(500, 231);
891 try b.setRatio(18903, 8584);893 try b.setRatio(18903, 8584);
892 testing.expect((try a.cmp(b)) < 0);894 testing.expect((try a.cmp(b)) == .lt);
893895
894 try a.setRatio(890, 10);896 try a.setRatio(890, 10);
895 try b.setRatio(89, 1);897 try b.setRatio(89, 1);
896 testing.expect((try a.cmp(b)) == 0);898 testing.expect((try a.cmp(b)) == .eq);
897}899}
898900
899test "big.rational add" {901test "big.rational add" {
...@@ -909,7 +911,7 @@ test "big.rational add" {...@@ -909,7 +911,7 @@ test "big.rational add" {
909 try a.add(a, b);911 try a.add(a, b);
910912
911 try r.setRatio(984786924199, 290395044174);913 try r.setRatio(984786924199, 290395044174);
912 testing.expect((try a.cmp(r)) == 0);914 testing.expect((try a.cmp(r)) == .eq);
913}915}
914916
915test "big.rational sub" {917test "big.rational sub" {
...@@ -925,7 +927,7 @@ test "big.rational sub" {...@@ -925,7 +927,7 @@ test "big.rational sub" {
925 try a.sub(a, b);927 try a.sub(a, b);
926928
927 try r.setRatio(979040510045, 290395044174);929 try r.setRatio(979040510045, 290395044174);
928 testing.expect((try a.cmp(r)) == 0);930 testing.expect((try a.cmp(r)) == .eq);
929}931}
930932
931test "big.rational mul" {933test "big.rational mul" {
...@@ -941,7 +943,7 @@ test "big.rational mul" {...@@ -941,7 +943,7 @@ test "big.rational mul" {
941 try a.mul(a, b);943 try a.mul(a, b);
942944
943 try r.setRatio(571481443, 17082061422);945 try r.setRatio(571481443, 17082061422);
944 testing.expect((try a.cmp(r)) == 0);946 testing.expect((try a.cmp(r)) == .eq);
945}947}
946948
947test "big.rational div" {949test "big.rational div" {
...@@ -957,7 +959,7 @@ test "big.rational div" {...@@ -957,7 +959,7 @@ test "big.rational div" {
957 try a.div(a, b);959 try a.div(a, b);
958960
959 try r.setRatio(75531824394, 221015929);961 try r.setRatio(75531824394, 221015929);
960 testing.expect((try a.cmp(r)) == 0);962 testing.expect((try a.cmp(r)) == .eq);
961}963}
962964
963test "big.rational div" {965test "big.rational div" {
...@@ -970,11 +972,11 @@ test "big.rational div" {...@@ -970,11 +972,11 @@ test "big.rational div" {
970 a.invert();972 a.invert();
971973
972 try r.setRatio(23341, 78923);974 try r.setRatio(23341, 78923);
973 testing.expect((try a.cmp(r)) == 0);975 testing.expect((try a.cmp(r)) == .eq);
974976
975 try a.setRatio(-78923, 23341);977 try a.setRatio(-78923, 23341);
976 a.invert();978 a.invert();
977979
978 try r.setRatio(-23341, 78923);980 try r.setRatio(-23341, 78923);
979 testing.expect((try a.cmp(r)) == 0);981 testing.expect((try a.cmp(r)) == .eq);
980}982}