authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2019-04-09 17:44:49+12:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2019-04-11 19:36:35+12:00
log78af62a19a87904193c59f46ac554330ba872564
treeaf89875455723e0ec9bd2d3f1159b85258054d30
parent87d8ecda462688c597c726b1da5dbd5f8478e0fc

Pack big.Int sign and length fields

This effectively takes one-bit from the length field and uses it as the sign bit. It reduces the size of an Int from 40 bits to 32 bits on a 64-bit arch. This also reduces std.Rational from 80 bits to 64 bits.

3 files changed, 203 insertions(+), 185 deletions(-)

src-self-hosted/value.zig+4-4
......@@ -538,21 +538,21 @@ pub const Value = struct {
538538 switch (self.base.typ.id) {
539539 Type.Id.Int => {
540540 const type_ref = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
541 if (self.big_int.len == 0) {
541 if (self.big_int.len() == 0) {
542542 return llvm.ConstNull(type_ref);
543543 }
544 const unsigned_val = if (self.big_int.len == 1) blk: {
544 const unsigned_val = if (self.big_int.len() == 1) blk: {
545545 break :blk llvm.ConstInt(type_ref, self.big_int.limbs[0], @boolToInt(false));
546546 } else if (@sizeOf(std.math.big.Limb) == @sizeOf(u64)) blk: {
547547 break :blk llvm.ConstIntOfArbitraryPrecision(
548548 type_ref,
549 @intCast(c_uint, self.big_int.len),
549 @intCast(c_uint, self.big_int.len()),
550550 @ptrCast([*]u64, self.big_int.limbs.ptr),
551551 );
552552 } else {
553553 @compileError("std.math.Big.Int.Limb size does not match LLVM");
554554 };
555 return if (self.big_int.positive) unsigned_val else llvm.ConstNeg(unsigned_val);
555 return if (self.big_int.isPositive()) unsigned_val else llvm.ConstNeg(unsigned_val);
556556 },
557557 Type.Id.ComptimeInt => unreachable,
558558 else => unreachable,
std/math/big/int.zig+179-162
......@@ -22,13 +22,18 @@ comptime {
2222}
2323
2424pub const Int = struct {
25 const sign_bit: usize = 1 << (usize.bit_count - 1);
26
2527 allocator: ?*Allocator,
26 positive: bool,
2728 // - little-endian ordered
2829 // - len >= 1 always
2930 // - zero value -> len == 1 with limbs[0] == 0
3031 limbs: []Limb,
31 len: usize,
32 // High bit is the sign bit. 1 is negative, 0 positive.
33 // Remaining bits indicate the number of used limbs.
34 //
35 // If Zig gets smarter about packing data, this can be rewritten as a u1 and usize - 1 field.
36 metadata: usize,
3237
3338 const default_capacity = 4;
3439
......@@ -45,26 +50,45 @@ pub const Int = struct {
4550 pub fn initCapacity(allocator: *Allocator, capacity: usize) !Int {
4651 return Int{
4752 .allocator = allocator,
48 .positive = true,
53 .metadata = 1,
4954 .limbs = block: {
5055 var limbs = try allocator.alloc(Limb, math.max(default_capacity, capacity));
5156 limbs[0] = 0;
5257 break :block limbs;
5358 },
54 .len = 1,
5559 };
5660 }
5761
62 pub fn len(self: Int) usize {
63 return self.metadata & ~sign_bit;
64 }
65
66 pub fn isPositive(self: Int) bool {
67 return self.metadata & sign_bit == 0;
68 }
69
70 pub fn setSign(self: *Int, positive: bool) void {
71 if (positive) {
72 self.metadata &= ~sign_bit;
73 } else {
74 self.metadata |= sign_bit;
75 }
76 }
77
78 pub fn setLen(self: *Int, new_len: usize) void {
79 self.metadata &= sign_bit;
80 self.metadata |= new_len;
81 }
82
5883 // Initialize an Int directly from a fixed set of limb values. This is considered read-only
5984 // and cannot be used as a receiver argument to any functions. If this tries to allocate
6085 // at any point a panic will occur due to the null allocator.
6186 pub fn initFixed(limbs: []const Limb) Int {
6287 var self = Int{
6388 .allocator = null,
64 .positive = true,
89 .metadata = limbs.len,
6590 // Cast away the const, invalid use to pass as a pointer argument.
6691 .limbs = @intToPtr([*]Limb, @ptrToInt(limbs.ptr))[0..limbs.len],
67 .len = limbs.len,
6892 };
6993
7094 self.normalize(limbs.len);
......@@ -96,13 +120,12 @@ pub const Int = struct {
96120 other.assertWritable();
97121 return Int{
98122 .allocator = other.allocator,
99 .positive = other.positive,
123 .metadata = other.metadata,
100124 .limbs = block: {
101 var limbs = try other.allocator.?.alloc(Limb, other.len);
102 mem.copy(Limb, limbs[0..], other.limbs[0..other.len]);
125 var limbs = try other.allocator.?.alloc(Limb, other.len());
126 mem.copy(Limb, limbs[0..], other.limbs[0..other.len()]);
103127 break :block limbs;
104128 },
105 .len = other.len,
106129 };
107130 }
108131
......@@ -112,10 +135,9 @@ pub const Int = struct {
112135 return;
113136 }
114137
115 self.positive = other.positive;
116 try self.ensureCapacity(other.len);
117 mem.copy(Limb, self.limbs[0..], other.limbs[0..other.len]);
118 self.len = other.len;
138 try self.ensureCapacity(other.len());
139 mem.copy(Limb, self.limbs[0..], other.limbs[0..other.len()]);
140 self.metadata = other.metadata;
119141 }
120142
121143 pub fn swap(self: *Int, other: *Int) void {
......@@ -131,11 +153,11 @@ pub const Int = struct {
131153 }
132154
133155 pub fn negate(self: *Int) void {
134 self.positive = !self.positive;
156 self.metadata ^= sign_bit;
135157 }
136158
137159 pub fn abs(self: *Int) void {
138 self.positive = true;
160 self.metadata &= ~sign_bit;
139161 }
140162
141163 pub fn isOdd(self: Int) bool {
......@@ -148,7 +170,7 @@ pub const Int = struct {
148170
149171 // Returns the number of bits required to represent the absolute value of self.
150172 fn bitCountAbs(self: Int) usize {
151 return (self.len - 1) * Limb.bit_count + (Limb.bit_count - @clz(self.limbs[self.len - 1]));
173 return (self.len() - 1) * Limb.bit_count + (Limb.bit_count - @clz(self.limbs[self.len() - 1]));
152174 }
153175
154176 // Returns the number of bits required to represent the integer in twos-complement form.
......@@ -164,11 +186,11 @@ pub const Int = struct {
164186
165187 // If the entire value has only one bit set (e.g. 0b100000000) then the negation in twos
166188 // complement requires one less bit.
167 if (!self.positive) block: {
189 if (!self.isPositive()) block: {
168190 bits += 1;
169191
170 if (@popCount(self.limbs[self.len - 1]) == 1) {
171 for (self.limbs[0 .. self.len - 1]) |limb| {
192 if (@popCount(self.limbs[self.len() - 1]) == 1) {
193 for (self.limbs[0 .. self.len() - 1]) |limb| {
172194 if (@popCount(limb) != 0) {
173195 break :block;
174196 }
......@@ -185,11 +207,11 @@ pub const Int = struct {
185207 if (self.eqZero()) {
186208 return true;
187209 }
188 if (!is_signed and !self.positive) {
210 if (!is_signed and !self.isPositive()) {
189211 return false;
190212 }
191213
192 const req_bits = self.bitCountTwosComp() + @boolToInt(self.positive and is_signed);
214 const req_bits = self.bitCountTwosComp() + @boolToInt(self.isPositive() and is_signed);
193215 return bit_count >= req_bits;
194216 }
195217
......@@ -201,7 +223,7 @@ pub const Int = struct {
201223 // the minus sign. This is used for determining the number of characters needed to print the
202224 // value. It is inexact and will exceed the given value by 1-2 digits.
203225 pub fn sizeInBase(self: Int, base: usize) usize {
204 const bit_count = usize(@boolToInt(!self.positive)) + self.bitCountAbs();
226 const bit_count = usize(@boolToInt(!self.isPositive())) + self.bitCountAbs();
205227 return (bit_count / math.log2(base)) + 1;
206228 }
207229
......@@ -214,19 +236,19 @@ pub const Int = struct {
214236 const UT = if (T.is_signed) @IntType(false, T.bit_count - 1) else T;
215237
216238 try self.ensureCapacity(@sizeOf(UT) / @sizeOf(Limb));
217 self.positive = value >= 0;
218 self.len = 0;
239 self.metadata = 0;
240 self.setSign(value >= 0);
219241
220242 var w_value: UT = if (value < 0) @intCast(UT, -value) else @intCast(UT, value);
221243
222244 if (info.bits <= Limb.bit_count) {
223245 self.limbs[0] = Limb(w_value);
224 self.len = 1;
246 self.metadata += 1;
225247 } else {
226248 var i: usize = 0;
227249 while (w_value != 0) : (i += 1) {
228250 self.limbs[i] = @truncate(Limb, w_value);
229 self.len += 1;
251 self.metadata += 1;
230252
231253 // TODO: shift == 64 at compile-time fails. Fails on u128 limbs.
232254 w_value >>= Limb.bit_count / 2;
......@@ -240,8 +262,8 @@ pub const Int = struct {
240262 const req_limbs = @divFloor(math.log2(w_value), Limb.bit_count) + 1;
241263 try self.ensureCapacity(req_limbs);
242264
243 self.positive = value >= 0;
244 self.len = req_limbs;
265 self.metadata = req_limbs;
266 self.setSign(value >= 0);
245267
246268 if (w_value <= maxInt(Limb)) {
247269 self.limbs[0] = w_value;
......@@ -282,17 +304,17 @@ pub const Int = struct {
282304 if (@sizeOf(UT) <= @sizeOf(Limb)) {
283305 r = @intCast(UT, self.limbs[0]);
284306 } else {
285 for (self.limbs[0..self.len]) |_, ri| {
286 const limb = self.limbs[self.len - ri - 1];
307 for (self.limbs[0..self.len()]) |_, ri| {
308 const limb = self.limbs[self.len() - ri - 1];
287309 r <<= Limb.bit_count;
288310 r |= limb;
289311 }
290312 }
291313
292314 if (!T.is_signed) {
293 return if (self.positive) @intCast(T, r) else error.NegativeIntoUnsigned;
315 return if (self.isPositive()) @intCast(T, r) else error.NegativeIntoUnsigned;
294316 } else {
295 if (self.positive) {
317 if (self.isPositive()) {
296318 return @intCast(T, r);
297319 } else {
298320 if (math.cast(T, r)) |ok| {
......@@ -355,7 +377,7 @@ pub const Int = struct {
355377 try self.mul(self.*, ap_base);
356378 try self.add(self.*, ap_d);
357379 }
358 self.positive = positive;
380 self.setSign(positive);
359381 }
360382
361383 /// TODO make this call format instead of the other way around
......@@ -377,7 +399,7 @@ pub const Int = struct {
377399 if (base & (base - 1) == 0) {
378400 const base_shift = math.log2_int(Limb, base);
379401
380 for (self.limbs[0..self.len]) |limb| {
402 for (self.limbs[0..self.len()]) |limb| {
381403 var shift: usize = 0;
382404 while (shift < Limb.bit_count) : (shift += base_shift) {
383405 const r = @intCast(u8, (limb >> @intCast(Log2Limb, shift)) & Limb(base - 1));
......@@ -404,11 +426,11 @@ pub const Int = struct {
404426 }
405427
406428 var q = try self.clone();
407 q.positive = true;
429 q.abs();
408430 var r = try Int.init(allocator);
409431 var b = try Int.initSet(allocator, limb_base);
410432
411 while (q.len >= 2) {
433 while (q.len() >= 2) {
412434 try Int.divTrunc(&q, &r, q, b);
413435
414436 var r_word = r.limbs[0];
......@@ -421,7 +443,7 @@ pub const Int = struct {
421443 }
422444
423445 {
424 debug.assert(q.len == 1);
446 debug.assert(q.len() == 1);
425447
426448 var r_word = q.limbs[0];
427449 while (r_word != 0) {
......@@ -432,7 +454,7 @@ pub const Int = struct {
432454 }
433455 }
434456
435 if (!self.positive) {
457 if (!self.isPositive()) {
436458 try digits.append('-');
437459 }
438460
......@@ -460,14 +482,14 @@ pub const Int = struct {
460482
461483 // returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.
462484 pub fn cmpAbs(a: Int, b: Int) i8 {
463 if (a.len < b.len) {
485 if (a.len() < b.len()) {
464486 return -1;
465487 }
466 if (a.len > b.len) {
488 if (a.len() > b.len()) {
467489 return 1;
468490 }
469491
470 var i: usize = a.len - 1;
492 var i: usize = a.len() - 1;
471493 while (i != 0) : (i -= 1) {
472494 if (a.limbs[i] != b.limbs[i]) {
473495 break;
......@@ -485,17 +507,17 @@ pub const Int = struct {
485507
486508 // returns -1, 0, 1 if a < b, a == b or a > b respectively.
487509 pub fn cmp(a: Int, b: Int) i8 {
488 if (a.positive != b.positive) {
489 return if (a.positive) i8(1) else -1;
510 if (a.isPositive() != b.isPositive()) {
511 return if (a.isPositive()) i8(1) else -1;
490512 } else {
491513 const r = cmpAbs(a, b);
492 return if (a.positive) r else -r;
514 return if (a.isPositive()) r else -r;
493515 }
494516 }
495517
496518 // if a == 0
497519 pub fn eqZero(a: Int) bool {
498 return a.len == 1 and a.limbs[0] == 0;
520 return a.len() == 1 and a.limbs[0] == 0;
499521 }
500522
501523 // if |a| == |b|
......@@ -525,16 +547,15 @@ pub const Int = struct {
525547 }
526548
527549 // Handle zero
528 r.len = if (j != 0) j else 1;
550 r.setLen(if (j != 0) j else 1);
529551 }
530552
531553 // Cannot be used as a result argument to any function.
532554 fn readOnlyPositive(a: Int) Int {
533555 return Int{
534556 .allocator = null,
535 .positive = true,
557 .metadata = a.len(),
536558 .limbs = a.limbs,
537 .len = a.len,
538559 };
539560 }
540561
......@@ -549,8 +570,8 @@ pub const Int = struct {
549570 return;
550571 }
551572
552 if (a.positive != b.positive) {
553 if (a.positive) {
573 if (a.isPositive() != b.isPositive()) {
574 if (a.isPositive()) {
554575 // (a) + (-b) => a - b
555576 try r.sub(a, readOnlyPositive(b));
556577 } else {
......@@ -558,17 +579,17 @@ pub const Int = struct {
558579 try r.sub(b, readOnlyPositive(a));
559580 }
560581 } else {
561 if (a.len >= b.len) {
562 try r.ensureCapacity(a.len + 1);
563 lladd(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
564 r.normalize(a.len + 1);
582 if (a.len() >= b.len()) {
583 try r.ensureCapacity(a.len() + 1);
584 lladd(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]);
585 r.normalize(a.len() + 1);
565586 } else {
566 try r.ensureCapacity(b.len + 1);
567 lladd(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]);
568 r.normalize(b.len + 1);
587 try r.ensureCapacity(b.len() + 1);
588 lladd(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]);
589 r.normalize(b.len() + 1);
569590 }
570591
571 r.positive = a.positive;
592 r.setSign(a.isPositive());
572593 }
573594 }
574595
......@@ -599,41 +620,41 @@ pub const Int = struct {
599620 // r = a - b
600621 pub fn sub(r: *Int, a: Int, b: Int) !void {
601622 r.assertWritable();
602 if (a.positive != b.positive) {
603 if (a.positive) {
623 if (a.isPositive() != b.isPositive()) {
624 if (a.isPositive()) {
604625 // (a) - (-b) => a + b
605626 try r.add(a, readOnlyPositive(b));
606627 } else {
607628 // (-a) - (b) => -(a + b)
608629 try r.add(readOnlyPositive(a), b);
609 r.positive = false;
630 r.setSign(false);
610631 }
611632 } else {
612 if (a.positive) {
633 if (a.isPositive()) {
613634 // (a) - (b) => a - b
614635 if (a.cmp(b) >= 0) {
615 try r.ensureCapacity(a.len + 1);
616 llsub(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
617 r.normalize(a.len);
618 r.positive = true;
636 try r.ensureCapacity(a.len() + 1);
637 llsub(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]);
638 r.normalize(a.len());
639 r.setSign(true);
619640 } else {
620 try r.ensureCapacity(b.len + 1);
621 llsub(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]);
622 r.normalize(b.len);
623 r.positive = false;
641 try r.ensureCapacity(b.len() + 1);
642 llsub(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]);
643 r.normalize(b.len());
644 r.setSign(false);
624645 }
625646 } else {
626647 // (-a) - (-b) => -(a - b)
627648 if (a.cmp(b) < 0) {
628 try r.ensureCapacity(a.len + 1);
629 llsub(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
630 r.normalize(a.len);
631 r.positive = false;
649 try r.ensureCapacity(a.len() + 1);
650 llsub(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]);
651 r.normalize(a.len());
652 r.setSign(false);
632653 } else {
633 try r.ensureCapacity(b.len + 1);
634 llsub(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]);
635 r.normalize(b.len);
636 r.positive = true;
654 try r.ensureCapacity(b.len() + 1);
655 llsub(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]);
656 r.normalize(b.len());
657 r.setSign(true);
637658 }
638659 }
639660 }
......@@ -674,7 +695,7 @@ pub const Int = struct {
674695
675696 var sr: Int = undefined;
676697 if (aliased) {
677 sr = try Int.initCapacity(rma.allocator.?, a.len + b.len);
698 sr = try Int.initCapacity(rma.allocator.?, a.len() + b.len());
678699 r = &sr;
679700 aliased = true;
680701 }
......@@ -683,16 +704,16 @@ pub const Int = struct {
683704 r.deinit();
684705 };
685706
686 try r.ensureCapacity(a.len + b.len);
707 try r.ensureCapacity(a.len() + b.len());
687708
688 if (a.len >= b.len) {
689 llmul(r.limbs, a.limbs[0..a.len], b.limbs[0..b.len]);
709 if (a.len() >= b.len()) {
710 llmul(r.limbs, a.limbs[0..a.len()], b.limbs[0..b.len()]);
690711 } else {
691 llmul(r.limbs, b.limbs[0..b.len], a.limbs[0..a.len]);
712 llmul(r.limbs, b.limbs[0..b.len()], a.limbs[0..a.len()]);
692713 }
693714
694 r.positive = a.positive == b.positive;
695 r.normalize(a.len + b.len);
715 r.normalize(a.len() + b.len());
716 r.setSign(a.isPositive() == b.isPositive());
696717 }
697718
698719 // a + b * c + *carry, sets carry to the overflow bits
......@@ -742,17 +763,17 @@ pub const Int = struct {
742763 try div(q, r, a, b);
743764
744765 // Trunc -> Floor.
745 if (!q.positive) {
766 if (!q.isPositive()) {
746767 const one = Int.initFixed(([]Limb{1})[0..]);
747768 try q.sub(q.*, one);
748769 try r.add(q.*, one);
749770 }
750 r.positive = b.positive;
771 r.setSign(b.isPositive());
751772 }
752773
753774 pub fn divTrunc(q: *Int, r: *Int, a: Int, b: Int) !void {
754775 try div(q, r, a, b);
755 r.positive = a.positive;
776 r.setSign(a.isPositive());
756777 }
757778
758779 // Truncates by default.
......@@ -770,10 +791,9 @@ pub const Int = struct {
770791 if (a.cmpAbs(b) < 0) {
771792 // quo may alias a so handle rem first
772793 try rem.copy(a);
773 rem.positive = a.positive == b.positive;
794 rem.setSign(a.isPositive() == b.isPositive());
774795
775 quo.positive = true;
776 quo.len = 1;
796 quo.metadata = 1;
777797 quo.limbs[0] = 0;
778798 return;
779799 }
......@@ -782,14 +802,14 @@ pub const Int = struct {
782802 // algorithms.
783803 const a_zero_limb_count = blk: {
784804 var i: usize = 0;
785 while (i < a.len) : (i += 1) {
805 while (i < a.len()) : (i += 1) {
786806 if (a.limbs[i] != 0) break;
787807 }
788808 break :blk i;
789809 };
790810 const b_zero_limb_count = blk: {
791811 var i: usize = 0;
792 while (i < b.len) : (i += 1) {
812 while (i < b.len()) : (i += 1) {
793813 if (b.limbs[i] != 0) break;
794814 }
795815 break :blk i;
......@@ -797,39 +817,37 @@ pub const Int = struct {
797817
798818 const ab_zero_limb_count = std.math.min(a_zero_limb_count, b_zero_limb_count);
799819
800 if (b.len - ab_zero_limb_count == 1) {
801 try quo.ensureCapacity(a.len);
820 if (b.len() - ab_zero_limb_count == 1) {
821 try quo.ensureCapacity(a.len());
802822
803 lldiv1(quo.limbs[0..], &rem.limbs[0], a.limbs[ab_zero_limb_count..a.len], b.limbs[b.len - 1]);
804 quo.normalize(a.len - ab_zero_limb_count);
805 quo.positive = a.positive == b.positive;
823 lldiv1(quo.limbs[0..], &rem.limbs[0], a.limbs[ab_zero_limb_count..a.len()], b.limbs[b.len() - 1]);
824 quo.normalize(a.len() - ab_zero_limb_count);
825 quo.setSign(a.isPositive() == b.isPositive());
806826
807 rem.len = 1;
808 rem.positive = true;
827 rem.metadata = 1;
809828 } else {
810829 // x and y are modified during division
811 var x = try Int.initCapacity(quo.allocator.?, a.len);
830 var x = try Int.initCapacity(quo.allocator.?, a.len());
812831 defer x.deinit();
813832 try x.copy(a);
814833
815 var y = try Int.initCapacity(quo.allocator.?, b.len);
834 var y = try Int.initCapacity(quo.allocator.?, b.len());
816835 defer y.deinit();
817836 try y.copy(b);
818837
819838 // x may grow one limb during normalization
820 try quo.ensureCapacity(a.len + y.len);
839 try quo.ensureCapacity(a.len() + y.len());
821840
822841 // Shrink x, y such that the trailing zero limbs shared between are removed.
823842 if (ab_zero_limb_count != 0) {
824843 std.mem.copy(Limb, x.limbs[0..], x.limbs[ab_zero_limb_count..]);
825844 std.mem.copy(Limb, y.limbs[0..], y.limbs[ab_zero_limb_count..]);
826 x.len -= ab_zero_limb_count;
827 y.len -= ab_zero_limb_count;
845 x.metadata -= ab_zero_limb_count;
846 y.metadata -= ab_zero_limb_count;
828847 }
829848
830849 try divN(quo.allocator.?, quo, rem, &x, &y);
831
832 quo.positive = a.positive == b.positive;
850 quo.setSign(a.isPositive() == b.isPositive());
833851 }
834852
835853 if (ab_zero_limb_count != 0) {
......@@ -868,28 +886,28 @@ pub const Int = struct {
868886 //
869887 // x = qy + r where 0 <= r < y
870888 fn divN(allocator: *Allocator, q: *Int, r: *Int, x: *Int, y: *Int) !void {
871 debug.assert(y.len >= 2);
872 debug.assert(x.len >= y.len);
873 debug.assert(q.limbs.len >= x.len + y.len - 1);
889 debug.assert(y.len() >= 2);
890 debug.assert(x.len() >= y.len());
891 debug.assert(q.limbs.len >= x.len() + y.len() - 1);
874892 debug.assert(default_capacity >= 3); // see 3.2
875893
876894 var tmp = try Int.init(allocator);
877895 defer tmp.deinit();
878896
879897 // Normalize so y > Limb.bit_count / 2 (i.e. leading bit is set) and even
880 var norm_shift = @clz(y.limbs[y.len - 1]);
898 var norm_shift = @clz(y.limbs[y.len() - 1]);
881899 if (norm_shift == 0 and y.isOdd()) {
882900 norm_shift = Limb.bit_count;
883901 }
884902 try x.shiftLeft(x.*, norm_shift);
885903 try y.shiftLeft(y.*, norm_shift);
886904
887 const n = x.len - 1;
888 const t = y.len - 1;
905 const n = x.len() - 1;
906 const t = y.len() - 1;
889907
890908 // 1.
891 q.len = n - t + 1;
892 mem.set(Limb, q.limbs[0..q.len], 0);
909 q.metadata = n - t + 1;
910 mem.set(Limb, q.limbs[0..q.len()], 0);
893911
894912 // 2.
895913 try tmp.shiftLeft(y.*, Limb.bit_count * (n - t));
......@@ -937,7 +955,7 @@ pub const Int = struct {
937955 try tmp.shiftLeft(tmp, Limb.bit_count * (i - t - 1));
938956 try x.sub(x.*, tmp);
939957
940 if (!x.positive) {
958 if (!x.isPositive()) {
941959 try tmp.shiftLeft(y.*, Limb.bit_count * (i - t - 1));
942960 try x.add(x.*, tmp);
943961 q.limbs[i - t - 1] -= 1;
......@@ -945,20 +963,20 @@ pub const Int = struct {
945963 }
946964
947965 // Denormalize
948 q.normalize(q.len);
966 q.normalize(q.len());
949967
950968 try r.shiftRight(x.*, norm_shift);
951 r.normalize(r.len);
969 r.normalize(r.len());
952970 }
953971
954972 // r = a << shift, in other words, r = a * 2^shift
955973 pub fn shiftLeft(r: *Int, a: Int, shift: usize) !void {
956974 r.assertWritable();
957975
958 try r.ensureCapacity(a.len + (shift / Limb.bit_count) + 1);
959 llshl(r.limbs[0..], a.limbs[0..a.len], shift);
960 r.normalize(a.len + (shift / Limb.bit_count) + 1);
961 r.positive = a.positive;
976 try r.ensureCapacity(a.len() + (shift / Limb.bit_count) + 1);
977 llshl(r.limbs[0..], a.limbs[0..a.len()], shift);
978 r.normalize(a.len() + (shift / Limb.bit_count) + 1);
979 r.setSign(a.isPositive());
962980 }
963981
964982 fn llshl(r: []Limb, a: []const Limb, shift: usize) void {
......@@ -988,17 +1006,16 @@ pub const Int = struct {
9881006 pub fn shiftRight(r: *Int, a: Int, shift: usize) !void {
9891007 r.assertWritable();
9901008
991 if (a.len <= shift / Limb.bit_count) {
992 r.len = 1;
1009 if (a.len() <= shift / Limb.bit_count) {
1010 r.metadata = 1;
9931011 r.limbs[0] = 0;
994 r.positive = true;
9951012 return;
9961013 }
9971014
998 try r.ensureCapacity(a.len - (shift / Limb.bit_count));
999 const r_len = llshr(r.limbs[0..], a.limbs[0..a.len], shift);
1000 r.len = a.len - (shift / Limb.bit_count);
1001 r.positive = a.positive;
1015 try r.ensureCapacity(a.len() - (shift / Limb.bit_count));
1016 const r_len = llshr(r.limbs[0..], a.limbs[0..a.len()], shift);
1017 r.metadata = a.len() - (shift / Limb.bit_count);
1018 r.setSign(a.isPositive());
10021019 }
10031020
10041021 fn llshr(r: []Limb, a: []const Limb, shift: usize) void {
......@@ -1025,14 +1042,14 @@ pub const Int = struct {
10251042 pub fn bitOr(r: *Int, a: Int, b: Int) !void {
10261043 r.assertWritable();
10271044
1028 if (a.len > b.len) {
1029 try r.ensureCapacity(a.len);
1030 llor(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
1031 r.len = a.len;
1045 if (a.len() > b.len()) {
1046 try r.ensureCapacity(a.len());
1047 llor(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]);
1048 r.setLen(a.len());
10321049 } else {
1033 try r.ensureCapacity(b.len);
1034 llor(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]);
1035 r.len = b.len;
1050 try r.ensureCapacity(b.len());
1051 llor(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]);
1052 r.setLen(b.len());
10361053 }
10371054 }
10381055
......@@ -1054,14 +1071,14 @@ pub const Int = struct {
10541071 pub fn bitAnd(r: *Int, a: Int, b: Int) !void {
10551072 r.assertWritable();
10561073
1057 if (a.len > b.len) {
1058 try r.ensureCapacity(b.len);
1059 lland(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
1060 r.normalize(b.len);
1074 if (a.len() > b.len()) {
1075 try r.ensureCapacity(b.len());
1076 lland(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]);
1077 r.normalize(b.len());
10611078 } else {
1062 try r.ensureCapacity(a.len);
1063 lland(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]);
1064 r.normalize(a.len);
1079 try r.ensureCapacity(a.len());
1080 lland(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]);
1081 r.normalize(a.len());
10651082 }
10661083 }
10671084
......@@ -1080,14 +1097,14 @@ pub const Int = struct {
10801097 pub fn bitXor(r: *Int, a: Int, b: Int) !void {
10811098 r.assertWritable();
10821099
1083 if (a.len > b.len) {
1084 try r.ensureCapacity(a.len);
1085 llxor(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
1086 r.normalize(a.len);
1100 if (a.len() > b.len()) {
1101 try r.ensureCapacity(a.len());
1102 llxor(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]);
1103 r.normalize(a.len());
10871104 } else {
1088 try r.ensureCapacity(b.len);
1089 llxor(r.limbs[0..], b.limbs[0..b.len], a.limbs[0..a.len]);
1090 r.normalize(b.len);
1105 try r.ensureCapacity(b.len());
1106 llxor(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]);
1107 r.normalize(b.len());
10911108 }
10921109 }
10931110
......@@ -1134,14 +1151,14 @@ test "big.int comptime_int set negative" {
11341151 var a = try Int.initSet(al, -10);
11351152
11361153 testing.expect(a.limbs[0] == 10);
1137 testing.expect(a.positive == false);
1154 testing.expect(a.isPositive() == false);
11381155}
11391156
11401157test "big.int int set unaligned small" {
11411158 var a = try Int.initSet(al, u7(45));
11421159
11431160 testing.expect(a.limbs[0] == 45);
1144 testing.expect(a.positive == true);
1161 testing.expect(a.isPositive() == true);
11451162}
11461163
11471164test "big.int comptime_int to" {
......@@ -1171,22 +1188,22 @@ test "big.int normalize" {
11711188 a.limbs[2] = 3;
11721189 a.limbs[3] = 0;
11731190 a.normalize(4);
1174 testing.expect(a.len == 3);
1191 testing.expect(a.len() == 3);
11751192
11761193 a.limbs[0] = 1;
11771194 a.limbs[1] = 2;
11781195 a.limbs[2] = 3;
11791196 a.normalize(3);
1180 testing.expect(a.len == 3);
1197 testing.expect(a.len() == 3);
11811198
11821199 a.limbs[0] = 0;
11831200 a.limbs[1] = 0;
11841201 a.normalize(2);
1185 testing.expect(a.len == 1);
1202 testing.expect(a.len() == 1);
11861203
11871204 a.limbs[0] = 0;
11881205 a.normalize(1);
1189 testing.expect(a.len == 1);
1206 testing.expect(a.len() == 1);
11901207}
11911208
11921209test "big.int normalize multi" {
......@@ -1198,24 +1215,24 @@ test "big.int normalize multi" {
11981215 a.limbs[2] = 0;
11991216 a.limbs[3] = 0;
12001217 a.normalize(4);
1201 testing.expect(a.len == 2);
1218 testing.expect(a.len() == 2);
12021219
12031220 a.limbs[0] = 1;
12041221 a.limbs[1] = 2;
12051222 a.limbs[2] = 3;
12061223 a.normalize(3);
1207 testing.expect(a.len == 3);
1224 testing.expect(a.len() == 3);
12081225
12091226 a.limbs[0] = 0;
12101227 a.limbs[1] = 0;
12111228 a.limbs[2] = 0;
12121229 a.limbs[3] = 0;
12131230 a.normalize(4);
1214 testing.expect(a.len == 1);
1231 testing.expect(a.len() == 1);
12151232
12161233 a.limbs[0] = 0;
12171234 a.normalize(1);
1218 testing.expect(a.len == 1);
1235 testing.expect(a.len() == 1);
12191236}
12201237
12211238test "big.int parity" {
......@@ -1250,7 +1267,7 @@ test "big.int bitcount + sizeInBase" {
12501267 try a.shiftLeft(a, 5000);
12511268 testing.expect(a.bitCountAbs() == 5032);
12521269 testing.expect(a.sizeInBase(2) >= 5032);
1253 a.positive = false;
1270 a.setSign(false);
12541271
12551272 testing.expect(a.bitCountAbs() == 5032);
12561273 testing.expect(a.sizeInBase(2) >= 5033);
std/math/big/rational.zig+20-19
......@@ -15,7 +15,7 @@ const DoubleLimb = bn.DoubleLimb;
1515const Int = bn.Int;
1616
1717pub const Rational = struct {
18 // sign of Rational is a.positive, b.positive is ignored
18 // Sign of Rational is sign of p. Sign of q is ignored
1919 p: Int,
2020 q: Int,
2121
......@@ -152,7 +152,7 @@ pub const Rational = struct {
152152 }
153153
154154 try self.p.set(mantissa);
155 self.p.positive = f >= 0;
155 self.p.setSign(f >= 0);
156156
157157 try self.q.set(1);
158158 if (shift >= 0) {
......@@ -211,7 +211,7 @@ pub const Rational = struct {
211211 try Int.divTrunc(&q, &r, a2, b2);
212212
213213 var mantissa = extractLowBits(q, BitReprType);
214 var have_rem = r.len > 0;
214 var have_rem = r.len() > 0;
215215
216216 // 3. q didn't fit in msize2 bits, redo division b2 << 1
217217 if (mantissa >> msize2 == 1) {
......@@ -256,15 +256,16 @@ pub const Rational = struct {
256256 exact = false;
257257 }
258258
259 return if (self.p.positive) f else -f;
259 return if (self.p.isPositive()) f else -f;
260260 }
261261
262262 pub fn setRatio(self: *Rational, p: var, q: var) !void {
263263 try self.p.set(p);
264264 try self.q.set(q);
265265
266 self.p.positive = (@boolToInt(self.p.positive) ^ @boolToInt(self.q.positive)) == 0;
267 self.q.positive = true;
266 self.p.setSign(@boolToInt(self.p.isPositive()) ^ @boolToInt(self.q.isPositive()) == 0);
267 self.q.setSign(true);
268
268269 try self.reduce();
269270
270271 if (self.q.eqZero()) {
......@@ -281,8 +282,9 @@ pub const Rational = struct {
281282 try self.p.copy(a);
282283 try self.q.copy(b);
283284
284 self.p.positive = (@boolToInt(self.p.positive) ^ @boolToInt(self.q.positive)) == 0;
285 self.q.positive = true;
285 self.p.setSign(@boolToInt(self.p.isPositive()) ^ @boolToInt(self.q.isPositive()) == 0);
286 self.q.setSign(true);
287
286288 try self.reduce();
287289 }
288290
......@@ -403,11 +405,10 @@ pub const Rational = struct {
403405 var a = try Int.init(r.p.allocator.?);
404406 defer a.deinit();
405407
406 const sign = r.p.positive;
407
408 const sign = r.p.isPositive();
408409 r.p.abs();
409410 try gcd(&a, r.p, r.q);
410 r.p.positive = sign;
411 r.p.setSign(sign);
411412
412413 const one = Int.initFixed(([]Limb{1})[0..]);
413414 if (a.cmp(one) != 0) {
......@@ -431,7 +432,7 @@ fn gcd(rma: *Int, x: Int, y: Int) !void {
431432
432433 var sr: Int = undefined;
433434 if (aliased) {
434 sr = try Int.initCapacity(rma.allocator.?, math.max(x.len, y.len));
435 sr = try Int.initCapacity(rma.allocator.?, math.max(x.len(), y.len()));
435436 r = &sr;
436437 aliased = true;
437438 }
......@@ -452,7 +453,7 @@ fn FixedIntFromSignedDoubleLimb(A: SignedDoubleLimb, storage: []Limb) Int {
452453 storage[0] = @truncate(Limb, Au);
453454 storage[1] = @truncate(Limb, Au >> Limb.bit_count);
454455 var Ap = Int.initFixed(storage[0..2]);
455 Ap.positive = A_is_positive;
456 Ap.setSign(A_is_positive);
456457 return Ap;
457458}
458459
......@@ -472,12 +473,12 @@ fn gcdLehmer(r: *Int, xa: Int, ya: Int) !void {
472473 var T = try Int.init(r.allocator.?);
473474 defer T.deinit();
474475
475 while (y.len > 1) {
476 debug.assert(x.positive and y.positive);
477 debug.assert(x.len >= y.len);
476 while (y.len() > 1) {
477 debug.assert(x.isPositive() and y.isPositive());
478 debug.assert(x.len() >= y.len());
478479
479 var xh: SignedDoubleLimb = x.limbs[x.len - 1];
480 var yh: SignedDoubleLimb = if (x.len > y.len) 0 else y.limbs[x.len - 1];
480 var xh: SignedDoubleLimb = x.limbs[x.len() - 1];
481 var yh: SignedDoubleLimb = if (x.len() > y.len()) 0 else y.limbs[x.len() - 1];
481482
482483 var A: SignedDoubleLimb = 1;
483484 var B: SignedDoubleLimb = 0;
......@@ -506,7 +507,7 @@ fn gcdLehmer(r: *Int, xa: Int, ya: Int) !void {
506507 if (B == 0) {
507508 // T = x % y, r is unused
508509 try Int.divTrunc(r, &T, x, y);
509 debug.assert(T.positive);
510 debug.assert(T.isPositive());
510511
511512 x.swap(&y);
512513 y.swap(&T);