authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-01 06:15:58-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-01 06:47:56-04:00
log87668211578b843571d6819fddde944328a05f89
tree68cfe7fcdeaab2fef3d56260c23e0d965a056d56
parent1d202008d8008681988effdf25be2c6a753cf067

rework std.math.big.Int

Now there are 3 types: * std.math.big.int.Const - the memory is immutable, only stores limbs and is_positive - all methods operating on constant data go here * std.math.big.int.Mutable - the memory is mutable, stores capacity in addition to limbs and is_positive - methods here have some Mutable parameters and some Const parameters. These methods expect callers to pre-calculate the amount of resources required, and asserts that the resources are available. * std.math.big.int.Managed - the memory is mutable and additionally stores an allocator. - methods here perform the resource calculations for the programmer. - this is the high level abstraction from before Each of these 3 types can be converted to the other ones. You can see the use case for this in the self-hosted compiler, where we only store limbs, and construct the big ints as needed. This gets rid of the hack where the allocator was optional and the notion of "fixed" versions of the struct. Such things are now modeled with the `big.int.Const` type.

10 files changed, 3341 insertions(+), 2663 deletions(-)

lib/std/fmt.zig+1-1
......@@ -1058,7 +1058,7 @@ pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
10581058 return value;
10591059}
10601060
1061fn digitToChar(digit: u8, uppercase: bool) u8 {
1061pub fn digitToChar(digit: u8, uppercase: bool) u8 {
10621062 return switch (digit) {
10631063 0...9 => digit + '0',
10641064 10...35 => digit + ((if (uppercase) @as(u8, 'A') else @as(u8, 'a')) - 10),
lib/std/math/big.zig+22-5
......@@ -1,7 +1,24 @@
1pub usingnamespace @import("big/int.zig");
2pub usingnamespace @import("big/rational.zig");
1const std = @import("../std.zig");
2const assert = std.debug.assert;
33
4test "math.big" {
5 _ = @import("big/int.zig");
6 _ = @import("big/rational.zig");
4pub const Rational = @import("big/rational.zig").Rational;
5pub const int = @import("big/int.zig");
6pub const Limb = usize;
7pub const DoubleLimb = std.meta.IntType(false, 2 * Limb.bit_count);
8pub const SignedDoubleLimb = std.meta.IntType(true, DoubleLimb.bit_count);
9pub const Log2Limb = std.math.Log2Int(Limb);
10
11comptime {
12 assert(std.math.floorPowerOfTwo(usize, Limb.bit_count) == Limb.bit_count);
13 assert(Limb.bit_count <= 64); // u128 set is unsupported
14 assert(Limb.is_signed == false);
15}
16
17test "" {
18 _ = int;
19 _ = Rational;
20 _ = Limb;
21 _ = DoubleLimb;
22 _ = SignedDoubleLimb;
23 _ = Log2Limb;
724}
lib/std/math/big/int.zig+1671-2526
......@@ -1,298 +1,196 @@
11const std = @import("../../std.zig");
2const debug = std.debug;
3const testing = std.testing;
42const math = std.math;
3const Limb = std.math.big.Limb;
4const DoubleLimb = std.math.big.DoubleLimb;
5const SignedDoubleLimb = std.math.big.SignedDoubleLimb;
6const Log2Limb = std.math.big.Log2Limb;
7const Allocator = std.mem.Allocator;
58const mem = std.mem;
6const Allocator = mem.Allocator;
7const ArrayList = std.ArrayList;
89const maxInt = std.math.maxInt;
910const minInt = std.math.minInt;
11const assert = std.debug.assert;
1012
11pub const Limb = usize;
12pub const DoubleLimb = std.meta.Int(false, 2 * Limb.bit_count);
13pub const SignedDoubleLimb = std.meta.Int(true, DoubleLimb.bit_count);
14pub const Log2Limb = math.Log2Int(Limb);
13/// Returns the number of limbs needed to store `scalar`, which must be a
14/// primitive integer value.
15pub fn calcLimbLen(scalar: var) usize {
16 const T = @TypeOf(scalar);
17 switch (@typeInfo(T)) {
18 .Int => |info| {
19 const UT = if (info.is_signed) std.meta.IntType(false, info.bits - 1) else T;
20 return @sizeOf(UT) / @sizeOf(Limb);
21 },
22 .ComptimeInt => {
23 const w_value = if (scalar < 0) -scalar else scalar;
24 return @divFloor(math.log2(w_value), Limb.bit_count) + 1;
25 },
26 else => @compileError("parameter must be a primitive integer type"),
27 }
28}
1529
16comptime {
17 debug.assert(math.floorPowerOfTwo(usize, Limb.bit_count) == Limb.bit_count);
18 debug.assert(Limb.bit_count <= 64); // u128 set is unsupported
19 debug.assert(Limb.is_signed == false);
30pub fn calcToStringLimbsBufferLen(a_len: usize, base: u8) usize {
31 if (math.isPowerOfTwo(base))
32 return 0;
33 return a_len + 2 + a_len + calcDivLimbsBufferLen(a_len, 1);
2034}
2135
22/// An arbitrary-precision big integer.
23///
24/// Memory is allocated by an Int as needed to ensure operations never overflow. The range of an
25/// Int is bounded only by available memory.
26pub const Int = struct {
27 const sign_bit: usize = 1 << (usize.bit_count - 1);
36pub fn calcDivLimbsBufferLen(a_len: usize, b_len: usize) usize {
37 return calcMulLimbsBufferLen(a_len, b_len, 2) * 4;
38}
2839
29 /// Default number of limbs to allocate on creation of an Int.
30 pub const default_capacity = 4;
40pub fn calcMulLimbsBufferLen(a_len: usize, b_len: usize, aliases: usize) usize {
41 return aliases * math.max(a_len, b_len);
42}
43
44pub fn calcSetStringLimbsBufferLen(base: u8, string_len: usize) usize {
45 const limb_count = calcSetStringLimbCount(base, string_len);
46 return calcMulLimbsBufferLen(limb_count, limb_count, 2);
47}
3148
32 /// Allocator used by the Int when requesting memory.
33 allocator: ?*Allocator,
49pub fn calcSetStringLimbCount(base: u8, string_len: usize) usize {
50 return (string_len + (Limb.bit_count / base - 1)) / (Limb.bit_count / base);
51}
52
53/// a + b * c + *carry, sets carry to the overflow bits
54pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb {
55 @setRuntimeSafety(false);
56 var r1: Limb = undefined;
57
58 // r1 = a + *carry
59 const c1: Limb = @boolToInt(@addWithOverflow(Limb, a, carry.*, &r1));
60
61 // r2 = b * c
62 const bc = @as(DoubleLimb, math.mulWide(Limb, b, c));
63 const r2 = @truncate(Limb, bc);
64 const c2 = @truncate(Limb, bc >> Limb.bit_count);
65
66 // r1 = r1 + r2
67 const c3: Limb = @boolToInt(@addWithOverflow(Limb, r1, r2, &r1));
68
69 // This never overflows, c1, c3 are either 0 or 1 and if both are 1 then
70 // c2 is at least <= maxInt(Limb) - 2.
71 carry.* = c1 + c2 + c3;
72
73 return r1;
74}
3475
76/// A arbitrary-precision big integer, with a fixed set of mutable limbs.
77pub const Mutable = struct {
3578 /// Raw digits. These are:
3679 ///
3780 /// * Little-endian ordered
3881 /// * limbs.len >= 1
39 /// * Zero is represent as Int.len() == 1 with limbs[0] == 0.
82 /// * Zero is represented as limbs.len == 1 with limbs[0] == 0.
4083 ///
4184 /// Accessing limbs directly should be avoided.
85 /// These are allocated limbs; the `len` field tells the valid range.
4286 limbs: []Limb,
87 len: usize,
88 positive: bool,
4389
44 /// High bit is the sign bit. If set, Int is negative, else Int is positive.
45 /// The remaining bits represent the number of limbs used by Int.
46 metadata: usize,
47
48 /// Creates a new Int. default_capacity limbs will be allocated immediately.
49 /// Int will be zeroed.
50 pub fn init(allocator: *Allocator) !Int {
51 return try Int.initCapacity(allocator, default_capacity);
52 }
53
54 /// Creates a new Int. Int will be set to `value`.
55 ///
56 /// This is identical to an `init`, followed by a `set`.
57 pub fn initSet(allocator: *Allocator, value: var) !Int {
58 var s = try Int.init(allocator);
59 try s.set(value);
60 return s;
61 }
62
63 /// Hint: use `calcLimbLen` to figure out how big an array to allocate for `limbs`.
64 pub fn initSetFixed(limbs: []Limb, value: var) Int {
65 mem.set(Limb, limbs, 0);
66 var s = Int.initFixed(limbs);
67 s.set(value) catch unreachable;
68 return s;
69 }
70
71 /// Creates a new Int with a specific capacity. If capacity < default_capacity then the
72 /// default capacity will be used instead.
73 pub fn initCapacity(allocator: *Allocator, capacity: usize) !Int {
74 return Int{
75 .allocator = allocator,
76 .metadata = 1,
77 .limbs = block: {
78 var limbs = try allocator.alloc(Limb, math.max(default_capacity, capacity));
79 limbs[0] = 0;
80 break :block limbs;
81 },
90 pub fn toConst(self: Mutable) Const {
91 return .{
92 .limbs = self.limbs[0..self.len],
93 .positive = self.positive,
8294 };
8395 }
8496
85 /// Returns the number of limbs currently in use.
86 pub fn len(self: Int) usize {
87 return self.metadata & ~sign_bit;
88 }
89
90 /// Returns whether an Int is positive.
91 pub fn isPositive(self: Int) bool {
92 return self.metadata & sign_bit == 0;
93 }
94
95 /// Sets the sign of an Int.
96 pub fn setSign(self: *Int, positive: bool) void {
97 if (positive) {
98 self.metadata &= ~sign_bit;
99 } else {
100 self.metadata |= sign_bit;
101 }
102 }
103
104 /// Sets the length of an Int.
105 ///
106 /// If setLen is used, then the Int must be normalized to suit.
107 pub fn setLen(self: *Int, new_len: usize) void {
108 self.metadata &= sign_bit;
109 self.metadata |= new_len;
110 }
111
112 /// Returns an Int backed by a fixed set of limb values.
113 /// This is read-only and cannot be used as a result argument. If the Int tries to allocate
114 /// memory a runtime panic will occur.
115 pub fn initFixed(limbs: []Limb) Int {
116 var self = Int{
117 .allocator = null,
118 .metadata = limbs.len,
97 /// Asserts that the allocator owns the limbs memory. If this is not the case,
98 /// use `toConst().toManaged()`.
99 pub fn toManaged(self: Mutable, allocator: *Allocator) Managed {
100 return .{
101 .allocator = allocator,
119102 .limbs = limbs,
103 .metadata = if (self.positive)
104 self.len & ~Managed.sign_bit
105 else
106 self.len | Managed.sign_bit,
120107 };
121
122 self.normalize(limbs.len);
123 return self;
124 }
125
126 /// Ensures an Int has enough space allocated for capacity limbs. If the Int does not have
127 /// sufficient capacity, the exact amount will be allocated. This occurs even if the requested
128 /// capacity is only greater than the current capacity by one limb.
129 pub fn ensureCapacity(self: *Int, capacity: usize) !void {
130 if (capacity <= self.limbs.len) {
131 return;
132 }
133 self.assertWritable();
134 self.limbs = try self.allocator.?.realloc(self.limbs, capacity);
135 }
136
137 fn assertWritable(self: Int) void {
138 if (self.allocator == null) {
139 @panic("provided Int value is read-only but must be writable");
140 }
141 }
142
143 /// Frees all memory associated with an Int.
144 pub fn deinit(self: Int) void {
145 self.assertWritable();
146 self.allocator.?.free(self.limbs);
147 }
148
149 /// Clones an Int and returns a new Int with the same value. The new Int is a deep copy and
150 /// can be modified separately from the original.
151 pub fn clone(other: Int) !Int {
152 return other.clone2(other.allocator.?);
153108 }
154109
155 pub fn clone2(other: Int, allocator: *Allocator) !Int {
156 return Int{
157 .allocator = allocator,
158 .metadata = other.metadata,
159 .limbs = block: {
160 var limbs = try allocator.alloc(Limb, other.len());
161 mem.copy(Limb, limbs[0..], other.limbs[0..other.len()]);
162 break :block limbs;
163 },
110 /// `value` is a primitive integer type.
111 /// Asserts the value fits within the provided `limbs_buffer`.
112 /// Note: `calcLimbLen` can be used to figure out how big an array to allocate for `limbs_buffer`.
113 pub fn init(limbs_buffer: []Limb, value: var) Mutable {
114 limbs_buffer[0] = 0;
115 var self: Mutable = .{
116 .limbs = limbs_buffer,
117 .len = 1,
118 .positive = true,
164119 };
120 self.set(value);
121 return self;
165122 }
166123
167 /// Copies the value of an Int to an existing Int so that they both have the same value.
168 /// Extra memory will be allocated if the receiver does not have enough capacity.
169 pub fn copy(self: *Int, other: Int) !void {
170 self.assertWritable();
171 if (self.limbs.ptr == other.limbs.ptr) {
172 return;
124 /// Copies the value of a Const to an existing Mutable so that they both have the same value.
125 /// Asserts the value fits in the limbs buffer.
126 pub fn copy(self: *Mutable, other: Const) void {
127 if (self.limbs.ptr != other.limbs.ptr) {
128 mem.copy(Limb, self.limbs[0..], other.limbs[0..other.limbs.len]);
173129 }
174
175 try self.ensureCapacity(other.len());
176 mem.copy(Limb, self.limbs[0..], other.limbs[0..other.len()]);
177 self.metadata = other.metadata;
130 self.positive = other.positive;
131 self.len = other.limbs.len;
178132 }
179133
180 /// Efficiently swap an Int with another. This swaps the limb pointers and a full copy is not
134 /// Efficiently swap an Mutable with another. This swaps the limb pointers and a full copy is not
181135 /// performed. The address of the limbs field will not be the same after this function.
182 pub fn swap(self: *Int, other: *Int) void {
183 self.assertWritable();
184 mem.swap(Int, self, other);
185 }
186
187 pub fn dump(self: Int) void {
188 for (self.limbs) |limb| {
189 debug.warn("{x} ", .{limb});
190 }
191 debug.warn("\n", .{});
192 }
193
194 /// Negate the sign of an Int.
195 pub fn negate(self: *Int) void {
196 self.metadata ^= sign_bit;
197 }
198
199 /// Make an Int positive.
200 pub fn abs(self: *Int) void {
201 self.metadata &= ~sign_bit;
202 }
203
204 /// Returns true if an Int is odd.
205 pub fn isOdd(self: Int) bool {
206 return self.limbs[0] & 1 != 0;
136 pub fn swap(self: *Mutable, other: *Mutable) void {
137 mem.swap(Mutable, self, other);
207138 }
208139
209 /// Returns true if an Int is even.
210 pub fn isEven(self: Int) bool {
211 return !self.isOdd();
212 }
213
214 /// Returns the number of bits required to represent the absolute value an Int.
215 fn bitCountAbs(self: Int) usize {
216 return (self.len() - 1) * Limb.bit_count + (Limb.bit_count - @clz(Limb, self.limbs[self.len() - 1]));
217 }
218
219 /// Returns the number of bits required to represent the integer in twos-complement form.
220 ///
221 /// If the integer is negative the value returned is the number of bits needed by a signed
222 /// integer to represent the value. If positive the value is the number of bits for an
223 /// unsigned integer. Any unsigned integer will fit in the signed integer with bitcount
224 /// one greater than the returned value.
225 ///
226 /// e.g. -127 returns 8 as it will fit in an i8. 127 returns 7 since it fits in a u7.
227 pub fn bitCountTwosComp(self: Int) usize {
228 var bits = self.bitCountAbs();
229
230 // If the entire value has only one bit set (e.g. 0b100000000) then the negation in twos
231 // complement requires one less bit.
232 if (!self.isPositive()) block: {
233 bits += 1;
234
235 if (@popCount(Limb, self.limbs[self.len() - 1]) == 1) {
236 for (self.limbs[0 .. self.len() - 1]) |limb| {
237 if (@popCount(Limb, limb) != 0) {
238 break :block;
239 }
240 }
241
242 bits -= 1;
243 }
140 pub fn dump(self: Mutable) void {
141 for (self.limbs[0..self.len]) |limb| {
142 std.debug.warn("{x} ", .{limb});
244143 }
245
246 return bits;
144 std.debug.warn("capacity={} positive={}\n", .{ self.limbs.len, self.positive });
247145 }
248146
249 pub fn fitsInTwosComp(self: Int, is_signed: bool, bit_count: usize) bool {
250 if (self.eqZero()) {
251 return true;
252 }
253 if (!is_signed and !self.isPositive()) {
254 return false;
255 }
256
257 const req_bits = self.bitCountTwosComp() + @boolToInt(self.isPositive() and is_signed);
258 return bit_count >= req_bits;
147 /// Clones an Mutable and returns a new Mutable with the same value. The new Mutable is a deep copy and
148 /// can be modified separately from the original.
149 /// Asserts that limbs is big enough to store the value.
150 pub fn clone(other: Mutable, limbs: []Limb) Mutable {
151 mem.copy(Limb, limbs, other.limbs[0..other.len]);
152 return .{
153 .limbs = limbs,
154 .len = other.len,
155 .positive = other.positive,
156 };
259157 }
260158
261 /// Returns whether self can fit into an integer of the requested type.
262 pub fn fits(self: Int, comptime T: type) bool {
263 return self.fitsInTwosComp(T.is_signed, T.bit_count);
159 pub fn negate(self: *Mutable) void {
160 self.positive = !self.positive;
264161 }
265162
266 /// Returns the approximate size of the integer in the given base. Negative values accommodate for
267 /// the minus sign. This is used for determining the number of characters needed to print the
268 /// value. It is inexact and may exceed the given value by ~1-2 bytes.
269 pub fn sizeInBase(self: Int, base: usize) usize {
270 const bit_count = @as(usize, @boolToInt(!self.isPositive())) + self.bitCountAbs();
271 return (bit_count / math.log2(base)) + 1;
163 /// Modify to become the absolute value
164 pub fn abs(self: *Mutable) void {
165 self.positive = true;
272166 }
273167
274 /// Sets an Int to value. Value must be an primitive integer type.
275 pub fn set(self: *Int, value: var) Allocator.Error!void {
168 /// Sets the Mutable to value. Value must be an primitive integer type.
169 /// Asserts the value fits within the limbs buffer.
170 /// Note: `calcLimbLen` can be used to figure out how big the limbs buffer
171 /// needs to be to store a specific value.
172 pub fn set(self: *Mutable, value: var) void {
276173 const T = @TypeOf(value);
277174
278175 switch (@typeInfo(T)) {
279176 .Int => |info| {
280 const UT = if (T.is_signed) std.meta.Int(false, T.bit_count - 1) else T;
177 const UT = if (T.is_signed) std.meta.IntType(false, T.bit_count - 1) else T;
281178
282 try self.ensureCapacity(@sizeOf(UT) / @sizeOf(Limb));
283 self.metadata = 0;
284 self.setSign(value >= 0);
179 const needed_limbs = @sizeOf(UT) / @sizeOf(Limb);
180 assert(needed_limbs <= self.limbs.len); // value too big
181 self.len = 0;
182 self.positive = value >= 0;
285183
286184 var w_value: UT = if (value < 0) @intCast(UT, -value) else @intCast(UT, value);
287185
288186 if (info.bits <= Limb.bit_count) {
289187 self.limbs[0] = @as(Limb, w_value);
290 self.metadata += 1;
188 self.len += 1;
291189 } else {
292190 var i: usize = 0;
293191 while (w_value != 0) : (i += 1) {
294192 self.limbs[i] = @truncate(Limb, w_value);
295 self.metadata += 1;
193 self.len += 1;
296194
297195 // TODO: shift == 64 at compile-time fails. Fails on u128 limbs.
298196 w_value >>= Limb.bit_count / 2;
......@@ -304,10 +202,10 @@ pub const Int = struct {
304202 comptime var w_value = if (value < 0) -value else value;
305203
306204 const req_limbs = @divFloor(math.log2(w_value), Limb.bit_count) + 1;
307 try self.ensureCapacity(req_limbs);
205 assert(req_limbs <= self.limbs.len); // value too big
308206
309 self.metadata = req_limbs;
310 self.setSign(value >= 0);
207 self.len = req_limbs;
208 self.positive = value >= 0;
311209
312210 if (w_value <= maxInt(Limb)) {
313211 self.limbs[0] = w_value;
......@@ -323,83 +221,8 @@ pub const Int = struct {
323221 }
324222 }
325223 },
326 else => {
327 @compileError("cannot set Int using type " ++ @typeName(T));
328 },
329 }
330 }
331
332 pub const ConvertError = error{
333 NegativeIntoUnsigned,
334 TargetTooSmall,
335 };
336
337 /// Convert self to type T.
338 ///
339 /// Returns an error if self cannot be narrowed into the requested type without truncation.
340 pub fn to(self: Int, comptime T: type) ConvertError!T {
341 switch (@typeInfo(T)) {
342 .Int => {
343 const UT = std.meta.Int(false, T.bit_count);
344
345 if (self.bitCountTwosComp() > T.bit_count) {
346 return error.TargetTooSmall;
347 }
348
349 var r: UT = 0;
350
351 if (@sizeOf(UT) <= @sizeOf(Limb)) {
352 r = @intCast(UT, self.limbs[0]);
353 } else {
354 for (self.limbs[0..self.len()]) |_, ri| {
355 const limb = self.limbs[self.len() - ri - 1];
356 r <<= Limb.bit_count;
357 r |= limb;
358 }
359 }
360
361 if (!T.is_signed) {
362 return if (self.isPositive()) @intCast(T, r) else error.NegativeIntoUnsigned;
363 } else {
364 if (self.isPositive()) {
365 return @intCast(T, r);
366 } else {
367 if (math.cast(T, r)) |ok| {
368 return -ok;
369 } else |_| {
370 return minInt(T);
371 }
372 }
373 }
374 },
375 else => {
376 @compileError("cannot convert Int to type " ++ @typeName(T));
377 },
378 }
379 }
380
381 fn charToDigit(ch: u8, base: u8) !u8 {
382 const d = switch (ch) {
383 '0'...'9' => ch - '0',
384 'a'...'f' => (ch - 'a') + 0xa,
385 'A'...'F' => (ch - 'A') + 0xa,
386 else => return error.InvalidCharForDigit,
387 };
388
389 return if (d < base) d else return error.DigitTooLargeForBase;
390 }
391
392 fn digitToChar(d: u8, base: u8, uppercase: bool) !u8 {
393 if (d >= base) {
394 return error.DigitTooLargeForBase;
224 else => @compileError("cannot set Mutable using type " ++ @typeName(T)),
395225 }
396
397 const a: u8 = if (uppercase) 'A' else 'a';
398 return switch (d) {
399 0...9 => '0' + d,
400 0xa...0xf => (a - 0xa) + d,
401 else => unreachable,
402 };
403226 }
404227
405228 /// Set self from the string representation `value`.
......@@ -408,13 +231,25 @@ pub const Int = struct {
408231 /// not allowed (e.g. 0x43 should simply be 43). Underscores in the input string are
409232 /// ignored and can be used as digit separators.
410233 ///
411 /// Returns an error if memory could not be allocated or `value` has invalid digits for the
412 /// requested base.
413 pub fn setString(self: *Int, base: u8, value: []const u8) !void {
414 self.assertWritable();
415 if (base < 2 or base > 16) {
416 return error.InvalidBase;
417 }
234 /// Asserts there is enough memory for the value in `self.limbs`. An upper bound on number of limbs can
235 /// be determined with `calcSetStringLimbCount`.
236 /// Asserts the base is in the range [2, 16].
237 ///
238 /// Returns an error if the value has invalid digits for the requested base.
239 ///
240 /// `limbs_buffer` is used for temporary storage. The size required can be found with
241 /// `calcSetStringLimbsBufferLen`.
242 ///
243 /// If `allocator` is provided, it will be used for temporary storage to improve
244 /// multiplication performance. `error.OutOfMemory` is handled with a fallback algorithm.
245 pub fn setString(
246 self: *Mutable,
247 base: u8,
248 value: []const u8,
249 limbs_buffer: []Limb,
250 allocator: ?*Allocator,
251 ) error{InvalidCharacter}!void {
252 assert(base >= 2 and base <= 16);
418253
419254 var i: usize = 0;
420255 var positive = true;
......@@ -423,787 +258,561 @@ pub const Int = struct {
423258 i += 1;
424259 }
425260
426 const ap_base = Int.initFixed(([_]Limb{base})[0..]);
427 try self.set(0);
261 const ap_base: Const = .{ .limbs = &[_]Limb{base}, .positive = true };
262 self.set(0);
428263
429264 for (value[i..]) |ch| {
430265 if (ch == '_') {
431266 continue;
432267 }
433 const d = try charToDigit(ch, base);
268 const d = try std.fmt.charToDigit(ch, base);
269 const ap_d: Const = .{ .limbs = &[_]Limb{d}, .positive = true };
434270
435 const ap_d = Int.initFixed(([_]Limb{d})[0..]);
436
437 try self.mul(self.*, ap_base);
438 try self.add(self.*, ap_d);
271 self.mul(self.toConst(), ap_base, limbs_buffer, allocator);
272 self.add(self.toConst(), ap_d);
439273 }
440 self.setSign(positive);
274 self.positive = positive;
441275 }
442276
443 /// Converts self to a string in the requested base. Memory is allocated from the provided
444 /// allocator and not the one present in self.
445 /// TODO make this call format instead of the other way around
446 pub fn toString(self: Int, allocator: *Allocator, base: u8, uppercase: bool) ![]const u8 {
447 if (base < 2 or base > 16) {
448 return error.InvalidBase;
449 }
450
451 var digits = ArrayList(u8).init(allocator);
452 try digits.ensureCapacity(self.sizeInBase(base) + 1);
453 defer digits.deinit();
277 /// r = a + scalar
278 ///
279 /// r and a may be aliases.
280 /// scalar is a primitive integer type.
281 ///
282 /// Asserts the result fits in `r`. An upper bound on the number of limbs needed by
283 /// r is `math.max(a.limbs.len, calcLimbLen(scalar)) + 1`.
284 pub fn addScalar(r: *Mutable, a: Const, scalar: var) void {
285 var limbs: [calcLimbLen(scalar)]Limb = undefined;
286 const operand = init(&limbs, scalar).toConst();
287 return add(r, a, operand);
288 }
454289
455 if (self.eqZero()) {
456 try digits.append('0');
457 return digits.toOwnedSlice();
290 /// r = a + b
291 ///
292 /// r, a and b may be aliases.
293 ///
294 /// Asserts the result fits in `r`. An upper bound on the number of limbs needed by
295 /// r is `math.max(a.limbs.len, b.limbs.len) + 1`.
296 pub fn add(r: *Mutable, a: Const, b: Const) void {
297 if (a.eqZero()) {
298 r.copy(b);
299 return;
300 } else if (b.eqZero()) {
301 r.copy(a);
302 return;
458303 }
459304
460 // Power of two: can do a single pass and use masks to extract digits.
461 if (math.isPowerOfTwo(base)) {
462 const base_shift = math.log2_int(Limb, base);
463
464 for (self.limbs[0..self.len()]) |limb| {
465 var shift: usize = 0;
466 while (shift < Limb.bit_count) : (shift += base_shift) {
467 const r = @intCast(u8, (limb >> @intCast(Log2Limb, shift)) & @as(Limb, base - 1));
468 const ch = try digitToChar(r, base, uppercase);
469 try digits.append(ch);
470 }
305 if (a.limbs.len == 1 and b.limbs.len == 1 and a.positive == b.positive) {
306 if (!@addWithOverflow(Limb, a.limbs[0], b.limbs[0], &r.limbs[0])) {
307 r.len = 1;
308 r.positive = a.positive;
309 return;
471310 }
311 }
472312
473 while (true) {
474 // always will have a non-zero digit somewhere
475 const c = digits.pop();
476 if (c != '0') {
477 digits.append(c) catch unreachable;
478 break;
479 }
313 if (a.positive != b.positive) {
314 if (a.positive) {
315 // (a) + (-b) => a - b
316 r.sub(a, b.abs());
317 } else {
318 // (-a) + (b) => b - a
319 r.sub(b, a.abs());
480320 }
481321 } else {
482 // Non power-of-two: batch divisions per word size.
483 const digits_per_limb = math.log(Limb, base, maxInt(Limb));
484 var limb_base: Limb = 1;
485 var j: usize = 0;
486 while (j < digits_per_limb) : (j += 1) {
487 limb_base *= base;
322 if (a.limbs.len >= b.limbs.len) {
323 lladd(r.limbs[0..], a.limbs[0..a.limbs.len], b.limbs[0..b.limbs.len]);
324 r.normalize(a.limbs.len + 1);
325 } else {
326 lladd(r.limbs[0..], b.limbs[0..b.limbs.len], a.limbs[0..a.limbs.len]);
327 r.normalize(b.limbs.len + 1);
488328 }
489329
490 var q = try self.clone2(allocator);
491 defer q.deinit();
492 q.abs();
493 var r = try Int.init(allocator);
494 defer r.deinit();
495 var b = try Int.initSet(allocator, limb_base);
496 defer b.deinit();
497
498 while (q.len() >= 2) {
499 try Int.divTrunc(&q, &r, q, b);
330 r.positive = a.positive;
331 }
332 }
500333
501 var r_word = r.limbs[0];
502 var i: usize = 0;
503 while (i < digits_per_limb) : (i += 1) {
504 const ch = try digitToChar(@intCast(u8, r_word % base), base, uppercase);
505 r_word /= base;
506 try digits.append(ch);
507 }
334 /// r = a - b
335 ///
336 /// r, a and b may be aliases.
337 ///
338 /// Asserts the result fits in `r`. An upper bound on the number of limbs needed by
339 /// r is `math.max(a.limbs.len, b.limbs.len) + 1`. The +1 is not needed if both operands are positive.
340 pub fn sub(r: *Mutable, a: Const, b: Const) void {
341 if (a.positive != b.positive) {
342 if (a.positive) {
343 // (a) - (-b) => a + b
344 r.add(a, b.abs());
345 } else {
346 // (-a) - (b) => -(a + b)
347 r.add(a.abs(), b);
348 r.positive = false;
508349 }
509
510 {
511 debug.assert(q.len() == 1);
512
513 var r_word = q.limbs[0];
514 while (r_word != 0) {
515 const ch = try digitToChar(@intCast(u8, r_word % base), base, uppercase);
516 r_word /= base;
517 try digits.append(ch);
350 } else {
351 if (a.positive) {
352 // (a) - (b) => a - b
353 if (a.order(b) != .lt) {
354 llsub(r.limbs[0..], a.limbs[0..a.limbs.len], b.limbs[0..b.limbs.len]);
355 r.normalize(a.limbs.len);
356 r.positive = true;
357 } else {
358 llsub(r.limbs[0..], b.limbs[0..b.limbs.len], a.limbs[0..a.limbs.len]);
359 r.normalize(b.limbs.len);
360 r.positive = false;
361 }
362 } else {
363 // (-a) - (-b) => -(a - b)
364 if (a.order(b) == .lt) {
365 llsub(r.limbs[0..], a.limbs[0..a.limbs.len], b.limbs[0..b.limbs.len]);
366 r.normalize(a.limbs.len);
367 r.positive = false;
368 } else {
369 llsub(r.limbs[0..], b.limbs[0..b.limbs.len], a.limbs[0..a.limbs.len]);
370 r.normalize(b.limbs.len);
371 r.positive = true;
518372 }
519373 }
520374 }
521
522 if (!self.isPositive()) {
523 try digits.append('-');
524 }
525
526 var s = digits.toOwnedSlice();
527 mem.reverse(u8, s);
528 return s;
529375 }
530376
531 /// To allow `std.fmt.printf` to work with Int.
532 /// TODO make this non-allocating
533 /// TODO support read-only fixed integers
534 pub fn format(
535 self: Int,
536 comptime fmt: []const u8,
537 options: std.fmt.FormatOptions,
538 out_stream: var,
539 ) !void {
540 comptime var radix = 10;
541 comptime var uppercase = false;
542
543 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "d")) {
544 radix = 10;
545 uppercase = false;
546 } else if (comptime std.mem.eql(u8, fmt, "b")) {
547 radix = 2;
548 uppercase = false;
549 } else if (comptime std.mem.eql(u8, fmt, "x")) {
550 radix = 16;
551 uppercase = false;
552 } else if (comptime std.mem.eql(u8, fmt, "X")) {
553 radix = 16;
554 uppercase = true;
555 } else {
556 @compileError("Unknown format string: '" ++ fmt ++ "'");
557 }
558
559 var buf: [4096]u8 = undefined;
560 var fba = std.heap.FixedBufferAllocator.init(&buf);
561 const str = self.toString(&fba.allocator, radix, uppercase) catch @panic("TODO make this non allocating");
562 return out_stream.writeAll(str);
563 }
377 /// rma = a * b
378 ///
379 /// `rma` may alias with `a` or `b`.
380 /// `a` and `b` may alias with each other.
381 ///
382 /// Asserts the result fits in `rma`. An upper bound on the number of limbs needed by
383 /// rma is given by `a.limbs.len + b.limbs.len + 1`.
384 ///
385 /// `limbs_buffer` is used for temporary storage. The amount required is given by `calcMulLimbsBufferLen`.
386 pub fn mul(rma: *Mutable, a: Const, b: Const, limbs_buffer: []Limb, allocator: ?*Allocator) void {
387 var buf_index: usize = 0;
564388
565 /// Returns math.Order.lt, math.Order.eq, math.Order.gt if |a| < |b|, |a| ==
566 /// |b| or |a| > |b| respectively.
567 pub fn cmpAbs(a: Int, b: Int) math.Order {
568 if (a.len() < b.len()) {
569 return .lt;
570 }
571 if (a.len() > b.len()) {
572 return .gt;
573 }
389 const a_copy = if (rma.limbs.ptr == a.limbs.ptr) blk: {
390 const start = buf_index;
391 mem.copy(Limb, limbs_buffer[buf_index..], a.limbs);
392 buf_index += a.limbs.len;
393 break :blk a.toMutable(limbs_buffer[start..buf_index]).toConst();
394 } else a;
574395
575 var i: usize = a.len() - 1;
576 while (i != 0) : (i -= 1) {
577 if (a.limbs[i] != b.limbs[i]) {
578 break;
579 }
580 }
396 const b_copy = if (rma.limbs.ptr == b.limbs.ptr) blk: {
397 const start = buf_index;
398 mem.copy(Limb, limbs_buffer[buf_index..], b.limbs);
399 buf_index += b.limbs.len;
400 break :blk b.toMutable(limbs_buffer[start..buf_index]).toConst();
401 } else b;
581402
582 if (a.limbs[i] < b.limbs[i]) {
583 return .lt;
584 } else if (a.limbs[i] > b.limbs[i]) {
585 return .gt;
586 } else {
587 return .eq;
588 }
403 return rma.mulNoAlias(a_copy, b_copy, allocator);
589404 }
590405
591 /// Returns math.Order.lt, math.Order.eq, math.Order.gt if a < b, a == b or a
592 /// > b respectively.
593 pub fn cmp(a: Int, b: Int) math.Order {
594 if (a.isPositive() != b.isPositive()) {
595 return if (a.isPositive()) .gt else .lt;
596 } else {
597 const r = cmpAbs(a, b);
598 return if (a.isPositive()) r else switch (r) {
599 .lt => math.Order.gt,
600 .eq => math.Order.eq,
601 .gt => math.Order.lt,
602 };
406 /// rma = a * b
407 ///
408 /// `rma` may not alias with `a` or `b`.
409 /// `a` and `b` may alias with each other.
410 ///
411 /// Asserts the result fits in `rma`. An upper bound on the number of limbs needed by
412 /// rma is given by `a.limbs.len + b.limbs.len + 1`.
413 ///
414 /// If `allocator` is provided, it will be used for temporary storage to improve
415 /// multiplication performance. `error.OutOfMemory` is handled with a fallback algorithm.
416 pub fn mulNoAlias(rma: *Mutable, a: Const, b: Const, allocator: ?*Allocator) void {
417 assert(rma.limbs.ptr != a.limbs.ptr); // illegal aliasing
418 assert(rma.limbs.ptr != b.limbs.ptr); // illegal aliasing
419
420 if (a.limbs.len == 1 and b.limbs.len == 1) {
421 if (!@mulWithOverflow(Limb, a.limbs[0], b.limbs[0], &rma.limbs[0])) {
422 rma.len = 1;
423 rma.positive = (a.positive == b.positive);
424 return;
425 }
603426 }
604 }
605
606 /// Same as `cmp` but the right-hand operand is a primitive integer.
607 pub fn orderAgainstScalar(lhs: Int, scalar: var) math.Order {
608 var limbs: [calcLimbLen(scalar)]Limb = undefined;
609 const rhs = initSetFixed(&limbs, scalar);
610 return cmp(lhs, rhs);
611 }
612
613 /// Returns true if a == 0.
614 pub fn eqZero(a: Int) bool {
615 return a.len() == 1 and a.limbs[0] == 0;
616 }
617
618 /// Returns true if |a| == |b|.
619 pub fn eqAbs(a: Int, b: Int) bool {
620 return cmpAbs(a, b) == .eq;
621 }
622427
623 /// Returns true if a == b.
624 pub fn eq(a: Int, b: Int) bool {
625 return cmp(a, b) == .eq;
626 }
428 mem.set(Limb, rma.limbs[0 .. a.limbs.len + b.limbs.len + 1], 0);
627429
628 // Normalize a possible sequence of leading zeros.
629 //
630 // [1, 2, 3, 4, 0] -> [1, 2, 3, 4]
631 // [1, 2, 0, 0, 0] -> [1, 2]
632 // [0, 0, 0, 0, 0] -> [0]
633 fn normalize(r: *Int, length: usize) void {
634 debug.assert(length > 0);
635 debug.assert(length <= r.limbs.len);
636
637 var j = length;
638 while (j > 0) : (j -= 1) {
639 if (r.limbs[j - 1] != 0) {
640 break;
641 }
642 }
430 llmulacc(allocator, rma.limbs, a.limbs, b.limbs);
643431
644 // Handle zero
645 r.setLen(if (j != 0) j else 1);
432 rma.normalize(a.limbs.len + b.limbs.len);
433 rma.positive = (a.positive == b.positive);
646434 }
647435
648 // Cannot be used as a result argument to any function.
649 fn readOnlyPositive(a: Int) Int {
650 return Int{
651 .allocator = null,
652 .metadata = a.len(),
653 .limbs = a.limbs,
654 };
655 }
436 /// q = a / b (rem r)
437 ///
438 /// a / b are floored (rounded towards 0).
439 /// q may alias with a or b.
440 ///
441 /// Asserts there is enough memory to store q and r.
442 /// The upper bound for r limb count is a.limbs.len.
443 /// The upper bound for q limb count is given by `a.limbs.len + b.limbs.len + 1`.
444 ///
445 /// If `allocator` is provided, it will be used for temporary storage to improve
446 /// multiplication performance. `error.OutOfMemory` is handled with a fallback algorithm.
447 ///
448 /// `limbs_buffer` is used for temporary storage. The amount required is given by `calcDivLimbsBufferLen`.
449 pub fn divFloor(
450 q: *Mutable,
451 r: *Mutable,
452 a: Const,
453 b: Const,
454 limbs_buffer: []Limb,
455 allocator: ?*Allocator,
456 ) void {
457 div(q, r, a, b, limbs_buffer, allocator);
656458
657 /// Returns the number of limbs needed to store `scalar`, which must be a
658 /// primitive integer value.
659 pub fn calcLimbLen(scalar: var) usize {
660 switch (@typeInfo(@TypeOf(scalar))) {
661 .Int => return @sizeOf(scalar) / @sizeOf(Limb),
662 .ComptimeInt => {
663 const w_value = if (scalar < 0) -scalar else scalar;
664 const req_limbs = @divFloor(math.log2(w_value), Limb.bit_count) + 1;
665 return req_limbs;
666 },
667 else => @compileError("parameter must be a primitive integer type"),
459 // Trunc -> Floor.
460 if (!q.positive) {
461 const one: Const = .{ .limbs = &[_]Limb{1}, .positive = true };
462 q.sub(q.toConst(), one);
463 r.add(q.toConst(), one);
668464 }
465 r.positive = b.positive;
669466 }
670467
671 /// r = a + scalar
468 /// q = a / b (rem r)
672469 ///
673 /// r and a may be aliases.
674 /// scalar is a primitive integer type.
470 /// a / b are truncated (rounded towards -inf).
471 /// q may alias with a or b.
675472 ///
676 /// Returns an error if memory could not be allocated.
677 pub fn addScalar(r: *Int, a: Int, scalar: var) Allocator.Error!void {
678 var limbs: [calcLimbLen(scalar)]Limb = undefined;
679 var operand = initFixed(&limbs);
680 operand.set(scalar) catch unreachable;
681 return add(r, a, operand);
473 /// Asserts there is enough memory to store q and r.
474 /// The upper bound for r limb count is a.limbs.len.
475 /// The upper bound for q limb count is given by `calcQuotientLimbLen`. This accounts
476 /// for temporary space used by the division algorithm.
477 ///
478 /// If `allocator` is provided, it will be used for temporary storage to improve
479 /// multiplication performance. `error.OutOfMemory` is handled with a fallback algorithm.
480 ///
481 /// `limbs_buffer` is used for temporary storage. The amount required is given by `calcDivLimbsBufferLen`.
482 pub fn divTrunc(
483 q: *Mutable,
484 r: *Mutable,
485 a: Const,
486 b: Const,
487 limbs_buffer: []Limb,
488 allocator: ?*Allocator,
489 ) void {
490 div(q, r, a, b, limbs_buffer, allocator);
491 r.positive = a.positive;
682492 }
683493
684 /// r = a + b
494 /// r = a << shift, in other words, r = a * 2^shift
685495 ///
686 /// r, a and b may be aliases.
496 /// r and a may alias.
687497 ///
688 /// Returns an error if memory could not be allocated.
689 pub fn add(r: *Int, a: Int, b: Int) Allocator.Error!void {
690 r.assertWritable();
691 if (a.eqZero()) {
692 try r.copy(b);
693 return;
694 } else if (b.eqZero()) {
695 try r.copy(a);
696 return;
697 }
698
699 if (a.isPositive() != b.isPositive()) {
700 if (a.isPositive()) {
701 // (a) + (-b) => a - b
702 try r.sub(a, readOnlyPositive(b));
703 } else {
704 // (-a) + (b) => b - a
705 try r.sub(b, readOnlyPositive(a));
706 }
707 } else {
708 if (a.len() >= b.len()) {
709 try r.ensureCapacity(a.len() + 1);
710 lladd(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]);
711 r.normalize(a.len() + 1);
712 } else {
713 try r.ensureCapacity(b.len() + 1);
714 lladd(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]);
715 r.normalize(b.len() + 1);
716 }
717
718 r.setSign(a.isPositive());
719 }
498 /// Asserts there is enough memory to fit the result. The upper bound Limb count is
499 /// `a.limbs.len + (shift / (@sizeOf(Limb) * 8))`.
500 pub fn shiftLeft(r: *Mutable, a: Const, shift: usize) void {
501 llshl(r.limbs[0..], a.limbs[0..a.limbs.len], shift);
502 r.normalize(a.limbs.len + (shift / Limb.bit_count) + 1);
503 r.positive = a.positive;
720504 }
721505
722 // Knuth 4.3.1, Algorithm A.
723 fn lladd(r: []Limb, a: []const Limb, b: []const Limb) void {
724 @setRuntimeSafety(false);
725 debug.assert(a.len != 0 and b.len != 0);
726 debug.assert(a.len >= b.len);
727 debug.assert(r.len >= a.len + 1);
728
729 var i: usize = 0;
730 var carry: Limb = 0;
731
732 while (i < b.len) : (i += 1) {
733 var c: Limb = 0;
734 c += @boolToInt(@addWithOverflow(Limb, a[i], b[i], &r[i]));
735 c += @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i]));
736 carry = c;
737 }
738
739 while (i < a.len) : (i += 1) {
740 carry = @boolToInt(@addWithOverflow(Limb, a[i], carry, &r[i]));
506 /// r = a >> shift
507 /// r and a may alias.
508 ///
509 /// Asserts there is enough memory to fit the result. The upper bound Limb count is
510 /// `a.limbs.len - (shift / (@sizeOf(Limb) * 8))`.
511 pub fn shiftRight(r: *Mutable, a: Const, shift: usize) void {
512 if (a.limbs.len <= shift / Limb.bit_count) {
513 r.len = 1;
514 r.positive = true;
515 r.limbs[0] = 0;
516 return;
741517 }
742518
743 r[i] = carry;
519 const r_len = llshr(r.limbs[0..], a.limbs[0..a.limbs.len], shift);
520 r.len = a.limbs.len - (shift / Limb.bit_count);
521 r.positive = a.positive;
744522 }
745523
746 /// r = a - b
524 /// r = a | b
525 /// r may alias with a or b.
747526 ///
748 /// r, a and b may be aliases.
527 /// a and b are zero-extended to the longer of a or b.
749528 ///
750 /// Returns an error if memory could not be allocated.
751 pub fn sub(r: *Int, a: Int, b: Int) !void {
752 r.assertWritable();
753 if (a.isPositive() != b.isPositive()) {
754 if (a.isPositive()) {
755 // (a) - (-b) => a + b
756 try r.add(a, readOnlyPositive(b));
757 } else {
758 // (-a) - (b) => -(a + b)
759 try r.add(readOnlyPositive(a), b);
760 r.setSign(false);
761 }
529 /// Asserts that r has enough limbs to store the result. Upper bound is `math.max(a.limbs.len, b.limbs.len)`.
530 pub fn bitOr(r: *Mutable, a: Const, b: Const) void {
531 if (a.limbs.len > b.limbs.len) {
532 llor(r.limbs[0..], a.limbs[0..a.limbs.len], b.limbs[0..b.limbs.len]);
533 r.len = a.limbs.len;
762534 } else {
763 if (a.isPositive()) {
764 // (a) - (b) => a - b
765 if (a.cmp(b) != .lt) {
766 try r.ensureCapacity(a.len() + 1);
767 llsub(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]);
768 r.normalize(a.len());
769 r.setSign(true);
770 } else {
771 try r.ensureCapacity(b.len() + 1);
772 llsub(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]);
773 r.normalize(b.len());
774 r.setSign(false);
775 }
776 } else {
777 // (-a) - (-b) => -(a - b)
778 if (a.cmp(b) == .lt) {
779 try r.ensureCapacity(a.len() + 1);
780 llsub(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]);
781 r.normalize(a.len());
782 r.setSign(false);
783 } else {
784 try r.ensureCapacity(b.len() + 1);
785 llsub(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]);
786 r.normalize(b.len());
787 r.setSign(true);
788 }
789 }
535 llor(r.limbs[0..], b.limbs[0..b.limbs.len], a.limbs[0..a.limbs.len]);
536 r.len = b.limbs.len;
790537 }
791538 }
792539
793 // Knuth 4.3.1, Algorithm S.
794 fn llsub(r: []Limb, a: []const Limb, b: []const Limb) void {
795 @setRuntimeSafety(false);
796 debug.assert(a.len != 0 and b.len != 0);
797 debug.assert(a.len > b.len or (a.len == b.len and a[a.len - 1] >= b[b.len - 1]));
798 debug.assert(r.len >= a.len);
799
800 var i: usize = 0;
801 var borrow: Limb = 0;
802
803 while (i < b.len) : (i += 1) {
804 var c: Limb = 0;
805 c += @boolToInt(@subWithOverflow(Limb, a[i], b[i], &r[i]));
806 c += @boolToInt(@subWithOverflow(Limb, r[i], borrow, &r[i]));
807 borrow = c;
540 /// r = a & b
541 /// r may alias with a or b.
542 ///
543 /// Asserts that r has enough limbs to store the result. Upper bound is `math.min(a.limbs.len, b.limbs.len)`.
544 pub fn bitAnd(r: *Mutable, a: Const, b: Const) void {
545 if (a.limbs.len > b.limbs.len) {
546 lland(r.limbs[0..], a.limbs[0..a.limbs.len], b.limbs[0..b.limbs.len]);
547 r.normalize(b.limbs.len);
548 } else {
549 lland(r.limbs[0..], b.limbs[0..b.limbs.len], a.limbs[0..a.limbs.len]);
550 r.normalize(a.limbs.len);
808551 }
552 }
809553
810 while (i < a.len) : (i += 1) {
811 borrow = @boolToInt(@subWithOverflow(Limb, a[i], borrow, &r[i]));
554 /// r = a ^ b
555 /// r may alias with a or b.
556 ///
557 /// Asserts that r has enough limbs to store the result. Upper bound is `math.max(a.limbs.len, b.limbs.len)`.
558 pub fn bitXor(r: *Mutable, a: Const, b: Const) void {
559 if (a.limbs.len > b.limbs.len) {
560 llxor(r.limbs[0..], a.limbs[0..a.limbs.len], b.limbs[0..b.limbs.len]);
561 r.normalize(a.limbs.len);
562 } else {
563 llxor(r.limbs[0..], b.limbs[0..b.limbs.len], a.limbs[0..a.limbs.len]);
564 r.normalize(b.limbs.len);
812565 }
813
814 debug.assert(borrow == 0);
815566 }
816567
817 /// rma = a * b
568 /// rma may alias x or y.
569 /// x and y may alias each other.
570 /// Asserts that `rma` has enough limbs to store the result. Upper bound is
571 /// `math.min(x.limbs.len, y.limbs.len)`.
818572 ///
819 /// rma, a and b may be aliases. However, it is more efficient if rma does not alias a or b.
573 /// `limbs_buffer` is used for temporary storage during the operation. When this function returns,
574 /// it will have the same length as it had when the function was called.
575 pub fn gcd(rma: *Mutable, x: Const, y: Const, limbs_buffer: *std.ArrayList(Limb)) !void {
576 const prev_len = limbs_buffer.items.len;
577 defer limbs_buffer.shrink(prev_len);
578 const x_copy = if (rma.limbs.ptr == x.limbs.ptr) blk: {
579 const start = limbs_buffer.items.len;
580 try limbs_buffer.appendSlice(x.limbs);
581 break :blk x.toMutable(limbs_buffer.items[start..]).toConst();
582 } else x;
583 const y_copy = if (rma.limbs.ptr == y.limbs.ptr) blk: {
584 const start = limbs_buffer.items.len;
585 try limbs_buffer.appendSlice(y.limbs);
586 break :blk y.toMutable(limbs_buffer.items[start..]).toConst();
587 } else y;
588
589 return gcdLehmer(rma, x_copy, y_copy, limbs_buffer);
590 }
591
592 /// rma may not alias x or y.
593 /// x and y may alias each other.
594 /// Asserts that `rma` has enough limbs to store the result. Upper bound is given by `calcGcdNoAliasLimbLen`.
820595 ///
821 /// Returns an error if memory could not be allocated.
822 pub fn mul(rma: *Int, a: Int, b: Int) !void {
823 rma.assertWritable();
596 /// `limbs_buffer` is used for temporary storage during the operation.
597 pub fn gcdNoAlias(rma: *Mutable, x: Const, y: Const, limbs_buffer: *std.ArrayList(Limb)) !void {
598 assert(rma.limbs.ptr != x.limbs.ptr); // illegal aliasing
599 assert(rma.limbs.ptr != y.limbs.ptr); // illegal aliasing
600 return gcdLehmer(rma, x, y, allocator);
601 }
602
603 fn gcdLehmer(result: *Mutable, xa: Const, ya: Const, limbs_buffer: *std.ArrayList(Limb)) !void {
604 var x = try xa.toManaged(limbs_buffer.allocator);
605 defer x.deinit();
606 x.abs();
824607
825 var r = rma;
826 var aliased = rma.limbs.ptr == a.limbs.ptr or rma.limbs.ptr == b.limbs.ptr;
608 var y = try ya.toManaged(limbs_buffer.allocator);
609 defer y.deinit();
610 y.abs();
827611
828 var sr: Int = undefined;
829 if (aliased) {
830 sr = try Int.initCapacity(rma.allocator.?, a.len() + b.len());
831 r = &sr;
832 aliased = true;
612 if (x.toConst().order(y.toConst()) == .lt) {
613 x.swap(&y);
833614 }
834 defer if (aliased) {
835 rma.swap(r);
836 r.deinit();
837 };
838615
839 try r.ensureCapacity(a.len() + b.len() + 1);
616 var t_big = try Managed.init(limbs_buffer.allocator);
617 defer t_big.deinit();
840618
841 mem.set(Limb, r.limbs[0 .. a.len() + b.len() + 1], 0);
619 var r = try Managed.init(limbs_buffer.allocator);
620 defer r.deinit();
842621
843 try llmulacc(rma.allocator.?, r.limbs, a.limbs[0..a.len()], b.limbs[0..b.len()]);
622 while (y.len() > 1) {
623 assert(x.isPositive() and y.isPositive());
624 assert(x.len() >= y.len());
844625
845 r.normalize(a.len() + b.len());
846 r.setSign(a.isPositive() == b.isPositive());
847 }
626 var xh: SignedDoubleLimb = x.limbs[x.len() - 1];
627 var yh: SignedDoubleLimb = if (x.len() > y.len()) 0 else y.limbs[x.len() - 1];
628
629 var A: SignedDoubleLimb = 1;
630 var B: SignedDoubleLimb = 0;
631 var C: SignedDoubleLimb = 0;
632 var D: SignedDoubleLimb = 1;
633
634 while (yh + C != 0 and yh + D != 0) {
635 const q = @divFloor(xh + A, yh + C);
636 const qp = @divFloor(xh + B, yh + D);
637 if (q != qp) {
638 break;
639 }
848640
849 // a + b * c + *carry, sets carry to the overflow bits
850 pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb {
851 @setRuntimeSafety(false);
852 var r1: Limb = undefined;
641 var t = A - q * C;
642 A = C;
643 C = t;
644 t = B - q * D;
645 B = D;
646 D = t;
853647
854 // r1 = a + *carry
855 const c1: Limb = @boolToInt(@addWithOverflow(Limb, a, carry.*, &r1));
648 t = xh - q * yh;
649 xh = yh;
650 yh = t;
651 }
856652
857 // r2 = b * c
858 const bc = @as(DoubleLimb, math.mulWide(Limb, b, c));
859 const r2 = @truncate(Limb, bc);
860 const c2 = @truncate(Limb, bc >> Limb.bit_count);
653 if (B == 0) {
654 // t_big = x % y, r is unused
655 try r.divTrunc(&t_big, x.toConst(), y.toConst());
656 assert(t_big.isPositive());
861657
862 // r1 = r1 + r2
863 const c3: Limb = @boolToInt(@addWithOverflow(Limb, r1, r2, &r1));
658 x.swap(&y);
659 y.swap(&t_big);
660 } else {
661 var storage: [8]Limb = undefined;
662 const Ap = fixedIntFromSignedDoubleLimb(A, storage[0..2]).toConst();
663 const Bp = fixedIntFromSignedDoubleLimb(B, storage[2..4]).toConst();
664 const Cp = fixedIntFromSignedDoubleLimb(C, storage[4..6]).toConst();
665 const Dp = fixedIntFromSignedDoubleLimb(D, storage[6..8]).toConst();
864666
865 // This never overflows, c1, c3 are either 0 or 1 and if both are 1 then
866 // c2 is at least <= maxInt(Limb) - 2.
867 carry.* = c1 + c2 + c3;
667 // t_big = Ax + By
668 try r.mul(x.toConst(), Ap);
669 try t_big.mul(y.toConst(), Bp);
670 try t_big.add(r.toConst(), t_big.toConst());
868671
869 return r1;
870 }
672 // u = Cx + Dy, r as u
673 try x.mul(x.toConst(), Cp);
674 try r.mul(y.toConst(), Dp);
675 try r.add(x.toConst(), r.toConst());
871676
872 fn llmulDigit(acc: []Limb, y: []const Limb, xi: Limb) void {
873 @setRuntimeSafety(false);
874 if (xi == 0) {
875 return;
677 x.swap(&t_big);
678 y.swap(&r);
679 }
876680 }
877681
878 var carry: usize = 0;
879 var a_lo = acc[0..y.len];
880 var a_hi = acc[y.len..];
682 // euclidean algorithm
683 assert(x.toConst().order(y.toConst()) != .lt);
881684
882 var j: usize = 0;
883 while (j < a_lo.len) : (j += 1) {
884 a_lo[j] = @call(.{ .modifier = .always_inline }, addMulLimbWithCarry, .{ a_lo[j], y[j], xi, &carry });
685 while (!y.toConst().eqZero()) {
686 try t_big.divTrunc(&r, x.toConst(), y.toConst());
687 x.swap(&y);
688 y.swap(&r);
885689 }
886690
887 j = 0;
888 while ((carry != 0) and (j < a_hi.len)) : (j += 1) {
889 carry = @boolToInt(@addWithOverflow(Limb, a_hi[j], carry, &a_hi[j]));
890 }
691 result.copy(x.toConst());
891692 }
892693
893 // Knuth 4.3.1, Algorithm M.
894 //
895 // r MUST NOT alias any of a or b.
896 fn llmulacc(allocator: *Allocator, r: []Limb, a: []const Limb, b: []const Limb) error{OutOfMemory}!void {
897 @setRuntimeSafety(false);
694 /// Truncates by default.
695 fn div(quo: *Mutable, rem: *Mutable, a: Const, b: Const, limbs_buffer: []Limb, allocator: ?*Allocator) void {
696 assert(!b.eqZero()); // division by zero
697 assert(quo != rem); // illegal aliasing
898698
899 const a_norm = a[0..llnormalize(a)];
900 const b_norm = b[0..llnormalize(b)];
901 var x = a_norm;
902 var y = b_norm;
903 if (a_norm.len > b_norm.len) {
904 x = b_norm;
905 y = a_norm;
906 }
699 if (a.orderAbs(b) == .lt) {
700 // quo may alias a so handle rem first
701 rem.copy(a);
702 rem.positive = a.positive == b.positive;
907703
908 debug.assert(r.len >= x.len + y.len + 1);
704 quo.positive = true;
705 quo.len = 1;
706 quo.limbs[0] = 0;
707 return;
708 }
909709
910 // 48 is a pretty abitrary size chosen based on performance of a factorial program.
911 if (x.len <= 48) {
912 // Basecase multiplication
710 // Handle trailing zero-words of divisor/dividend. These are not handled in the following
711 // algorithms.
712 const a_zero_limb_count = blk: {
913713 var i: usize = 0;
914 while (i < x.len) : (i += 1) {
915 llmulDigit(r[i..], y, x[i]);
714 while (i < a.limbs.len) : (i += 1) {
715 if (a.limbs[i] != 0) break;
916716 }
917 } else {
918 // Karatsuba multiplication
919 const split = @divFloor(x.len, 2);
920 var x0 = x[0..split];
921 var x1 = x[split..x.len];
922 var y0 = y[0..split];
923 var y1 = y[split..y.len];
924
925 var tmp = try allocator.alloc(Limb, x1.len + y1.len + 1);
926 defer allocator.free(tmp);
927 mem.set(Limb, tmp, 0);
928
929 try llmulacc(allocator, tmp, x1, y1);
717 break :blk i;
718 };
719 const b_zero_limb_count = blk: {
720 var i: usize = 0;
721 while (i < b.limbs.len) : (i += 1) {
722 if (b.limbs[i] != 0) break;
723 }
724 break :blk i;
725 };
930726
931 var length = llnormalize(tmp);
932 _ = llaccum(r[split..], tmp[0..length]);
933 _ = llaccum(r[split * 2 ..], tmp[0..length]);
727 const ab_zero_limb_count = math.min(a_zero_limb_count, b_zero_limb_count);
934728
935 mem.set(Limb, tmp[0..length], 0);
729 if (b.limbs.len - ab_zero_limb_count == 1) {
730 lldiv1(quo.limbs[0..], &rem.limbs[0], a.limbs[ab_zero_limb_count..a.limbs.len], b.limbs[b.limbs.len - 1]);
731 quo.normalize(a.limbs.len - ab_zero_limb_count);
732 quo.positive = (a.positive == b.positive);
936733
937 try llmulacc(allocator, tmp, x0, y0);
734 rem.len = 1;
735 rem.positive = true;
736 } else {
737 // x and y are modified during division
738 const sep_len = calcMulLimbsBufferLen(a.limbs.len, b.limbs.len, 2);
739 const x_limbs = limbs_buffer[0 * sep_len ..][0..sep_len];
740 const y_limbs = limbs_buffer[1 * sep_len ..][0..sep_len];
741 const t_limbs = limbs_buffer[2 * sep_len ..][0..sep_len];
742 const mul_limbs_buf = limbs_buffer[3 * sep_len ..][0..sep_len];
743
744 var x: Mutable = .{
745 .limbs = x_limbs,
746 .positive = a.positive,
747 .len = a.limbs.len - ab_zero_limb_count,
748 };
749 var y: Mutable = .{
750 .limbs = y_limbs,
751 .positive = b.positive,
752 .len = b.limbs.len - ab_zero_limb_count,
753 };
938754
939 length = llnormalize(tmp);
940 _ = llaccum(r[0..], tmp[0..length]);
941 _ = llaccum(r[split..], tmp[0..length]);
755 // Shrink x, y such that the trailing zero limbs shared between are removed.
756 mem.copy(Limb, x.limbs, a.limbs[ab_zero_limb_count..a.limbs.len]);
757 mem.copy(Limb, y.limbs, b.limbs[ab_zero_limb_count..b.limbs.len]);
942758
943 const x_cmp = llcmp(x1, x0);
944 const y_cmp = llcmp(y1, y0);
945 if (x_cmp * y_cmp == 0) {
946 return;
947 }
948 const x0_len = llnormalize(x0);
949 const x1_len = llnormalize(x1);
950 var j0 = try allocator.alloc(Limb, math.max(x0_len, x1_len));
951 defer allocator.free(j0);
952 if (x_cmp == 1) {
953 llsub(j0, x1[0..x1_len], x0[0..x0_len]);
954 } else {
955 llsub(j0, x0[0..x0_len], x1[0..x1_len]);
956 }
759 divN(quo, rem, &x, &y, t_limbs, mul_limbs_buf, allocator);
760 quo.positive = (a.positive == b.positive);
761 }
957762
958 const y0_len = llnormalize(y0);
959 const y1_len = llnormalize(y1);
960 var j1 = try allocator.alloc(Limb, math.max(y0_len, y1_len));
961 defer allocator.free(j1);
962 if (y_cmp == 1) {
963 llsub(j1, y1[0..y1_len], y0[0..y0_len]);
964 } else {
965 llsub(j1, y0[0..y0_len], y1[0..y1_len]);
966 }
967 const j0_len = llnormalize(j0);
968 const j1_len = llnormalize(j1);
969 if (x_cmp == y_cmp) {
970 mem.set(Limb, tmp[0..length], 0);
971 try llmulacc(allocator, tmp, j0, j1);
972
973 length = Int.llnormalize(tmp);
974 llsub(r[split..], r[split..], tmp[0..length]);
975 } else {
976 try llmulacc(allocator, r[split..], j0, j1);
977 }
763 if (ab_zero_limb_count != 0) {
764 rem.shiftLeft(rem.toConst(), ab_zero_limb_count * Limb.bit_count);
978765 }
979766 }
980767
981 // r = r + a
982 fn llaccum(r: []Limb, a: []const Limb) Limb {
983 @setRuntimeSafety(false);
984 debug.assert(r.len != 0 and a.len != 0);
985 debug.assert(r.len >= a.len);
986
987 var i: usize = 0;
988 var carry: Limb = 0;
989
990 while (i < a.len) : (i += 1) {
991 var c: Limb = 0;
992 c += @boolToInt(@addWithOverflow(Limb, r[i], a[i], &r[i]));
993 c += @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i]));
994 carry = c;
995 }
996
997 while ((carry != 0) and i < r.len) : (i += 1) {
998 carry = @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i]));
999 }
1000
1001 return carry;
1002 }
1003
1004 /// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively for limbs.
1005 pub fn llcmp(a: []const Limb, b: []const Limb) i8 {
1006 @setRuntimeSafety(false);
1007 const a_len = llnormalize(a);
1008 const b_len = llnormalize(b);
1009 if (a_len < b_len) {
1010 return -1;
1011 }
1012 if (a_len > b_len) {
1013 return 1;
1014 }
1015
1016 var i: usize = a_len - 1;
1017 while (i != 0) : (i -= 1) {
1018 if (a[i] != b[i]) {
1019 break;
1020 }
1021 }
1022
1023 if (a[i] < b[i]) {
1024 return -1;
1025 } else if (a[i] > b[i]) {
1026 return 1;
1027 } else {
1028 return 0;
1029 }
1030 }
1031
1032 // returns the min length the limb could be.
1033 fn llnormalize(a: []const Limb) usize {
1034 @setRuntimeSafety(false);
1035 var j = a.len;
1036 while (j > 0) : (j -= 1) {
1037 if (a[j - 1] != 0) {
1038 break;
1039 }
1040 }
1041
1042 // Handle zero
1043 return if (j != 0) j else 1;
1044 }
1045
1046 /// q = a / b (rem r)
768 /// Handbook of Applied Cryptography, 14.20
1047769 ///
1048 /// a / b are floored (rounded towards 0).
1049 pub fn divFloor(q: *Int, r: *Int, a: Int, b: Int) !void {
1050 try div(q, r, a, b);
1051
1052 // Trunc -> Floor.
1053 if (!q.isPositive()) {
1054 const one = Int.initFixed(([_]Limb{1})[0..]);
1055 try q.sub(q.*, one);
1056 try r.add(q.*, one);
1057 }
1058 r.setSign(b.isPositive());
1059 }
1060
1061 /// q = a / b (rem r)
1062 ///
1063 /// a / b are truncated (rounded towards -inf).
1064 pub fn divTrunc(q: *Int, r: *Int, a: Int, b: Int) !void {
1065 try div(q, r, a, b);
1066 r.setSign(a.isPositive());
1067 }
1068
1069 // Truncates by default.
1070 fn div(quo: *Int, rem: *Int, a: Int, b: Int) !void {
1071 quo.assertWritable();
1072 rem.assertWritable();
1073
1074 if (b.eqZero()) {
1075 @panic("division by zero");
1076 }
1077 if (quo == rem) {
1078 @panic("quo and rem cannot be same variable");
1079 }
1080
1081 if (a.cmpAbs(b) == .lt) {
1082 // quo may alias a so handle rem first
1083 try rem.copy(a);
1084 rem.setSign(a.isPositive() == b.isPositive());
1085
1086 quo.metadata = 1;
1087 quo.limbs[0] = 0;
1088 return;
1089 }
1090
1091 // Handle trailing zero-words of divisor/dividend. These are not handled in the following
1092 // algorithms.
1093 const a_zero_limb_count = blk: {
1094 var i: usize = 0;
1095 while (i < a.len()) : (i += 1) {
1096 if (a.limbs[i] != 0) break;
1097 }
1098 break :blk i;
1099 };
1100 const b_zero_limb_count = blk: {
1101 var i: usize = 0;
1102 while (i < b.len()) : (i += 1) {
1103 if (b.limbs[i] != 0) break;
1104 }
1105 break :blk i;
770 /// x = qy + r where 0 <= r < y
771 fn divN(
772 q: *Mutable,
773 r: *Mutable,
774 x: *Mutable,
775 y: *Mutable,
776 tmp_limbs: []Limb,
777 mul_limb_buf: []Limb,
778 allocator: ?*Allocator,
779 ) void {
780 assert(y.len >= 2);
781 assert(x.len >= y.len);
782 assert(q.limbs.len >= x.len + y.len - 1);
783
784 // See 3.2
785 var backup_tmp_limbs: [3]Limb = undefined;
786 const t_limbs = if (tmp_limbs.len < 3) &backup_tmp_limbs else tmp_limbs;
787
788 var tmp: Mutable = .{
789 .limbs = t_limbs,
790 .len = 1,
791 .positive = true,
1106792 };
1107
1108 const ab_zero_limb_count = std.math.min(a_zero_limb_count, b_zero_limb_count);
1109
1110 if (b.len() - ab_zero_limb_count == 1) {
1111 try quo.ensureCapacity(a.len());
1112
1113 lldiv1(quo.limbs[0..], &rem.limbs[0], a.limbs[ab_zero_limb_count..a.len()], b.limbs[b.len() - 1]);
1114 quo.normalize(a.len() - ab_zero_limb_count);
1115 quo.setSign(a.isPositive() == b.isPositive());
1116
1117 rem.metadata = 1;
1118 } else {
1119 // x and y are modified during division
1120 var x = try Int.initCapacity(quo.allocator.?, a.len());
1121 defer x.deinit();
1122 try x.copy(a);
1123
1124 var y = try Int.initCapacity(quo.allocator.?, b.len());
1125 defer y.deinit();
1126 try y.copy(b);
1127
1128 // x may grow one limb during normalization
1129 try quo.ensureCapacity(a.len() + y.len());
1130
1131 // Shrink x, y such that the trailing zero limbs shared between are removed.
1132 if (ab_zero_limb_count != 0) {
1133 std.mem.copy(Limb, x.limbs[0..], x.limbs[ab_zero_limb_count..]);
1134 std.mem.copy(Limb, y.limbs[0..], y.limbs[ab_zero_limb_count..]);
1135 x.metadata -= ab_zero_limb_count;
1136 y.metadata -= ab_zero_limb_count;
1137 }
1138
1139 try divN(quo.allocator.?, quo, rem, &x, &y);
1140 quo.setSign(a.isPositive() == b.isPositive());
1141 }
1142
1143 if (ab_zero_limb_count != 0) {
1144 try rem.shiftLeft(rem.*, ab_zero_limb_count * Limb.bit_count);
1145 }
1146 }
1147
1148 // Knuth 4.3.1, Exercise 16.
1149 fn lldiv1(quo: []Limb, rem: *Limb, a: []const Limb, b: Limb) void {
1150 @setRuntimeSafety(false);
1151 debug.assert(a.len > 1 or a[0] >= b);
1152 debug.assert(quo.len >= a.len);
1153
1154 rem.* = 0;
1155 for (a) |_, ri| {
1156 const i = a.len - ri - 1;
1157 const pdiv = ((@as(DoubleLimb, rem.*) << Limb.bit_count) | a[i]);
1158
1159 if (pdiv == 0) {
1160 quo[i] = 0;
1161 rem.* = 0;
1162 } else if (pdiv < b) {
1163 quo[i] = 0;
1164 rem.* = @truncate(Limb, pdiv);
1165 } else if (pdiv == b) {
1166 quo[i] = 1;
1167 rem.* = 0;
1168 } else {
1169 quo[i] = @truncate(Limb, @divTrunc(pdiv, b));
1170 rem.* = @truncate(Limb, pdiv - (quo[i] *% b));
1171 }
1172 }
1173 }
1174
1175 // Handbook of Applied Cryptography, 14.20
1176 //
1177 // x = qy + r where 0 <= r < y
1178 fn divN(allocator: *Allocator, q: *Int, r: *Int, x: *Int, y: *Int) !void {
1179 debug.assert(y.len() >= 2);
1180 debug.assert(x.len() >= y.len());
1181 debug.assert(q.limbs.len >= x.len() + y.len() - 1);
1182 debug.assert(default_capacity >= 3); // see 3.2
1183
1184 var tmp = try Int.init(allocator);
1185 defer tmp.deinit();
793 tmp.limbs[0] = 0;
1186794
1187795 // Normalize so y > Limb.bit_count / 2 (i.e. leading bit is set) and even
1188 var norm_shift = @clz(Limb, y.limbs[y.len() - 1]);
1189 if (norm_shift == 0 and y.isOdd()) {
796 var norm_shift = @clz(Limb, y.limbs[y.len - 1]);
797 if (norm_shift == 0 and y.toConst().isOdd()) {
1190798 norm_shift = Limb.bit_count;
1191799 }
1192 try x.shiftLeft(x.*, norm_shift);
1193 try y.shiftLeft(y.*, norm_shift);
800 x.shiftLeft(x.toConst(), norm_shift);
801 y.shiftLeft(y.toConst(), norm_shift);
1194802
1195 const n = x.len() - 1;
1196 const t = y.len() - 1;
803 const n = x.len - 1;
804 const t = y.len - 1;
1197805
1198806 // 1.
1199 q.metadata = n - t + 1;
1200 mem.set(Limb, q.limbs[0..q.len()], 0);
807 q.len = n - t + 1;
808 q.positive = true;
809 mem.set(Limb, q.limbs[0..q.len], 0);
1201810
1202811 // 2.
1203 try tmp.shiftLeft(y.*, Limb.bit_count * (n - t));
1204 while (x.cmp(tmp) != .lt) {
812 tmp.shiftLeft(y.toConst(), Limb.bit_count * (n - t));
813 while (x.toConst().order(tmp.toConst()) != .lt) {
1205814 q.limbs[n - t] += 1;
1206 try x.sub(x.*, tmp);
815 x.sub(x.toConst(), tmp.toConst());
1207816 }
1208817
1209818 // 3.
......@@ -1232,7 +841,7 @@ pub const Int = struct {
1232841 r.limbs[2] = carry;
1233842 r.normalize(3);
1234843
1235 if (r.cmpAbs(tmp) != .gt) {
844 if (r.toConst().orderAbs(tmp.toConst()) != .gt) {
1236845 break;
1237846 }
1238847
......@@ -1240,1748 +849,1284 @@ pub const Int = struct {
1240849 }
1241850
1242851 // 3.3
1243 try tmp.set(q.limbs[i - t - 1]);
1244 try tmp.mul(tmp, y.*);
1245 try tmp.shiftLeft(tmp, Limb.bit_count * (i - t - 1));
1246 try x.sub(x.*, tmp);
1247
1248 if (!x.isPositive()) {
1249 try tmp.shiftLeft(y.*, Limb.bit_count * (i - t - 1));
1250 try x.add(x.*, tmp);
852 tmp.set(q.limbs[i - t - 1]);
853 tmp.mul(tmp.toConst(), y.toConst(), mul_limb_buf, allocator);
854 tmp.shiftLeft(tmp.toConst(), Limb.bit_count * (i - t - 1));
855 x.sub(x.toConst(), tmp.toConst());
856
857 if (!x.positive) {
858 tmp.shiftLeft(y.toConst(), Limb.bit_count * (i - t - 1));
859 x.add(x.toConst(), tmp.toConst());
1251860 q.limbs[i - t - 1] -= 1;
1252861 }
1253862 }
1254863
1255864 // Denormalize
1256 q.normalize(q.len());
865 q.normalize(q.len);
1257866
1258 try r.shiftRight(x.*, norm_shift);
1259 r.normalize(r.len());
867 r.shiftRight(x.toConst(), norm_shift);
868 r.normalize(r.len);
1260869 }
1261870
1262 /// r = a << shift, in other words, r = a * 2^shift
1263 pub fn shiftLeft(r: *Int, a: Int, shift: usize) !void {
1264 r.assertWritable();
1265
1266 try r.ensureCapacity(a.len() + (shift / Limb.bit_count) + 1);
1267 llshl(r.limbs[0..], a.limbs[0..a.len()], shift);
1268 r.normalize(a.len() + (shift / Limb.bit_count) + 1);
1269 r.setSign(a.isPositive());
871 /// Normalize a possible sequence of leading zeros.
872 ///
873 /// [1, 2, 3, 4, 0] -> [1, 2, 3, 4]
874 /// [1, 2, 0, 0, 0] -> [1, 2]
875 /// [0, 0, 0, 0, 0] -> [0]
876 fn normalize(r: *Mutable, length: usize) void {
877 r.len = llnormalize(r.limbs[0..length]);
1270878 }
879};
1271880
1272 fn llshl(r: []Limb, a: []const Limb, shift: usize) void {
1273 @setRuntimeSafety(false);
1274 debug.assert(a.len >= 1);
1275 debug.assert(r.len >= a.len + (shift / Limb.bit_count) + 1);
1276
1277 const limb_shift = shift / Limb.bit_count + 1;
1278 const interior_limb_shift = @intCast(Log2Limb, shift % Limb.bit_count);
1279
1280 var carry: Limb = 0;
1281 var i: usize = 0;
1282 while (i < a.len) : (i += 1) {
1283 const src_i = a.len - i - 1;
1284 const dst_i = src_i + limb_shift;
1285
1286 const src_digit = a[src_i];
1287 r[dst_i] = carry | @call(.{ .modifier = .always_inline }, math.shr, .{
1288 Limb,
1289 src_digit,
1290 Limb.bit_count - @intCast(Limb, interior_limb_shift),
1291 });
1292 carry = (src_digit << interior_limb_shift);
1293 }
1294
1295 r[limb_shift - 1] = carry;
1296 mem.set(Limb, r[0 .. limb_shift - 1], 0);
881/// A arbitrary-precision big integer, with a fixed set of immutable limbs.
882pub const Const = struct {
883 /// Raw digits. These are:
884 ///
885 /// * Little-endian ordered
886 /// * limbs.len >= 1
887 /// * Zero is represented as limbs.len == 1 with limbs[0] == 0.
888 ///
889 /// Accessing limbs directly should be avoided.
890 limbs: []const Limb,
891 positive: bool,
892
893 /// The result is an independent resource which is managed by the caller.
894 pub fn toManaged(self: Const, allocator: *Allocator) Allocator.Error!Managed {
895 const limbs = try allocator.alloc(Limb, math.max(Managed.default_capacity, self.limbs.len));
896 mem.copy(Limb, limbs, self.limbs);
897 return Managed{
898 .allocator = allocator,
899 .limbs = limbs,
900 .metadata = if (self.positive)
901 self.limbs.len & ~Managed.sign_bit
902 else
903 self.limbs.len | Managed.sign_bit,
904 };
1297905 }
1298906
1299 /// r = a >> shift
1300 pub fn shiftRight(r: *Int, a: Int, shift: usize) !void {
1301 r.assertWritable();
907 /// Asserts `limbs` is big enough to store the value.
908 pub fn toMutable(self: Const, limbs: []Limb) Mutable {
909 mem.copy(Limb, limbs, self.limbs[0..self.limbs.len]);
910 return .{
911 .limbs = limbs,
912 .positive = self.positive,
913 .len = self.limbs.len,
914 };
915 }
1302916
1303 if (a.len() <= shift / Limb.bit_count) {
1304 r.metadata = 1;
1305 r.limbs[0] = 0;
1306 return;
917 pub fn dump(self: Const) void {
918 for (self.limbs[0..self.limbs.len]) |limb| {
919 std.debug.warn("{x} ", .{limb});
1307920 }
921 std.debug.warn("positive={}\n", .{self.positive});
922 }
1308923
1309 try r.ensureCapacity(a.len() - (shift / Limb.bit_count));
1310 const r_len = llshr(r.limbs[0..], a.limbs[0..a.len()], shift);
1311 r.metadata = a.len() - (shift / Limb.bit_count);
1312 r.setSign(a.isPositive());
924 pub fn abs(self: Const) Const {
925 return .{
926 .limbs = self.limbs,
927 .positive = true,
928 };
1313929 }
1314930
1315 fn llshr(r: []Limb, a: []const Limb, shift: usize) void {
1316 @setRuntimeSafety(false);
1317 debug.assert(a.len >= 1);
1318 debug.assert(r.len >= a.len - (shift / Limb.bit_count));
931 pub fn isOdd(self: Const) bool {
932 return self.limbs[0] & 1 != 0;
933 }
1319934
1320 const limb_shift = shift / Limb.bit_count;
1321 const interior_limb_shift = @intCast(Log2Limb, shift % Limb.bit_count);
935 pub fn isEven(self: Const) bool {
936 return !self.isOdd();
937 }
1322938
1323 var carry: Limb = 0;
1324 var i: usize = 0;
1325 while (i < a.len - limb_shift) : (i += 1) {
1326 const src_i = a.len - i - 1;
1327 const dst_i = src_i - limb_shift;
1328
1329 const src_digit = a[src_i];
1330 r[dst_i] = carry | (src_digit >> interior_limb_shift);
1331 carry = @call(.{ .modifier = .always_inline }, math.shl, .{
1332 Limb,
1333 src_digit,
1334 Limb.bit_count - @intCast(Limb, interior_limb_shift),
1335 });
1336 }
939 /// Returns the number of bits required to represent the absolute value of an integer.
940 pub fn bitCountAbs(self: Const) usize {
941 return (self.limbs.len - 1) * Limb.bit_count + (Limb.bit_count - @clz(Limb, self.limbs[self.limbs.len - 1]));
1337942 }
1338943
1339 /// r = a | b
944 /// Returns the number of bits required to represent the integer in twos-complement form.
1340945 ///
1341 /// a and b are zero-extended to the longer of a or b.
1342 pub fn bitOr(r: *Int, a: Int, b: Int) !void {
1343 r.assertWritable();
946 /// If the integer is negative the value returned is the number of bits needed by a signed
947 /// integer to represent the value. If positive the value is the number of bits for an
948 /// unsigned integer. Any unsigned integer will fit in the signed integer with bitcount
949 /// one greater than the returned value.
950 ///
951 /// e.g. -127 returns 8 as it will fit in an i8. 127 returns 7 since it fits in a u7.
952 pub fn bitCountTwosComp(self: Const) usize {
953 var bits = self.bitCountAbs();
1344954
1345 if (a.len() > b.len()) {
1346 try r.ensureCapacity(a.len());
1347 llor(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]);
1348 r.setLen(a.len());
1349 } else {
1350 try r.ensureCapacity(b.len());
1351 llor(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]);
1352 r.setLen(b.len());
955 // If the entire value has only one bit set (e.g. 0b100000000) then the negation in twos
956 // complement requires one less bit.
957 if (!self.positive) block: {
958 bits += 1;
959
960 if (@popCount(Limb, self.limbs[self.limbs.len - 1]) == 1) {
961 for (self.limbs[0 .. self.limbs.len - 1]) |limb| {
962 if (@popCount(Limb, limb) != 0) {
963 break :block;
964 }
965 }
966
967 bits -= 1;
968 }
1353969 }
1354 }
1355970
1356 fn llor(r: []Limb, a: []const Limb, b: []const Limb) void {
1357 @setRuntimeSafety(false);
1358 debug.assert(r.len >= a.len);
1359 debug.assert(a.len >= b.len);
971 return bits;
972 }
1360973
1361 var i: usize = 0;
1362 while (i < b.len) : (i += 1) {
1363 r[i] = a[i] | b[i];
974 pub fn fitsInTwosComp(self: Const, is_signed: bool, bit_count: usize) bool {
975 if (self.eqZero()) {
976 return true;
1364977 }
1365 while (i < a.len) : (i += 1) {
1366 r[i] = a[i];
978 if (!is_signed and !self.positive) {
979 return false;
1367980 }
981
982 const req_bits = self.bitCountTwosComp() + @boolToInt(self.positive and is_signed);
983 return bit_count >= req_bits;
1368984 }
1369985
1370 /// r = a & b
1371 pub fn bitAnd(r: *Int, a: Int, b: Int) !void {
1372 r.assertWritable();
986 /// Returns whether self can fit into an integer of the requested type.
987 pub fn fits(self: Const, comptime T: type) bool {
988 const info = @typeInfo(T).Int;
989 return self.fitsInTwosComp(info.is_signed, info.bits);
990 }
1373991
1374 if (a.len() > b.len()) {
1375 try r.ensureCapacity(b.len());
1376 lland(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]);
1377 r.normalize(b.len());
1378 } else {
1379 try r.ensureCapacity(a.len());
1380 lland(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]);
1381 r.normalize(a.len());
1382 }
992 /// Returns the approximate size of the integer in the given base. Negative values accommodate for
993 /// the minus sign. This is used for determining the number of characters needed to print the
994 /// value. It is inexact and may exceed the given value by ~1-2 bytes.
995 /// TODO See if we can make this exact.
996 pub fn sizeInBaseUpperBound(self: Const, base: usize) usize {
997 const bit_count = @as(usize, @boolToInt(!self.positive)) + self.bitCountAbs();
998 return (bit_count / math.log2(base)) + 1;
1383999 }
13841000
1385 fn lland(r: []Limb, a: []const Limb, b: []const Limb) void {
1386 @setRuntimeSafety(false);
1387 debug.assert(r.len >= b.len);
1388 debug.assert(a.len >= b.len);
1001 pub const ConvertError = error{
1002 NegativeIntoUnsigned,
1003 TargetTooSmall,
1004 };
13891005
1390 var i: usize = 0;
1391 while (i < b.len) : (i += 1) {
1392 r[i] = a[i] & b[i];
1006 /// Convert self to type T.
1007 ///
1008 /// Returns an error if self cannot be narrowed into the requested type without truncation.
1009 pub fn to(self: Const, comptime T: type) ConvertError!T {
1010 switch (@typeInfo(T)) {
1011 .Int => {
1012 const UT = std.meta.IntType(false, T.bit_count);
1013
1014 if (self.bitCountTwosComp() > T.bit_count) {
1015 return error.TargetTooSmall;
1016 }
1017
1018 var r: UT = 0;
1019
1020 if (@sizeOf(UT) <= @sizeOf(Limb)) {
1021 r = @intCast(UT, self.limbs[0]);
1022 } else {
1023 for (self.limbs[0..self.limbs.len]) |_, ri| {
1024 const limb = self.limbs[self.limbs.len - ri - 1];
1025 r <<= Limb.bit_count;
1026 r |= limb;
1027 }
1028 }
1029
1030 if (!T.is_signed) {
1031 return if (self.positive) @intCast(T, r) else error.NegativeIntoUnsigned;
1032 } else {
1033 if (self.positive) {
1034 return @intCast(T, r);
1035 } else {
1036 if (math.cast(T, r)) |ok| {
1037 return -ok;
1038 } else |_| {
1039 return minInt(T);
1040 }
1041 }
1042 }
1043 },
1044 else => @compileError("cannot convert Const to type " ++ @typeName(T)),
13931045 }
13941046 }
13951047
1396 /// r = a ^ b
1397 pub fn bitXor(r: *Int, a: Int, b: Int) !void {
1398 r.assertWritable();
1048 /// To allow `std.fmt.format` to work with this type.
1049 /// If the integer is larger than `pow(2, 64 * @sizeOf(usize) * 8), this function will fail
1050 /// to print the string, printing "(BigInt)" instead of a number.
1051 /// This is because the rendering algorithm requires reversing a string, which requires O(N) memory.
1052 /// See `toString` and `toStringAlloc` for a way to print big integers without failure.
1053 pub fn format(
1054 self: Const,
1055 comptime fmt: []const u8,
1056 options: std.fmt.FormatOptions,
1057 out_stream: var,
1058 ) !void {
1059 comptime var radix = 10;
1060 comptime var uppercase = false;
13991061
1400 if (a.len() > b.len()) {
1401 try r.ensureCapacity(a.len());
1402 llxor(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]);
1403 r.normalize(a.len());
1062 if (fmt.len == 0 or comptime mem.eql(u8, fmt, "d")) {
1063 radix = 10;
1064 uppercase = false;
1065 } else if (comptime mem.eql(u8, fmt, "b")) {
1066 radix = 2;
1067 uppercase = false;
1068 } else if (comptime mem.eql(u8, fmt, "x")) {
1069 radix = 16;
1070 uppercase = false;
1071 } else if (comptime mem.eql(u8, fmt, "X")) {
1072 radix = 16;
1073 uppercase = true;
14041074 } else {
1405 try r.ensureCapacity(b.len());
1406 llxor(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]);
1407 r.normalize(b.len());
1075 @compileError("Unknown format string: '" ++ fmt ++ "'");
14081076 }
1409 }
14101077
1411 fn llxor(r: []Limb, a: []const Limb, b: []const Limb) void {
1412 @setRuntimeSafety(false);
1413 debug.assert(r.len >= a.len);
1414 debug.assert(a.len >= b.len);
1078 var limbs: [128]Limb = undefined;
1079 const needed_limbs = calcDivLimbsBufferLen(self.limbs.len, 1);
1080 if (needed_limbs > limbs.len)
1081 return out_stream.writeAll("(BigInt)");
14151082
1416 var i: usize = 0;
1417 while (i < b.len) : (i += 1) {
1418 r[i] = a[i] ^ b[i];
1419 }
1420 while (i < a.len) : (i += 1) {
1421 r[i] = a[i];
1422 }
1083 // This is the inverse of calcDivLimbsBufferLen
1084 const available_len = (limbs.len / 3) - 2;
1085
1086 const biggest: Const = .{
1087 .limbs = &([1]Limb{math.maxInt(Limb)} ** available_len),
1088 .positive = false,
1089 };
1090 var buf: [biggest.sizeInBaseUpperBound(radix)]u8 = undefined;
1091 const len = self.toString(&buf, radix, uppercase, &limbs);
1092 return out_stream.writeAll(buf[0..len]);
14231093 }
14241094
1425 pub fn gcd(rma: *Int, x: Int, y: Int) !void {
1426 rma.assertWritable();
1427 var r = rma;
1428 var aliased = rma.limbs.ptr == x.limbs.ptr or rma.limbs.ptr == y.limbs.ptr;
1095 /// Converts self to a string in the requested base.
1096 /// Caller owns returned memory.
1097 /// Asserts that `base` is in the range [2, 16].
1098 /// See also `toString`, a lower level function than this.
1099 pub fn toStringAlloc(self: Const, allocator: *Allocator, base: u8, uppercase: bool) Allocator.Error![]u8 {
1100 assert(base >= 2);
1101 assert(base <= 16);
14291102
1430 var sr: Int = undefined;
1431 if (aliased) {
1432 sr = try Int.initCapacity(rma.allocator.?, math.max(x.len(), y.len()));
1433 r = &sr;
1434 aliased = true;
1103 if (self.eqZero()) {
1104 return mem.dupe(allocator, u8, "0");
14351105 }
1436 defer if (aliased) {
1437 rma.swap(r);
1438 r.deinit();
1439 };
1106 const string = try allocator.alloc(u8, self.sizeInBaseUpperBound(base));
1107 errdefer allocator.free(string);
14401108
1441 try gcdLehmer(r, x, y);
1442 }
1109 const limbs = try allocator.alloc(Limb, calcToStringLimbsBufferLen(self.limbs.len, base));
1110 defer allocator.free(limbs);
14431111
1444 fn gcdLehmer(r: *Int, xa: Int, ya: Int) !void {
1445 var x = try xa.clone();
1446 x.abs();
1447 defer x.deinit();
1112 return allocator.shrink(string, self.toString(string, base, uppercase, limbs));
1113 }
14481114
1449 var y = try ya.clone();
1450 y.abs();
1451 defer y.deinit();
1115 /// Converts self to a string in the requested base.
1116 /// Asserts that `base` is in the range [2, 16].
1117 /// `string` is a caller-provided slice of at least `sizeInBaseUpperBound` bytes,
1118 /// where the result is written to.
1119 /// Returns the length of the string.
1120 /// `limbs_buffer` is caller-provided memory for `toString` to use as a working area. It must have
1121 /// length of at least `calcToStringLimbsBufferLen`.
1122 /// In the case of power-of-two base, `limbs_buffer` is ignored.
1123 /// See also `toStringAlloc`, a higher level function than this.
1124 pub fn toString(self: Const, string: []u8, base: u8, uppercase: bool, limbs_buffer: []Limb) usize {
1125 assert(base >= 2);
1126 assert(base <= 16);
14521127
1453 if (x.cmp(y) == .lt) {
1454 x.swap(&y);
1128 if (self.eqZero()) {
1129 string[0] = '0';
1130 return 1;
14551131 }
14561132
1457 var T = try Int.init(r.allocator.?);
1458 defer T.deinit();
1459
1460 while (y.len() > 1) {
1461 debug.assert(x.isPositive() and y.isPositive());
1462 debug.assert(x.len() >= y.len());
1133 var digits_len: usize = 0;
14631134
1464 var xh: SignedDoubleLimb = x.limbs[x.len() - 1];
1465 var yh: SignedDoubleLimb = if (x.len() > y.len()) 0 else y.limbs[x.len() - 1];
1135 // Power of two: can do a single pass and use masks to extract digits.
1136 if (math.isPowerOfTwo(base)) {
1137 const base_shift = math.log2_int(Limb, base);
14661138
1467 var A: SignedDoubleLimb = 1;
1468 var B: SignedDoubleLimb = 0;
1469 var C: SignedDoubleLimb = 0;
1470 var D: SignedDoubleLimb = 1;
1139 outer: for (self.limbs[0..self.limbs.len]) |limb| {
1140 var shift: usize = 0;
1141 while (shift < Limb.bit_count) : (shift += base_shift) {
1142 const r = @intCast(u8, (limb >> @intCast(Log2Limb, shift)) & @as(Limb, base - 1));
1143 const ch = std.fmt.digitToChar(r, uppercase);
1144 string[digits_len] = ch;
1145 digits_len += 1;
1146 // If we hit the end, it must be all zeroes from here.
1147 if (digits_len == string.len) break :outer;
1148 }
1149 }
14711150
1472 while (yh + C != 0 and yh + D != 0) {
1473 const q = @divFloor(xh + A, yh + C);
1474 const qp = @divFloor(xh + B, yh + D);
1475 if (q != qp) {
1476 break;
1477 }
1151 // Always will have a non-zero digit somewhere.
1152 while (string[digits_len - 1] == '0') {
1153 digits_len -= 1;
1154 }
1155 } else {
1156 // Non power-of-two: batch divisions per word size.
1157 const digits_per_limb = math.log(Limb, base, maxInt(Limb));
1158 var limb_base: Limb = 1;
1159 var j: usize = 0;
1160 while (j < digits_per_limb) : (j += 1) {
1161 limb_base *= base;
1162 }
1163 const b: Const = .{ .limbs = &[_]Limb{limb_base}, .positive = true };
14781164
1479 var t = A - q * C;
1480 A = C;
1481 C = t;
1482 t = B - q * D;
1483 B = D;
1484 D = t;
1165 var q: Mutable = .{
1166 .limbs = limbs_buffer[0 .. self.limbs.len + 2],
1167 .positive = true, // Make absolute by ignoring self.positive.
1168 .len = self.limbs.len,
1169 };
1170 mem.copy(Limb, q.limbs, self.limbs);
14851171
1486 t = xh - q * yh;
1487 xh = yh;
1488 yh = t;
1489 }
1172 var r: Mutable = .{
1173 .limbs = limbs_buffer[q.limbs.len..][0..self.limbs.len],
1174 .positive = true,
1175 .len = 1,
1176 };
1177 r.limbs[0] = 0;
14901178
1491 if (B == 0) {
1492 // T = x % y, r is unused
1493 try Int.divTrunc(r, &T, x, y);
1494 debug.assert(T.isPositive());
1179 const rest_of_the_limbs_buf = limbs_buffer[q.limbs.len + r.limbs.len ..];
14951180
1496 x.swap(&y);
1497 y.swap(&T);
1498 } else {
1499 var storage: [8]Limb = undefined;
1500 const Ap = FixedIntFromSignedDoubleLimb(A, storage[0..2]);
1501 const Bp = FixedIntFromSignedDoubleLimb(B, storage[2..4]);
1502 const Cp = FixedIntFromSignedDoubleLimb(C, storage[4..6]);
1503 const Dp = FixedIntFromSignedDoubleLimb(D, storage[6..8]);
1181 while (q.len >= 2) {
1182 // Passing an allocator here would not be helpful since this division is destroying
1183 // information, not creating it. [TODO citation needed]
1184 q.divTrunc(&r, q.toConst(), b, rest_of_the_limbs_buf, null);
15041185
1505 // T = Ax + By
1506 try r.mul(x, Ap);
1507 try T.mul(y, Bp);
1508 try T.add(r.*, T);
1186 var r_word = r.limbs[0];
1187 var i: usize = 0;
1188 while (i < digits_per_limb) : (i += 1) {
1189 const ch = std.fmt.digitToChar(@intCast(u8, r_word % base), uppercase);
1190 r_word /= base;
1191 string[digits_len] = ch;
1192 digits_len += 1;
1193 }
1194 }
15091195
1510 // u = Cx + Dy, r as u
1511 try x.mul(x, Cp);
1512 try r.mul(y, Dp);
1513 try r.add(x, r.*);
1196 {
1197 assert(q.len == 1);
15141198
1515 x.swap(&T);
1516 y.swap(r);
1199 var r_word = q.limbs[0];
1200 while (r_word != 0) {
1201 const ch = std.fmt.digitToChar(@intCast(u8, r_word % base), uppercase);
1202 r_word /= base;
1203 string[digits_len] = ch;
1204 digits_len += 1;
1205 }
15171206 }
15181207 }
15191208
1520 // euclidean algorithm
1521 debug.assert(x.cmp(y) != .lt);
1522
1523 while (!y.eqZero()) {
1524 try Int.divTrunc(&T, r, x, y);
1525 x.swap(&y);
1526 y.swap(r);
1209 if (!self.positive) {
1210 string[digits_len] = '-';
1211 digits_len += 1;
15271212 }
15281213
1529 r.swap(&x);
1214 const s = string[0..digits_len];
1215 mem.reverse(u8, s);
1216 return s.len;
15301217 }
1531};
15321218
1533// Storage must live for the lifetime of the returned value
1534fn FixedIntFromSignedDoubleLimb(A: SignedDoubleLimb, storage: []Limb) Int {
1535 std.debug.assert(storage.len >= 2);
1536
1537 var A_is_positive = A >= 0;
1538 const Au = @intCast(DoubleLimb, if (A < 0) -A else A);
1539 storage[0] = @truncate(Limb, Au);
1540 storage[1] = @truncate(Limb, Au >> Limb.bit_count);
1541 var Ap = Int.initFixed(storage[0..2]);
1542 Ap.setSign(A_is_positive);
1543 return Ap;
1544}
1545
1546// NOTE: All the following tests assume the max machine-word will be 64-bit.
1547//
1548// They will still run on larger than this and should pass, but the multi-limb code-paths
1549// may be untested in some cases.
1550
1551test "big.int comptime_int set" {
1552 comptime var s = 0xefffffff00000001eeeeeeefaaaaaaab;
1553 var a = try Int.initSet(testing.allocator, s);
1554 defer a.deinit();
1219 /// Returns `math.Order.lt`, `math.Order.eq`, `math.Order.gt` if
1220 /// `|a| < |b|`, `|a| == |b|`, or `|a| > |b|` respectively.
1221 pub fn orderAbs(a: Const, b: Const) math.Order {
1222 if (a.limbs.len < b.limbs.len) {
1223 return .lt;
1224 }
1225 if (a.limbs.len > b.limbs.len) {
1226 return .gt;
1227 }
15551228
1556 const s_limb_count = 128 / Limb.bit_count;
1229 var i: usize = a.limbs.len - 1;
1230 while (i != 0) : (i -= 1) {
1231 if (a.limbs[i] != b.limbs[i]) {
1232 break;
1233 }
1234 }
15571235
1558 comptime var i: usize = 0;
1559 inline while (i < s_limb_count) : (i += 1) {
1560 const result = @as(Limb, s & maxInt(Limb));
1561 s >>= Limb.bit_count / 2;
1562 s >>= Limb.bit_count / 2;
1563 testing.expect(a.limbs[i] == result);
1236 if (a.limbs[i] < b.limbs[i]) {
1237 return .lt;
1238 } else if (a.limbs[i] > b.limbs[i]) {
1239 return .gt;
1240 } else {
1241 return .eq;
1242 }
15641243 }
1565}
1566
1567test "big.int comptime_int set negative" {
1568 var a = try Int.initSet(testing.allocator, -10);
1569 defer a.deinit();
1570
1571 testing.expect(a.limbs[0] == 10);
1572 testing.expect(a.isPositive() == false);
1573}
1574
1575test "big.int int set unaligned small" {
1576 var a = try Int.initSet(testing.allocator, @as(u7, 45));
1577 defer a.deinit();
1578
1579 testing.expect(a.limbs[0] == 45);
1580 testing.expect(a.isPositive() == true);
1581}
1582
1583test "big.int comptime_int to" {
1584 const a = try Int.initSet(testing.allocator, 0xefffffff00000001eeeeeeefaaaaaaab);
1585 defer a.deinit();
1586
1587 testing.expect((try a.to(u128)) == 0xefffffff00000001eeeeeeefaaaaaaab);
1588}
1589
1590test "big.int sub-limb to" {
1591 const a = try Int.initSet(testing.allocator, 10);
1592 defer a.deinit();
1593
1594 testing.expect((try a.to(u8)) == 10);
1595}
1596
1597test "big.int to target too small error" {
1598 const a = try Int.initSet(testing.allocator, 0xffffffff);
1599 defer a.deinit();
1600
1601 testing.expectError(error.TargetTooSmall, a.to(u8));
1602}
1603
1604test "big.int normalize" {
1605 var a = try Int.init(testing.allocator);
1606 defer a.deinit();
1607 try a.ensureCapacity(8);
1608
1609 a.limbs[0] = 1;
1610 a.limbs[1] = 2;
1611 a.limbs[2] = 3;
1612 a.limbs[3] = 0;
1613 a.normalize(4);
1614 testing.expect(a.len() == 3);
1615
1616 a.limbs[0] = 1;
1617 a.limbs[1] = 2;
1618 a.limbs[2] = 3;
1619 a.normalize(3);
1620 testing.expect(a.len() == 3);
1621
1622 a.limbs[0] = 0;
1623 a.limbs[1] = 0;
1624 a.normalize(2);
1625 testing.expect(a.len() == 1);
1626
1627 a.limbs[0] = 0;
1628 a.normalize(1);
1629 testing.expect(a.len() == 1);
1630}
1631
1632test "big.int normalize multi" {
1633 var a = try Int.init(testing.allocator);
1634 defer a.deinit();
1635 try a.ensureCapacity(8);
1636
1637 a.limbs[0] = 1;
1638 a.limbs[1] = 2;
1639 a.limbs[2] = 0;
1640 a.limbs[3] = 0;
1641 a.normalize(4);
1642 testing.expect(a.len() == 2);
1643
1644 a.limbs[0] = 1;
1645 a.limbs[1] = 2;
1646 a.limbs[2] = 3;
1647 a.normalize(3);
1648 testing.expect(a.len() == 3);
1649
1650 a.limbs[0] = 0;
1651 a.limbs[1] = 0;
1652 a.limbs[2] = 0;
1653 a.limbs[3] = 0;
1654 a.normalize(4);
1655 testing.expect(a.len() == 1);
1656
1657 a.limbs[0] = 0;
1658 a.normalize(1);
1659 testing.expect(a.len() == 1);
1660}
1661
1662test "big.int parity" {
1663 var a = try Int.init(testing.allocator);
1664 defer a.deinit();
1665
1666 try a.set(0);
1667 testing.expect(a.isEven());
1668 testing.expect(!a.isOdd());
1669
1670 try a.set(7);
1671 testing.expect(!a.isEven());
1672 testing.expect(a.isOdd());
1673}
1674
1675test "big.int bitcount + sizeInBase" {
1676 var a = try Int.init(testing.allocator);
1677 defer a.deinit();
1678
1679 try a.set(0b100);
1680 testing.expect(a.bitCountAbs() == 3);
1681 testing.expect(a.sizeInBase(2) >= 3);
1682 testing.expect(a.sizeInBase(10) >= 1);
1683
1684 a.negate();
1685 testing.expect(a.bitCountAbs() == 3);
1686 testing.expect(a.sizeInBase(2) >= 4);
1687 testing.expect(a.sizeInBase(10) >= 2);
1688
1689 try a.set(0xffffffff);
1690 testing.expect(a.bitCountAbs() == 32);
1691 testing.expect(a.sizeInBase(2) >= 32);
1692 testing.expect(a.sizeInBase(10) >= 10);
1693
1694 try a.shiftLeft(a, 5000);
1695 testing.expect(a.bitCountAbs() == 5032);
1696 testing.expect(a.sizeInBase(2) >= 5032);
1697 a.setSign(false);
1698
1699 testing.expect(a.bitCountAbs() == 5032);
1700 testing.expect(a.sizeInBase(2) >= 5033);
1701}
1702
1703test "big.int bitcount/to" {
1704 var a = try Int.init(testing.allocator);
1705 defer a.deinit();
1706
1707 try a.set(0);
1708 testing.expect(a.bitCountTwosComp() == 0);
1709
1710 testing.expect((try a.to(u0)) == 0);
1711 testing.expect((try a.to(i0)) == 0);
1712
1713 try a.set(-1);
1714 testing.expect(a.bitCountTwosComp() == 1);
1715 testing.expect((try a.to(i1)) == -1);
1716
1717 try a.set(-8);
1718 testing.expect(a.bitCountTwosComp() == 4);
1719 testing.expect((try a.to(i4)) == -8);
1720
1721 try a.set(127);
1722 testing.expect(a.bitCountTwosComp() == 7);
1723 testing.expect((try a.to(u7)) == 127);
1724
1725 try a.set(-128);
1726 testing.expect(a.bitCountTwosComp() == 8);
1727 testing.expect((try a.to(i8)) == -128);
1728
1729 try a.set(-129);
1730 testing.expect(a.bitCountTwosComp() == 9);
1731 testing.expect((try a.to(i9)) == -129);
1732}
1733
1734test "big.int fits" {
1735 var a = try Int.init(testing.allocator);
1736 defer a.deinit();
1737
1738 try a.set(0);
1739 testing.expect(a.fits(u0));
1740 testing.expect(a.fits(i0));
1741
1742 try a.set(255);
1743 testing.expect(!a.fits(u0));
1744 testing.expect(!a.fits(u1));
1745 testing.expect(!a.fits(i8));
1746 testing.expect(a.fits(u8));
1747 testing.expect(a.fits(u9));
1748 testing.expect(a.fits(i9));
1749
1750 try a.set(-128);
1751 testing.expect(!a.fits(i7));
1752 testing.expect(a.fits(i8));
1753 testing.expect(a.fits(i9));
1754 testing.expect(!a.fits(u9));
1755
1756 try a.set(0x1ffffffffeeeeeeee);
1757 testing.expect(!a.fits(u32));
1758 testing.expect(!a.fits(u64));
1759 testing.expect(a.fits(u65));
1760}
1761
1762test "big.int string set" {
1763 var a = try Int.init(testing.allocator);
1764 defer a.deinit();
1765
1766 try a.setString(10, "120317241209124781241290847124");
1767 testing.expect((try a.to(u128)) == 120317241209124781241290847124);
1768}
1769
1770test "big.int string negative" {
1771 var a = try Int.init(testing.allocator);
1772 defer a.deinit();
1773
1774 try a.setString(10, "-1023");
1775 testing.expect((try a.to(i32)) == -1023);
1776}
1777
1778test "big.int string set number with underscores" {
1779 var a = try Int.init(testing.allocator);
1780 defer a.deinit();
1781
1782 try a.setString(10, "__1_2_0_3_1_7_2_4_1_2_0_____9_1__2__4_7_8_1_2_4_1_2_9_0_8_4_7_1_2_4___");
1783 testing.expect((try a.to(u128)) == 120317241209124781241290847124);
1784}
1785
1786test "big.int string set case insensitive number" {
1787 var a = try Int.init(testing.allocator);
1788 defer a.deinit();
1789
1790 try a.setString(16, "aB_cD_eF");
1791 testing.expect((try a.to(u32)) == 0xabcdef);
1792}
1793
1794test "big.int string set bad char error" {
1795 var a = try Int.init(testing.allocator);
1796 defer a.deinit();
1797 testing.expectError(error.InvalidCharForDigit, a.setString(10, "x"));
1798}
1799
1800test "big.int string set bad base error" {
1801 var a = try Int.init(testing.allocator);
1802 defer a.deinit();
1803 testing.expectError(error.InvalidBase, a.setString(45, "10"));
1804}
1805
1806test "big.int string to" {
1807 const a = try Int.initSet(testing.allocator, 120317241209124781241290847124);
1808 defer a.deinit();
1809
1810 const as = try a.toString(testing.allocator, 10, false);
1811 defer testing.allocator.free(as);
1812 const es = "120317241209124781241290847124";
1813
1814 testing.expect(mem.eql(u8, as, es));
1815}
1816
1817test "big.int string to base base error" {
1818 const a = try Int.initSet(testing.allocator, 0xffffffff);
1819 defer a.deinit();
1820
1821 testing.expectError(error.InvalidBase, a.toString(testing.allocator, 45, false));
1822}
1823
1824test "big.int string to base 2" {
1825 const a = try Int.initSet(testing.allocator, -0b1011);
1826 defer a.deinit();
1827
1828 const as = try a.toString(testing.allocator, 2, false);
1829 defer testing.allocator.free(as);
1830 const es = "-1011";
1831
1832 testing.expect(mem.eql(u8, as, es));
1833}
1834
1835test "big.int string to base 16" {
1836 const a = try Int.initSet(testing.allocator, 0xefffffff00000001eeeeeeefaaaaaaab);
1837 defer a.deinit();
1838
1839 const as = try a.toString(testing.allocator, 16, false);
1840 defer testing.allocator.free(as);
1841 const es = "efffffff00000001eeeeeeefaaaaaaab";
1842
1843 testing.expect(mem.eql(u8, as, es));
1844}
1845
1846test "big.int neg string to" {
1847 const a = try Int.initSet(testing.allocator, -123907434);
1848 defer a.deinit();
1849
1850 const as = try a.toString(testing.allocator, 10, false);
1851 defer testing.allocator.free(as);
1852 const es = "-123907434";
1853
1854 testing.expect(mem.eql(u8, as, es));
1855}
1856
1857test "big.int zero string to" {
1858 const a = try Int.initSet(testing.allocator, 0);
1859 defer a.deinit();
1860
1861 const as = try a.toString(testing.allocator, 10, false);
1862 defer testing.allocator.free(as);
1863 const es = "0";
1864
1865 testing.expect(mem.eql(u8, as, es));
1866}
1867
1868test "big.int clone" {
1869 var a = try Int.initSet(testing.allocator, 1234);
1870 defer a.deinit();
1871 const b = try a.clone();
1872 defer b.deinit();
1873
1874 testing.expect((try a.to(u32)) == 1234);
1875 testing.expect((try b.to(u32)) == 1234);
1876
1877 try a.set(77);
1878 testing.expect((try a.to(u32)) == 77);
1879 testing.expect((try b.to(u32)) == 1234);
1880}
1881
1882test "big.int swap" {
1883 var a = try Int.initSet(testing.allocator, 1234);
1884 defer a.deinit();
1885 var b = try Int.initSet(testing.allocator, 5678);
1886 defer b.deinit();
1887
1888 testing.expect((try a.to(u32)) == 1234);
1889 testing.expect((try b.to(u32)) == 5678);
1890
1891 a.swap(&b);
1892
1893 testing.expect((try a.to(u32)) == 5678);
1894 testing.expect((try b.to(u32)) == 1234);
1895}
1896
1897test "big.int to negative" {
1898 var a = try Int.initSet(testing.allocator, -10);
1899 defer a.deinit();
1900
1901 testing.expect((try a.to(i32)) == -10);
1902}
1903
1904test "big.int compare" {
1905 var a = try Int.initSet(testing.allocator, -11);
1906 defer a.deinit();
1907 var b = try Int.initSet(testing.allocator, 10);
1908 defer b.deinit();
19091244
1910 testing.expect(a.cmpAbs(b) == .gt);
1911 testing.expect(a.cmp(b) == .lt);
1912}
1913
1914test "big.int compare similar" {
1915 var a = try Int.initSet(testing.allocator, 0xffffffffeeeeeeeeffffffffeeeeeeee);
1916 defer a.deinit();
1917 var b = try Int.initSet(testing.allocator, 0xffffffffeeeeeeeeffffffffeeeeeeef);
1918 defer b.deinit();
1919
1920 testing.expect(a.cmpAbs(b) == .lt);
1921 testing.expect(b.cmpAbs(a) == .gt);
1922}
1923
1924test "big.int compare different limb size" {
1925 var a = try Int.initSet(testing.allocator, maxInt(Limb) + 1);
1926 defer a.deinit();
1927 var b = try Int.initSet(testing.allocator, 1);
1928 defer b.deinit();
1929
1930 testing.expect(a.cmpAbs(b) == .gt);
1931 testing.expect(b.cmpAbs(a) == .lt);
1932}
1933
1934test "big.int compare multi-limb" {
1935 var a = try Int.initSet(testing.allocator, -0x7777777799999999ffffeeeeffffeeeeffffeeeef);
1936 defer a.deinit();
1937 var b = try Int.initSet(testing.allocator, 0x7777777799999999ffffeeeeffffeeeeffffeeeee);
1938 defer b.deinit();
1939
1940 testing.expect(a.cmpAbs(b) == .gt);
1941 testing.expect(a.cmp(b) == .lt);
1942}
1943
1944test "big.int equality" {
1945 var a = try Int.initSet(testing.allocator, 0xffffffff1);
1946 defer a.deinit();
1947 var b = try Int.initSet(testing.allocator, -0xffffffff1);
1948 defer b.deinit();
1949
1950 testing.expect(a.eqAbs(b));
1951 testing.expect(!a.eq(b));
1952}
1953
1954test "big.int abs" {
1955 var a = try Int.initSet(testing.allocator, -5);
1956 defer a.deinit();
1957
1958 a.abs();
1959 testing.expect((try a.to(u32)) == 5);
1960
1961 a.abs();
1962 testing.expect((try a.to(u32)) == 5);
1963}
1964
1965test "big.int negate" {
1966 var a = try Int.initSet(testing.allocator, 5);
1967 defer a.deinit();
1968
1969 a.negate();
1970 testing.expect((try a.to(i32)) == -5);
1971
1972 a.negate();
1973 testing.expect((try a.to(i32)) == 5);
1974}
1975
1976test "big.int add single-single" {
1977 var a = try Int.initSet(testing.allocator, 50);
1978 defer a.deinit();
1979 var b = try Int.initSet(testing.allocator, 5);
1980 defer b.deinit();
1981
1982 var c = try Int.init(testing.allocator);
1983 defer c.deinit();
1984 try c.add(a, b);
1985
1986 testing.expect((try c.to(u32)) == 55);
1987}
1988
1989test "big.int add multi-single" {
1990 var a = try Int.initSet(testing.allocator, maxInt(Limb) + 1);
1991 defer a.deinit();
1992 var b = try Int.initSet(testing.allocator, 1);
1993 defer b.deinit();
1994
1995 var c = try Int.init(testing.allocator);
1996 defer c.deinit();
1997
1998 try c.add(a, b);
1999 testing.expect((try c.to(DoubleLimb)) == maxInt(Limb) + 2);
2000
2001 try c.add(b, a);
2002 testing.expect((try c.to(DoubleLimb)) == maxInt(Limb) + 2);
2003}
2004
2005test "big.int add multi-multi" {
2006 const op1 = 0xefefefef7f7f7f7f;
2007 const op2 = 0xfefefefe9f9f9f9f;
2008 var a = try Int.initSet(testing.allocator, op1);
2009 defer a.deinit();
2010 var b = try Int.initSet(testing.allocator, op2);
2011 defer b.deinit();
2012
2013 var c = try Int.init(testing.allocator);
2014 defer c.deinit();
2015 try c.add(a, b);
2016
2017 testing.expect((try c.to(u128)) == op1 + op2);
2018}
2019
2020test "big.int add zero-zero" {
2021 var a = try Int.initSet(testing.allocator, 0);
2022 defer a.deinit();
2023 var b = try Int.initSet(testing.allocator, 0);
2024 defer b.deinit();
2025
2026 var c = try Int.init(testing.allocator);
2027 defer c.deinit();
2028 try c.add(a, b);
2029
2030 testing.expect((try c.to(u32)) == 0);
2031}
2032
2033test "big.int add alias multi-limb nonzero-zero" {
2034 const op1 = 0xffffffff777777771;
2035 var a = try Int.initSet(testing.allocator, op1);
2036 defer a.deinit();
2037 var b = try Int.initSet(testing.allocator, 0);
2038 defer b.deinit();
2039
2040 try a.add(a, b);
2041
2042 testing.expect((try a.to(u128)) == op1);
2043}
2044
2045test "big.int add sign" {
2046 var a = try Int.init(testing.allocator);
2047 defer a.deinit();
2048
2049 const one = try Int.initSet(testing.allocator, 1);
2050 defer one.deinit();
2051 const two = try Int.initSet(testing.allocator, 2);
2052 defer two.deinit();
2053 const neg_one = try Int.initSet(testing.allocator, -1);
2054 defer neg_one.deinit();
2055 const neg_two = try Int.initSet(testing.allocator, -2);
2056 defer neg_two.deinit();
2057
2058 try a.add(one, two);
2059 testing.expect((try a.to(i32)) == 3);
2060
2061 try a.add(neg_one, two);
2062 testing.expect((try a.to(i32)) == 1);
2063
2064 try a.add(one, neg_two);
2065 testing.expect((try a.to(i32)) == -1);
2066
2067 try a.add(neg_one, neg_two);
2068 testing.expect((try a.to(i32)) == -3);
2069}
2070
2071test "big.int sub single-single" {
2072 var a = try Int.initSet(testing.allocator, 50);
2073 defer a.deinit();
2074 var b = try Int.initSet(testing.allocator, 5);
2075 defer b.deinit();
2076
2077 var c = try Int.init(testing.allocator);
2078 defer c.deinit();
2079 try c.sub(a, b);
2080
2081 testing.expect((try c.to(u32)) == 45);
2082}
2083
2084test "big.int sub multi-single" {
2085 var a = try Int.initSet(testing.allocator, maxInt(Limb) + 1);
2086 defer a.deinit();
2087 var b = try Int.initSet(testing.allocator, 1);
2088 defer b.deinit();
2089
2090 var c = try Int.init(testing.allocator);
2091 defer c.deinit();
2092 try c.sub(a, b);
2093
2094 testing.expect((try c.to(Limb)) == maxInt(Limb));
2095}
2096
2097test "big.int sub multi-multi" {
2098 const op1 = 0xefefefefefefefefefefefef;
2099 const op2 = 0xabababababababababababab;
2100
2101 var a = try Int.initSet(testing.allocator, op1);
2102 defer a.deinit();
2103 var b = try Int.initSet(testing.allocator, op2);
2104 defer b.deinit();
2105
2106 var c = try Int.init(testing.allocator);
2107 defer c.deinit();
2108 try c.sub(a, b);
2109
2110 testing.expect((try c.to(u128)) == op1 - op2);
2111}
2112
2113test "big.int sub equal" {
2114 var a = try Int.initSet(testing.allocator, 0x11efefefefefefefefefefefef);
2115 defer a.deinit();
2116 var b = try Int.initSet(testing.allocator, 0x11efefefefefefefefefefefef);
2117 defer b.deinit();
2118
2119 var c = try Int.init(testing.allocator);
2120 defer c.deinit();
2121 try c.sub(a, b);
2122
2123 testing.expect((try c.to(u32)) == 0);
2124}
2125
2126test "big.int sub sign" {
2127 var a = try Int.init(testing.allocator);
2128 defer a.deinit();
2129
2130 const one = try Int.initSet(testing.allocator, 1);
2131 defer one.deinit();
2132 const two = try Int.initSet(testing.allocator, 2);
2133 defer two.deinit();
2134 const neg_one = try Int.initSet(testing.allocator, -1);
2135 defer neg_one.deinit();
2136 const neg_two = try Int.initSet(testing.allocator, -2);
2137 defer neg_two.deinit();
2138
2139 try a.sub(one, two);
2140 testing.expect((try a.to(i32)) == -1);
2141
2142 try a.sub(neg_one, two);
2143 testing.expect((try a.to(i32)) == -3);
2144
2145 try a.sub(one, neg_two);
2146 testing.expect((try a.to(i32)) == 3);
2147
2148 try a.sub(neg_one, neg_two);
2149 testing.expect((try a.to(i32)) == 1);
2150
2151 try a.sub(neg_two, neg_one);
2152 testing.expect((try a.to(i32)) == -1);
2153}
2154
2155test "big.int mul single-single" {
2156 var a = try Int.initSet(testing.allocator, 50);
2157 defer a.deinit();
2158 var b = try Int.initSet(testing.allocator, 5);
2159 defer b.deinit();
2160
2161 var c = try Int.init(testing.allocator);
2162 defer c.deinit();
2163 try c.mul(a, b);
2164
2165 testing.expect((try c.to(u64)) == 250);
2166}
2167
2168test "big.int mul multi-single" {
2169 var a = try Int.initSet(testing.allocator, maxInt(Limb));
2170 defer a.deinit();
2171 var b = try Int.initSet(testing.allocator, 2);
2172 defer b.deinit();
2173
2174 var c = try Int.init(testing.allocator);
2175 defer c.deinit();
2176 try c.mul(a, b);
2177
2178 testing.expect((try c.to(DoubleLimb)) == 2 * maxInt(Limb));
2179}
2180
2181test "big.int mul multi-multi" {
2182 const op1 = 0x998888efefefefefefefef;
2183 const op2 = 0x333000abababababababab;
2184 var a = try Int.initSet(testing.allocator, op1);
2185 defer a.deinit();
2186 var b = try Int.initSet(testing.allocator, op2);
2187 defer b.deinit();
2188
2189 var c = try Int.init(testing.allocator);
2190 defer c.deinit();
2191 try c.mul(a, b);
2192
2193 testing.expect((try c.to(u256)) == op1 * op2);
2194}
2195
2196test "big.int mul alias r with a" {
2197 var a = try Int.initSet(testing.allocator, maxInt(Limb));
2198 defer a.deinit();
2199 var b = try Int.initSet(testing.allocator, 2);
2200 defer b.deinit();
2201
2202 try a.mul(a, b);
2203
2204 testing.expect((try a.to(DoubleLimb)) == 2 * maxInt(Limb));
2205}
2206
2207test "big.int mul alias r with b" {
2208 var a = try Int.initSet(testing.allocator, maxInt(Limb));
2209 defer a.deinit();
2210 var b = try Int.initSet(testing.allocator, 2);
2211 defer b.deinit();
2212
2213 try a.mul(b, a);
2214
2215 testing.expect((try a.to(DoubleLimb)) == 2 * maxInt(Limb));
2216}
2217
2218test "big.int mul alias r with a and b" {
2219 var a = try Int.initSet(testing.allocator, maxInt(Limb));
2220 defer a.deinit();
2221
2222 try a.mul(a, a);
2223
2224 testing.expect((try a.to(DoubleLimb)) == maxInt(Limb) * maxInt(Limb));
2225}
2226
2227test "big.int mul a*0" {
2228 var a = try Int.initSet(testing.allocator, 0xefefefefefefefef);
2229 defer a.deinit();
2230 var b = try Int.initSet(testing.allocator, 0);
2231 defer b.deinit();
2232
2233 var c = try Int.init(testing.allocator);
2234 defer c.deinit();
2235 try c.mul(a, b);
2236
2237 testing.expect((try c.to(u32)) == 0);
2238}
2239
2240test "big.int mul 0*0" {
2241 var a = try Int.initSet(testing.allocator, 0);
2242 defer a.deinit();
2243 var b = try Int.initSet(testing.allocator, 0);
2244 defer b.deinit();
2245
2246 var c = try Int.init(testing.allocator);
2247 defer c.deinit();
2248 try c.mul(a, b);
2249
2250 testing.expect((try c.to(u32)) == 0);
2251}
2252
2253test "big.int div single-single no rem" {
2254 var a = try Int.initSet(testing.allocator, 50);
2255 defer a.deinit();
2256 var b = try Int.initSet(testing.allocator, 5);
2257 defer b.deinit();
2258
2259 var q = try Int.init(testing.allocator);
2260 defer q.deinit();
2261 var r = try Int.init(testing.allocator);
2262 defer r.deinit();
2263 try Int.divTrunc(&q, &r, a, b);
2264
2265 testing.expect((try q.to(u32)) == 10);
2266 testing.expect((try r.to(u32)) == 0);
2267}
2268
2269test "big.int div single-single with rem" {
2270 var a = try Int.initSet(testing.allocator, 49);
2271 defer a.deinit();
2272 var b = try Int.initSet(testing.allocator, 5);
2273 defer b.deinit();
2274
2275 var q = try Int.init(testing.allocator);
2276 defer q.deinit();
2277 var r = try Int.init(testing.allocator);
2278 defer r.deinit();
2279 try Int.divTrunc(&q, &r, a, b);
2280
2281 testing.expect((try q.to(u32)) == 9);
2282 testing.expect((try r.to(u32)) == 4);
2283}
2284
2285test "big.int div multi-single no rem" {
2286 const op1 = 0xffffeeeeddddcccc;
2287 const op2 = 34;
2288
2289 var a = try Int.initSet(testing.allocator, op1);
2290 defer a.deinit();
2291 var b = try Int.initSet(testing.allocator, op2);
2292 defer b.deinit();
2293
2294 var q = try Int.init(testing.allocator);
2295 defer q.deinit();
2296 var r = try Int.init(testing.allocator);
2297 defer r.deinit();
2298 try Int.divTrunc(&q, &r, a, b);
2299
2300 testing.expect((try q.to(u64)) == op1 / op2);
2301 testing.expect((try r.to(u64)) == 0);
2302}
2303
2304test "big.int div multi-single with rem" {
2305 const op1 = 0xffffeeeeddddcccf;
2306 const op2 = 34;
2307
2308 var a = try Int.initSet(testing.allocator, op1);
2309 defer a.deinit();
2310 var b = try Int.initSet(testing.allocator, op2);
2311 defer b.deinit();
2312
2313 var q = try Int.init(testing.allocator);
2314 defer q.deinit();
2315 var r = try Int.init(testing.allocator);
2316 defer r.deinit();
2317 try Int.divTrunc(&q, &r, a, b);
2318
2319 testing.expect((try q.to(u64)) == op1 / op2);
2320 testing.expect((try r.to(u64)) == 3);
2321}
2322
2323test "big.int div multi>2-single" {
2324 const op1 = 0xfefefefefefefefefefefefefefefefe;
2325 const op2 = 0xefab8;
2326
2327 var a = try Int.initSet(testing.allocator, op1);
2328 defer a.deinit();
2329 var b = try Int.initSet(testing.allocator, op2);
2330 defer b.deinit();
1245 /// Returns `math.Order.lt`, `math.Order.eq`, `math.Order.gt` if `a < b`, `a == b` or `a > b` respectively.
1246 pub fn order(a: Const, b: Const) math.Order {
1247 if (a.positive != b.positive) {
1248 return if (a.positive) .gt else .lt;
1249 } else {
1250 const r = orderAbs(a, b);
1251 return if (a.positive) r else switch (r) {
1252 .lt => math.Order.gt,
1253 .eq => math.Order.eq,
1254 .gt => math.Order.lt,
1255 };
1256 }
1257 }
23311258
2332 var q = try Int.init(testing.allocator);
2333 defer q.deinit();
2334 var r = try Int.init(testing.allocator);
2335 defer r.deinit();
2336 try Int.divTrunc(&q, &r, a, b);
1259 /// Same as `order` but the right-hand operand is a primitive integer.
1260 pub fn orderAgainstScalar(lhs: Const, scalar: var) math.Order {
1261 var limbs: [calcLimbLen(scalar)]Limb = undefined;
1262 const rhs = Mutable.init(&limbs, scalar);
1263 return order(lhs, rhs.toConst());
1264 }
23371265
2338 testing.expect((try q.to(u128)) == op1 / op2);
2339 testing.expect((try r.to(u32)) == 0x3e4e);
2340}
1266 /// Returns true if `a == 0`.
1267 pub fn eqZero(a: Const) bool {
1268 return a.limbs.len == 1 and a.limbs[0] == 0;
1269 }
23411270
2342test "big.int div single-single q < r" {
2343 var a = try Int.initSet(testing.allocator, 0x0078f432);
2344 defer a.deinit();
2345 var b = try Int.initSet(testing.allocator, 0x01000000);
2346 defer b.deinit();
1271 /// Returns true if `|a| == |b|`.
1272 pub fn eqAbs(a: Const, b: Const) bool {
1273 return orderAbs(a, b) == .eq;
1274 }
23471275
2348 var q = try Int.init(testing.allocator);
2349 defer q.deinit();
2350 var r = try Int.init(testing.allocator);
2351 defer r.deinit();
2352 try Int.divTrunc(&q, &r, a, b);
1276 /// Returns true if `a == b`.
1277 pub fn eq(a: Const, b: Const) bool {
1278 return order(a, b) == .eq;
1279 }
1280};
23531281
2354 testing.expect((try q.to(u64)) == 0);
2355 testing.expect((try r.to(u64)) == 0x0078f432);
2356}
1282/// An arbitrary-precision big integer along with an allocator which manages the memory.
1283///
1284/// Memory is allocated as needed to ensure operations never overflow. The range
1285/// is bounded only by available memory.
1286pub const Managed = struct {
1287 pub const sign_bit: usize = 1 << (usize.bit_count - 1);
23571288
2358test "big.int div single-single q == r" {
2359 var a = try Int.initSet(testing.allocator, 10);
2360 defer a.deinit();
2361 var b = try Int.initSet(testing.allocator, 10);
2362 defer b.deinit();
1289 /// Default number of limbs to allocate on creation of a `Managed`.
1290 pub const default_capacity = 4;
23631291
2364 var q = try Int.init(testing.allocator);
2365 defer q.deinit();
2366 var r = try Int.init(testing.allocator);
2367 defer r.deinit();
2368 try Int.divTrunc(&q, &r, a, b);
1292 /// Allocator used by the Managed when requesting memory.
1293 allocator: *Allocator,
23691294
2370 testing.expect((try q.to(u64)) == 1);
2371 testing.expect((try r.to(u64)) == 0);
2372}
1295 /// Raw digits. These are:
1296 ///
1297 /// * Little-endian ordered
1298 /// * limbs.len >= 1
1299 /// * Zero is represent as Managed.len() == 1 with limbs[0] == 0.
1300 ///
1301 /// Accessing limbs directly should be avoided.
1302 limbs: []Limb,
23731303
2374test "big.int div q=0 alias" {
2375 var a = try Int.initSet(testing.allocator, 3);
2376 defer a.deinit();
2377 var b = try Int.initSet(testing.allocator, 10);
2378 defer b.deinit();
1304 /// High bit is the sign bit. If set, Managed is negative, else Managed is positive.
1305 /// The remaining bits represent the number of limbs used by Managed.
1306 metadata: usize,
23791307
2380 try Int.divTrunc(&a, &b, a, b);
1308 /// Creates a new `Managed`. `default_capacity` limbs will be allocated immediately.
1309 /// The integer value after initializing is `0`.
1310 pub fn init(allocator: *Allocator) !Managed {
1311 return initCapacity(allocator, default_capacity);
1312 }
23811313
2382 testing.expect((try a.to(u64)) == 0);
2383 testing.expect((try b.to(u64)) == 3);
2384}
1314 pub fn toMutable(self: Managed) Mutable {
1315 return .{
1316 .limbs = self.limbs,
1317 .positive = self.isPositive(),
1318 .len = self.len(),
1319 };
1320 }
23851321
2386test "big.int div multi-multi q < r" {
2387 const op1 = 0x1ffffffff0078f432;
2388 const op2 = 0x1ffffffff01000000;
2389 var a = try Int.initSet(testing.allocator, op1);
2390 defer a.deinit();
2391 var b = try Int.initSet(testing.allocator, op2);
2392 defer b.deinit();
2393
2394 var q = try Int.init(testing.allocator);
2395 defer q.deinit();
2396 var r = try Int.init(testing.allocator);
2397 defer r.deinit();
2398 try Int.divTrunc(&q, &r, a, b);
2399
2400 testing.expect((try q.to(u128)) == 0);
2401 testing.expect((try r.to(u128)) == op1);
2402}
1322 pub fn toConst(self: Managed) Const {
1323 return .{
1324 .limbs = self.limbs[0..self.len()],
1325 .positive = self.isPositive(),
1326 };
1327 }
24031328
2404test "big.int div trunc single-single +/+" {
2405 const u: i32 = 5;
2406 const v: i32 = 3;
1329 /// Creates a new `Managed` with value `value`.
1330 ///
1331 /// This is identical to an `init`, followed by a `set`.
1332 pub fn initSet(allocator: *Allocator, value: var) !Managed {
1333 var s = try Managed.init(allocator);
1334 try s.set(value);
1335 return s;
1336 }
24071337
2408 var a = try Int.initSet(testing.allocator, u);
2409 defer a.deinit();
2410 var b = try Int.initSet(testing.allocator, v);
2411 defer b.deinit();
1338 /// Creates a new Managed with a specific capacity. If capacity < default_capacity then the
1339 /// default capacity will be used instead.
1340 /// The integer value after initializing is `0`.
1341 pub fn initCapacity(allocator: *Allocator, capacity: usize) !Managed {
1342 return Managed{
1343 .allocator = allocator,
1344 .metadata = 1,
1345 .limbs = block: {
1346 const limbs = try allocator.alloc(Limb, math.max(default_capacity, capacity));
1347 limbs[0] = 0;
1348 break :block limbs;
1349 },
1350 };
1351 }
24121352
2413 var q = try Int.init(testing.allocator);
2414 defer q.deinit();
2415 var r = try Int.init(testing.allocator);
2416 defer r.deinit();
2417 try Int.divTrunc(&q, &r, a, b);
1353 /// Returns the number of limbs currently in use.
1354 pub fn len(self: Managed) usize {
1355 return self.metadata & ~sign_bit;
1356 }
24181357
2419 // n = q * d + r
2420 // 5 = 1 * 3 + 2
2421 const eq = @divTrunc(u, v);
2422 const er = @mod(u, v);
1358 /// Returns whether an Managed is positive.
1359 pub fn isPositive(self: Managed) bool {
1360 return self.metadata & sign_bit == 0;
1361 }
24231362
2424 testing.expect((try q.to(i32)) == eq);
2425 testing.expect((try r.to(i32)) == er);
2426}
1363 /// Sets the sign of an Managed.
1364 pub fn setSign(self: *Managed, positive: bool) void {
1365 if (positive) {
1366 self.metadata &= ~sign_bit;
1367 } else {
1368 self.metadata |= sign_bit;
1369 }
1370 }
24271371
2428test "big.int div trunc single-single -/+" {
2429 const u: i32 = -5;
2430 const v: i32 = 3;
1372 /// Sets the length of an Managed.
1373 ///
1374 /// If setLen is used, then the Managed must be normalized to suit.
1375 pub fn setLen(self: *Managed, new_len: usize) void {
1376 self.metadata &= sign_bit;
1377 self.metadata |= new_len;
1378 }
24311379
2432 var a = try Int.initSet(testing.allocator, u);
2433 defer a.deinit();
2434 var b = try Int.initSet(testing.allocator, v);
2435 defer b.deinit();
1380 pub fn setMetadata(self: *Managed, positive: bool, length: usize) void {
1381 self.metadata = if (positive) length & ~sign_bit else length | sign_bit;
1382 }
24361383
2437 var q = try Int.init(testing.allocator);
2438 defer q.deinit();
2439 var r = try Int.init(testing.allocator);
2440 defer r.deinit();
2441 try Int.divTrunc(&q, &r, a, b);
1384 /// Ensures an Managed has enough space allocated for capacity limbs. If the Managed does not have
1385 /// sufficient capacity, the exact amount will be allocated. This occurs even if the requested
1386 /// capacity is only greater than the current capacity by one limb.
1387 pub fn ensureCapacity(self: *Managed, capacity: usize) !void {
1388 if (capacity <= self.limbs.len) {
1389 return;
1390 }
1391 self.limbs = try self.allocator.realloc(self.limbs, capacity);
1392 }
24421393
2443 // n = q * d + r
2444 // -5 = 1 * -3 - 2
2445 const eq = -1;
2446 const er = -2;
1394 /// Frees all associated memory.
1395 pub fn deinit(self: *Managed) void {
1396 self.allocator.free(self.limbs);
1397 self.* = undefined;
1398 }
24471399
2448 testing.expect((try q.to(i32)) == eq);
2449 testing.expect((try r.to(i32)) == er);
2450}
1400 /// Returns a `Managed` with the same value. The returned `Managed` is a deep copy and
1401 /// can be modified separately from the original, and its resources are managed
1402 /// separately from the original.
1403 pub fn clone(other: Managed) !Managed {
1404 return other.cloneWithDifferentAllocator(other.allocator);
1405 }
24511406
2452test "big.int div trunc single-single +/-" {
2453 const u: i32 = 5;
2454 const v: i32 = -3;
1407 pub fn cloneWithDifferentAllocator(other: Managed, allocator: *Allocator) !Managed {
1408 return Managed{
1409 .allocator = allocator,
1410 .metadata = other.metadata,
1411 .limbs = block: {
1412 var limbs = try allocator.alloc(Limb, other.len());
1413 mem.copy(Limb, limbs[0..], other.limbs[0..other.len()]);
1414 break :block limbs;
1415 },
1416 };
1417 }
24551418
2456 var a = try Int.initSet(testing.allocator, u);
2457 defer a.deinit();
2458 var b = try Int.initSet(testing.allocator, v);
2459 defer b.deinit();
1419 /// Copies the value of the integer to an existing `Managed` so that they both have the same value.
1420 /// Extra memory will be allocated if the receiver does not have enough capacity.
1421 pub fn copy(self: *Managed, other: Const) !void {
1422 if (self.limbs.ptr == other.limbs.ptr) return;
24601423
2461 var q = try Int.init(testing.allocator);
2462 defer q.deinit();
2463 var r = try Int.init(testing.allocator);
2464 defer r.deinit();
2465 try Int.divTrunc(&q, &r, a, b);
1424 try self.ensureCapacity(other.limbs.len);
1425 mem.copy(Limb, self.limbs[0..], other.limbs[0..other.limbs.len]);
1426 self.setMetadata(other.positive, other.limbs.len);
1427 }
24661428
2467 // n = q * d + r
2468 // 5 = -1 * -3 + 2
2469 const eq = -1;
2470 const er = 2;
1429 /// Efficiently swap a `Managed` with another. This swaps the limb pointers and a full copy is not
1430 /// performed. The address of the limbs field will not be the same after this function.
1431 pub fn swap(self: *Managed, other: *Managed) void {
1432 mem.swap(Managed, self, other);
1433 }
24711434
2472 testing.expect((try q.to(i32)) == eq);
2473 testing.expect((try r.to(i32)) == er);
2474}
1435 /// Debugging tool: prints the state to stderr.
1436 pub fn dump(self: Managed) void {
1437 for (self.limbs[0..self.len()]) |limb| {
1438 std.debug.warn("{x} ", .{limb});
1439 }
1440 std.debug.warn("capacity={} positive={}\n", .{ self.limbs.len, self.positive });
1441 }
24751442
2476test "big.int div trunc single-single -/-" {
2477 const u: i32 = -5;
2478 const v: i32 = -3;
1443 /// Negate the sign.
1444 pub fn negate(self: *Managed) void {
1445 self.metadata ^= sign_bit;
1446 }
24791447
2480 var a = try Int.initSet(testing.allocator, u);
2481 defer a.deinit();
2482 var b = try Int.initSet(testing.allocator, v);
2483 defer b.deinit();
1448 /// Make positive.
1449 pub fn abs(self: *Managed) void {
1450 self.metadata &= ~sign_bit;
1451 }
24841452
2485 var q = try Int.init(testing.allocator);
2486 defer q.deinit();
2487 var r = try Int.init(testing.allocator);
2488 defer r.deinit();
2489 try Int.divTrunc(&q, &r, a, b);
1453 pub fn isOdd(self: Managed) bool {
1454 return self.limbs[0] & 1 != 0;
1455 }
24901456
2491 // n = q * d + r
2492 // -5 = 1 * -3 - 2
2493 const eq = 1;
2494 const er = -2;
1457 pub fn isEven(self: Managed) bool {
1458 return !self.isOdd();
1459 }
24951460
2496 testing.expect((try q.to(i32)) == eq);
2497 testing.expect((try r.to(i32)) == er);
2498}
1461 /// Returns the number of bits required to represent the absolute value of an integer.
1462 pub fn bitCountAbs(self: Managed) usize {
1463 return self.toConst().bitCountAbs();
1464 }
24991465
2500test "big.int div floor single-single +/+" {
2501 const u: i32 = 5;
2502 const v: i32 = 3;
1466 /// Returns the number of bits required to represent the integer in twos-complement form.
1467 ///
1468 /// If the integer is negative the value returned is the number of bits needed by a signed
1469 /// integer to represent the value. If positive the value is the number of bits for an
1470 /// unsigned integer. Any unsigned integer will fit in the signed integer with bitcount
1471 /// one greater than the returned value.
1472 ///
1473 /// e.g. -127 returns 8 as it will fit in an i8. 127 returns 7 since it fits in a u7.
1474 pub fn bitCountTwosComp(self: Managed) usize {
1475 return self.toConst().bitCountTwosComp();
1476 }
25031477
2504 var a = try Int.initSet(testing.allocator, u);
2505 defer a.deinit();
2506 var b = try Int.initSet(testing.allocator, v);
2507 defer b.deinit();
1478 pub fn fitsInTwosComp(self: Managed, is_signed: bool, bit_count: usize) bool {
1479 return self.toConst().fitsInTwosComp(is_signed, bit_count);
1480 }
25081481
2509 var q = try Int.init(testing.allocator);
2510 defer q.deinit();
2511 var r = try Int.init(testing.allocator);
2512 defer r.deinit();
2513 try Int.divFloor(&q, &r, a, b);
1482 /// Returns whether self can fit into an integer of the requested type.
1483 pub fn fits(self: Managed, comptime T: type) bool {
1484 return self.toConst().fits(T);
1485 }
25141486
2515 // n = q * d + r
2516 // 5 = 1 * 3 + 2
2517 const eq = 1;
2518 const er = 2;
1487 /// Returns the approximate size of the integer in the given base. Negative values accommodate for
1488 /// the minus sign. This is used for determining the number of characters needed to print the
1489 /// value. It is inexact and may exceed the given value by ~1-2 bytes.
1490 pub fn sizeInBaseUpperBound(self: Managed, base: usize) usize {
1491 return self.toConst().sizeInBaseUpperBound(base);
1492 }
25191493
2520 testing.expect((try q.to(i32)) == eq);
2521 testing.expect((try r.to(i32)) == er);
2522}
1494 /// Sets an Managed to value. Value must be an primitive integer type.
1495 pub fn set(self: *Managed, value: var) Allocator.Error!void {
1496 try self.ensureCapacity(calcLimbLen(value));
1497 var m = self.toMutable();
1498 m.set(value);
1499 self.setMetadata(m.positive, m.len);
1500 }
25231501
2524test "big.int div floor single-single -/+" {
2525 const u: i32 = -5;
2526 const v: i32 = 3;
1502 pub const ConvertError = Const.ConvertError;
25271503
2528 var a = try Int.initSet(testing.allocator, u);
2529 defer a.deinit();
2530 var b = try Int.initSet(testing.allocator, v);
2531 defer b.deinit();
1504 /// Convert self to type T.
1505 ///
1506 /// Returns an error if self cannot be narrowed into the requested type without truncation.
1507 pub fn to(self: Managed, comptime T: type) ConvertError!T {
1508 return self.toConst().to(T);
1509 }
25321510
2533 var q = try Int.init(testing.allocator);
2534 defer q.deinit();
2535 var r = try Int.init(testing.allocator);
2536 defer r.deinit();
2537 try Int.divFloor(&q, &r, a, b);
1511 /// Set self from the string representation `value`.
1512 ///
1513 /// `value` must contain only digits <= `base` and is case insensitive. Base prefixes are
1514 /// not allowed (e.g. 0x43 should simply be 43). Underscores in the input string are
1515 /// ignored and can be used as digit separators.
1516 ///
1517 /// Returns an error if memory could not be allocated or `value` has invalid digits for the
1518 /// requested base.
1519 ///
1520 /// self's allocator is used for temporary storage to boost multiplication performance.
1521 pub fn setString(self: *Managed, base: u8, value: []const u8) !void {
1522 if (base < 2 or base > 16) return error.InvalidBase;
1523 const den = (@sizeOf(Limb) * 8 / base);
1524 try self.ensureCapacity((value.len + (den - 1)) / den);
1525 const limbs_buffer = try self.allocator.alloc(Limb, calcSetStringLimbsBufferLen(base, value.len));
1526 defer self.allocator.free(limbs_buffer);
1527 var m = self.toMutable();
1528 try m.setString(base, value, limbs_buffer, self.allocator);
1529 self.setMetadata(m.positive, m.len);
1530 }
25381531
2539 // n = q * d + r
2540 // -5 = -2 * 3 + 1
2541 const eq = -2;
2542 const er = 1;
1532 /// Converts self to a string in the requested base. Memory is allocated from the provided
1533 /// allocator and not the one present in self.
1534 pub fn toString(self: Managed, allocator: *Allocator, base: u8, uppercase: bool) ![]u8 {
1535 if (base < 2 or base > 16) return error.InvalidBase;
1536 return self.toConst().toStringAlloc(self.allocator, base, uppercase);
1537 }
25431538
2544 testing.expect((try q.to(i32)) == eq);
2545 testing.expect((try r.to(i32)) == er);
2546}
1539 /// To allow `std.fmt.format` to work with `Managed`.
1540 /// If the integer is larger than `pow(2, 64 * @sizeOf(usize) * 8), this function will fail
1541 /// to print the string, printing "(BigInt)" instead of a number.
1542 /// This is because the rendering algorithm requires reversing a string, which requires O(N) memory.
1543 /// See `toString` and `toStringAlloc` for a way to print big integers without failure.
1544 pub fn format(
1545 self: Managed,
1546 comptime fmt: []const u8,
1547 options: std.fmt.FormatOptions,
1548 out_stream: var,
1549 ) !void {
1550 return self.toConst().format(fmt, options, out_stream);
1551 }
25471552
2548test "big.int div floor single-single +/-" {
2549 const u: i32 = 5;
2550 const v: i32 = -3;
1553 /// Returns math.Order.lt, math.Order.eq, math.Order.gt if |a| < |b|, |a| ==
1554 /// |b| or |a| > |b| respectively.
1555 pub fn orderAbs(a: Managed, b: Managed) math.Order {
1556 return a.toConst().orderAbs(b.toConst());
1557 }
25511558
2552 var a = try Int.initSet(testing.allocator, u);
2553 defer a.deinit();
2554 var b = try Int.initSet(testing.allocator, v);
2555 defer b.deinit();
1559 /// Returns math.Order.lt, math.Order.eq, math.Order.gt if a < b, a == b or a
1560 /// > b respectively.
1561 pub fn order(a: Managed, b: Managed) math.Order {
1562 return a.toConst().order(b.toConst());
1563 }
25561564
2557 var q = try Int.init(testing.allocator);
2558 defer q.deinit();
2559 var r = try Int.init(testing.allocator);
2560 defer r.deinit();
2561 try Int.divFloor(&q, &r, a, b);
1565 /// Returns true if a == 0.
1566 pub fn eqZero(a: Managed) bool {
1567 return a.toConst().eqZero();
1568 }
25621569
2563 // n = q * d + r
2564 // 5 = -2 * -3 - 1
2565 const eq = -2;
2566 const er = -1;
1570 /// Returns true if |a| == |b|.
1571 pub fn eqAbs(a: Managed, b: Managed) bool {
1572 return a.toConst().eqAbs(b.toConst());
1573 }
25671574
2568 testing.expect((try q.to(i32)) == eq);
2569 testing.expect((try r.to(i32)) == er);
2570}
1575 /// Returns true if a == b.
1576 pub fn eq(a: Managed, b: Managed) bool {
1577 return a.toConst().eq(b.toConst());
1578 }
25711579
2572test "big.int div floor single-single -/-" {
2573 const u: i32 = -5;
2574 const v: i32 = -3;
1580 /// Normalize a possible sequence of leading zeros.
1581 ///
1582 /// [1, 2, 3, 4, 0] -> [1, 2, 3, 4]
1583 /// [1, 2, 0, 0, 0] -> [1, 2]
1584 /// [0, 0, 0, 0, 0] -> [0]
1585 pub fn normalize(r: *Managed, length: usize) void {
1586 assert(length > 0);
1587 assert(length <= r.limbs.len);
25751588
2576 var a = try Int.initSet(testing.allocator, u);
2577 defer a.deinit();
2578 var b = try Int.initSet(testing.allocator, v);
2579 defer b.deinit();
1589 var j = length;
1590 while (j > 0) : (j -= 1) {
1591 if (r.limbs[j - 1] != 0) {
1592 break;
1593 }
1594 }
25801595
2581 var q = try Int.init(testing.allocator);
2582 defer q.deinit();
2583 var r = try Int.init(testing.allocator);
2584 defer r.deinit();
2585 try Int.divFloor(&q, &r, a, b);
1596 // Handle zero
1597 r.setLen(if (j != 0) j else 1);
1598 }
25861599
2587 // n = q * d + r
2588 // -5 = 2 * -3 + 1
2589 const eq = 1;
2590 const er = -2;
1600 /// r = a + scalar
1601 ///
1602 /// r and a may be aliases.
1603 /// scalar is a primitive integer type.
1604 ///
1605 /// Returns an error if memory could not be allocated.
1606 pub fn addScalar(r: *Managed, a: Const, scalar: var) Allocator.Error!void {
1607 try r.ensureCapacity(math.max(a.limbs.len, calcLimbLen(scalar)) + 1);
1608 var m = r.toMutable();
1609 m.addScalar(a, scalar);
1610 r.setMetadata(m.positive, m.len);
1611 }
25911612
2592 testing.expect((try q.to(i32)) == eq);
2593 testing.expect((try r.to(i32)) == er);
2594}
1613 /// r = a + b
1614 ///
1615 /// r, a and b may be aliases.
1616 ///
1617 /// Returns an error if memory could not be allocated.
1618 pub fn add(r: *Managed, a: Const, b: Const) Allocator.Error!void {
1619 try r.ensureCapacity(math.max(a.limbs.len, b.limbs.len) + 1);
1620 var m = r.toMutable();
1621 m.add(a, b);
1622 r.setMetadata(m.positive, m.len);
1623 }
25951624
2596test "big.int div multi-multi with rem" {
2597 var a = try Int.initSet(testing.allocator, 0x8888999911110000ffffeeeeddddccccbbbbaaaa9999);
2598 defer a.deinit();
2599 var b = try Int.initSet(testing.allocator, 0x99990000111122223333);
2600 defer b.deinit();
1625 /// r = a - b
1626 ///
1627 /// r, a and b may be aliases.
1628 ///
1629 /// Returns an error if memory could not be allocated.
1630 pub fn sub(r: *Managed, a: Const, b: Const) !void {
1631 try r.ensureCapacity(math.max(a.limbs.len, b.limbs.len) + 1);
1632 var m = r.toMutable();
1633 m.sub(a, b);
1634 r.setMetadata(m.positive, m.len);
1635 }
26011636
2602 var q = try Int.init(testing.allocator);
2603 defer q.deinit();
2604 var r = try Int.init(testing.allocator);
2605 defer r.deinit();
2606 try Int.divTrunc(&q, &r, a, b);
1637 /// rma = a * b
1638 ///
1639 /// rma, a and b may be aliases. However, it is more efficient if rma does not alias a or b.
1640 ///
1641 /// Returns an error if memory could not be allocated.
1642 ///
1643 /// rma's allocator is used for temporary storage to speed up the multiplication.
1644 pub fn mul(rma: *Managed, a: Const, b: Const) !void {
1645 try rma.ensureCapacity(a.limbs.len + b.limbs.len + 1);
1646 var alias_count: usize = 0;
1647 if (rma.limbs.ptr == a.limbs.ptr)
1648 alias_count += 1;
1649 if (rma.limbs.ptr == b.limbs.ptr)
1650 alias_count += 1;
1651 var m = rma.toMutable();
1652 if (alias_count == 0) {
1653 m.mulNoAlias(a, b, rma.allocator);
1654 } else {
1655 const limb_count = calcMulLimbsBufferLen(a.limbs.len, b.limbs.len, alias_count);
1656 const limbs_buffer = try rma.allocator.alloc(Limb, limb_count);
1657 defer rma.allocator.free(limbs_buffer);
1658 m.mul(a, b, limbs_buffer, rma.allocator);
1659 }
1660 rma.setMetadata(m.positive, m.len);
1661 }
26071662
2608 testing.expect((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b);
2609 testing.expect((try r.to(u128)) == 0x28de0acacd806823638);
2610}
1663 /// q = a / b (rem r)
1664 ///
1665 /// a / b are floored (rounded towards 0).
1666 ///
1667 /// Returns an error if memory could not be allocated.
1668 ///
1669 /// q's allocator is used for temporary storage to speed up the multiplication.
1670 pub fn divFloor(q: *Managed, r: *Managed, a: Const, b: Const) !void {
1671 try q.ensureCapacity(a.limbs.len + b.limbs.len + 1);
1672 try r.ensureCapacity(a.limbs.len);
1673 var mq = q.toMutable();
1674 var mr = r.toMutable();
1675 const limbs_buffer = try q.allocator.alloc(Limb, calcDivLimbsBufferLen(a.limbs.len, b.limbs.len));
1676 defer q.allocator.free(limbs_buffer);
1677 mq.divFloor(&mr, a, b, limbs_buffer, q.allocator);
1678 q.setMetadata(mq.positive, mq.len);
1679 r.setMetadata(mr.positive, mr.len);
1680 }
26111681
2612test "big.int div multi-multi no rem" {
2613 var a = try Int.initSet(testing.allocator, 0x8888999911110000ffffeeeedb4fec200ee3a4286361);
2614 defer a.deinit();
2615 var b = try Int.initSet(testing.allocator, 0x99990000111122223333);
2616 defer b.deinit();
1682 /// q = a / b (rem r)
1683 ///
1684 /// a / b are truncated (rounded towards -inf).
1685 ///
1686 /// Returns an error if memory could not be allocated.
1687 ///
1688 /// q's allocator is used for temporary storage to speed up the multiplication.
1689 pub fn divTrunc(q: *Managed, r: *Managed, a: Const, b: Const) !void {
1690 try q.ensureCapacity(a.limbs.len + b.limbs.len + 1);
1691 try r.ensureCapacity(a.limbs.len);
1692 var mq = q.toMutable();
1693 var mr = r.toMutable();
1694 const limbs_buffer = try q.allocator.alloc(Limb, calcDivLimbsBufferLen(a.limbs.len, b.limbs.len));
1695 defer q.allocator.free(limbs_buffer);
1696 mq.divTrunc(&mr, a, b, limbs_buffer, q.allocator);
1697 q.setMetadata(mq.positive, mq.len);
1698 r.setMetadata(mr.positive, mr.len);
1699 }
26171700
2618 var q = try Int.init(testing.allocator);
2619 defer q.deinit();
2620 var r = try Int.init(testing.allocator);
2621 defer r.deinit();
2622 try Int.divTrunc(&q, &r, a, b);
1701 /// r = a << shift, in other words, r = a * 2^shift
1702 pub fn shiftLeft(r: *Managed, a: Managed, shift: usize) !void {
1703 try r.ensureCapacity(a.len() + (shift / Limb.bit_count) + 1);
1704 var m = r.toMutable();
1705 m.shiftLeft(a.toConst(), shift);
1706 r.setMetadata(m.positive, m.len);
1707 }
26231708
2624 testing.expect((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b);
2625 testing.expect((try r.to(u128)) == 0);
2626}
1709 /// r = a >> shift
1710 pub fn shiftRight(r: *Managed, a: Managed, shift: usize) !void {
1711 if (a.len() <= shift / Limb.bit_count) {
1712 r.metadata = 1;
1713 r.limbs[0] = 0;
1714 return;
1715 }
26271716
2628test "big.int div multi-multi (2 branch)" {
2629 var a = try Int.initSet(testing.allocator, 0x866666665555555588888887777777761111111111111111);
2630 defer a.deinit();
2631 var b = try Int.initSet(testing.allocator, 0x86666666555555554444444433333333);
2632 defer b.deinit();
1717 try r.ensureCapacity(a.len() - (shift / Limb.bit_count));
1718 var m = r.toMutable();
1719 m.shiftRight(a.toConst(), shift);
1720 r.setMetadata(m.positive, m.len);
1721 }
26331722
2634 var q = try Int.init(testing.allocator);
2635 defer q.deinit();
2636 var r = try Int.init(testing.allocator);
2637 defer r.deinit();
2638 try Int.divTrunc(&q, &r, a, b);
1723 /// r = a | b
1724 ///
1725 /// a and b are zero-extended to the longer of a or b.
1726 pub fn bitOr(r: *Managed, a: Managed, b: Managed) !void {
1727 try r.ensureCapacity(math.max(a.len(), b.len()));
1728 var m = r.toMutable();
1729 m.bitOr(a.toConst(), b.toConst());
1730 r.setMetadata(m.positive, m.len);
1731 }
26391732
2640 testing.expect((try q.to(u128)) == 0x10000000000000000);
2641 testing.expect((try r.to(u128)) == 0x44444443444444431111111111111111);
2642}
1733 /// r = a & b
1734 pub fn bitAnd(r: *Managed, a: Managed, b: Managed) !void {
1735 try r.ensureCapacity(math.min(a.len(), b.len()));
1736 var m = r.toMutable();
1737 m.bitAnd(a.toConst(), b.toConst());
1738 r.setMetadata(m.positive, m.len);
1739 }
26431740
2644test "big.int div multi-multi (3.1/3.3 branch)" {
2645 var a = try Int.initSet(testing.allocator, 0x11111111111111111111111111111111111111111111111111111111111111);
2646 defer a.deinit();
2647 var b = try Int.initSet(testing.allocator, 0x1111111111111111111111111111111111111111171);
2648 defer b.deinit();
1741 /// r = a ^ b
1742 pub fn bitXor(r: *Managed, a: Managed, b: Managed) !void {
1743 try r.ensureCapacity(math.max(a.len(), b.len()));
1744 var m = r.toMutable();
1745 m.bitXor(a.toConst(), b.toConst());
1746 r.setMetadata(m.positive, m.len);
1747 }
26491748
2650 var q = try Int.init(testing.allocator);
2651 defer q.deinit();
2652 var r = try Int.init(testing.allocator);
2653 defer r.deinit();
2654 try Int.divTrunc(&q, &r, a, b);
1749 /// rma may alias x or y.
1750 /// x and y may alias each other.
1751 ///
1752 /// rma's allocator is used for temporary storage to boost multiplication performance.
1753 pub fn gcd(rma: *Managed, x: Managed, y: Managed) !void {
1754 try rma.ensureCapacity(math.min(x.len(), y.len()));
1755 var m = rma.toMutable();
1756 var limbs_buffer = std.ArrayList(Limb).init(rma.allocator);
1757 defer limbs_buffer.deinit();
1758 try m.gcd(x.toConst(), y.toConst(), &limbs_buffer);
1759 rma.setMetadata(m.positive, m.len);
1760 }
1761};
26551762
2656 testing.expect((try q.to(u128)) == 0xfffffffffffffffffff);
2657 testing.expect((try r.to(u256)) == 0x1111111111111111111110b12222222222222222282);
2658}
1763/// Knuth 4.3.1, Algorithm M.
1764///
1765/// r MUST NOT alias any of a or b.
1766fn llmulacc(opt_allocator: ?*Allocator, r: []Limb, a: []const Limb, b: []const Limb) void {
1767 @setRuntimeSafety(false);
1768
1769 const a_norm = a[0..llnormalize(a)];
1770 const b_norm = b[0..llnormalize(b)];
1771 var x = a_norm;
1772 var y = b_norm;
1773 if (a_norm.len > b_norm.len) {
1774 x = b_norm;
1775 y = a_norm;
1776 }
1777
1778 assert(r.len >= x.len + y.len + 1);
1779
1780 // 48 is a pretty abitrary size chosen based on performance of a factorial program.
1781 if (x.len > 48) {
1782 if (opt_allocator) |allocator| {
1783 llmulacc_karatsuba(allocator, r, x, y) catch |err| switch (err) {
1784 error.OutOfMemory => {}, // handled below
1785 };
1786 }
1787 }
26591788
2660test "big.int div multi-single zero-limb trailing" {
2661 var a = try Int.initSet(testing.allocator, 0x60000000000000000000000000000000000000000000000000000000000000000);
2662 defer a.deinit();
2663 var b = try Int.initSet(testing.allocator, 0x10000000000000000);
2664 defer b.deinit();
2665
2666 var q = try Int.init(testing.allocator);
2667 defer q.deinit();
2668 var r = try Int.init(testing.allocator);
2669 defer r.deinit();
2670 try Int.divTrunc(&q, &r, a, b);
2671
2672 var expected = try Int.initSet(testing.allocator, 0x6000000000000000000000000000000000000000000000000);
2673 defer expected.deinit();
2674 testing.expect(q.eq(expected));
2675 testing.expect(r.eqZero());
1789 // Basecase multiplication
1790 var i: usize = 0;
1791 while (i < x.len) : (i += 1) {
1792 llmulDigit(r[i..], y, x[i]);
1793 }
26761794}
26771795
2678test "big.int div multi-multi zero-limb trailing (with rem)" {
2679 var a = try Int.initSet(testing.allocator, 0x86666666555555558888888777777776111111111111111100000000000000000000000000000000);
2680 defer a.deinit();
2681 var b = try Int.initSet(testing.allocator, 0x8666666655555555444444443333333300000000000000000000000000000000);
2682 defer b.deinit();
2683
2684 var q = try Int.init(testing.allocator);
2685 defer q.deinit();
2686 var r = try Int.init(testing.allocator);
2687 defer r.deinit();
2688 try Int.divTrunc(&q, &r, a, b);
2689
2690 testing.expect((try q.to(u128)) == 0x10000000000000000);
1796/// Knuth 4.3.1, Algorithm M.
1797///
1798/// r MUST NOT alias any of a or b.
1799fn llmulacc_karatsuba(allocator: *Allocator, r: []Limb, x: []const Limb, y: []const Limb) error{OutOfMemory}!void {
1800 @setRuntimeSafety(false);
26911801
2692 const rs = try r.toString(testing.allocator, 16, false);
2693 defer testing.allocator.free(rs);
2694 testing.expect(std.mem.eql(u8, rs, "4444444344444443111111111111111100000000000000000000000000000000"));
2695}
1802 assert(r.len >= x.len + y.len + 1);
26961803
2697test "big.int div multi-multi zero-limb trailing (with rem) and dividend zero-limb count > divisor zero-limb count" {
2698 var a = try Int.initSet(testing.allocator, 0x8666666655555555888888877777777611111111111111110000000000000000);
2699 defer a.deinit();
2700 var b = try Int.initSet(testing.allocator, 0x8666666655555555444444443333333300000000000000000000000000000000);
2701 defer b.deinit();
1804 const split = @divFloor(x.len, 2);
1805 var x0 = x[0..split];
1806 var x1 = x[split..x.len];
1807 var y0 = y[0..split];
1808 var y1 = y[split..y.len];
27021809
2703 var q = try Int.init(testing.allocator);
2704 defer q.deinit();
2705 var r = try Int.init(testing.allocator);
2706 defer r.deinit();
2707 try Int.divTrunc(&q, &r, a, b);
1810 var tmp = try allocator.alloc(Limb, x1.len + y1.len + 1);
1811 defer allocator.free(tmp);
1812 mem.set(Limb, tmp, 0);
27081813
2709 testing.expect((try q.to(u128)) == 0x1);
1814 llmulacc(allocator, tmp, x1, y1);
27101815
2711 const rs = try r.toString(testing.allocator, 16, false);
2712 defer testing.allocator.free(rs);
2713 testing.expect(std.mem.eql(u8, rs, "444444434444444311111111111111110000000000000000"));
2714}
1816 var length = llnormalize(tmp);
1817 _ = llaccum(r[split..], tmp[0..length]);
1818 _ = llaccum(r[split * 2 ..], tmp[0..length]);
27151819
2716test "big.int div multi-multi zero-limb trailing (with rem) and dividend zero-limb count < divisor zero-limb count" {
2717 var a = try Int.initSet(testing.allocator, 0x86666666555555558888888777777776111111111111111100000000000000000000000000000000);
2718 defer a.deinit();
2719 var b = try Int.initSet(testing.allocator, 0x866666665555555544444444333333330000000000000000);
2720 defer b.deinit();
2721
2722 var q = try Int.init(testing.allocator);
2723 defer q.deinit();
2724 var r = try Int.init(testing.allocator);
2725 defer r.deinit();
2726 try Int.divTrunc(&q, &r, a, b);
2727
2728 const qs = try q.toString(testing.allocator, 16, false);
2729 defer testing.allocator.free(qs);
2730 testing.expect(std.mem.eql(u8, qs, "10000000000000000820820803105186f"));
2731
2732 const rs = try r.toString(testing.allocator, 16, false);
2733 defer testing.allocator.free(rs);
2734 testing.expect(std.mem.eql(u8, rs, "4e11f2baa5896a321d463b543d0104e30000000000000000"));
2735}
1820 mem.set(Limb, tmp[0..length], 0);
27361821
2737test "big.int div multi-multi fuzz case #1" {
2738 var a = try Int.init(testing.allocator);
2739 defer a.deinit();
2740 var b = try Int.init(testing.allocator);
2741 defer b.deinit();
1822 llmulacc(allocator, tmp, x0, y0);
27421823
2743 try a.setString(16, "ffffffffffffffffffffffffffffc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
2744 try b.setString(16, "3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffc000000000000000000000000000000007fffffffffff");
1824 length = llnormalize(tmp);
1825 _ = llaccum(r[0..], tmp[0..length]);
1826 _ = llaccum(r[split..], tmp[0..length]);
27451827
2746 var q = try Int.init(testing.allocator);
2747 defer q.deinit();
2748 var r = try Int.init(testing.allocator);
2749 defer r.deinit();
2750 try Int.divTrunc(&q, &r, a, b);
1828 const x_cmp = llcmp(x1, x0);
1829 const y_cmp = llcmp(y1, y0);
1830 if (x_cmp * y_cmp == 0) {
1831 return;
1832 }
1833 const x0_len = llnormalize(x0);
1834 const x1_len = llnormalize(x1);
1835 var j0 = try allocator.alloc(Limb, math.max(x0_len, x1_len));
1836 defer allocator.free(j0);
1837 if (x_cmp == 1) {
1838 llsub(j0, x1[0..x1_len], x0[0..x0_len]);
1839 } else {
1840 llsub(j0, x0[0..x0_len], x1[0..x1_len]);
1841 }
27511842
2752 const qs = try q.toString(testing.allocator, 16, false);
2753 defer testing.allocator.free(qs);
2754 testing.expect(std.mem.eql(u8, qs, "3ffffffffffffffffffffffffffff0000000000000000000000000000000000001ffffffffffffffffffffffffffff7fffffffe000000000000000000000000000180000000000000000000003fffffbfffffffdfffffffffffffeffff800000100101000000100000000020003fffffdfbfffffe3ffffffffffffeffff7fffc00800a100000017ffe000002000400007efbfff7fe9f00000037ffff3fff7fffa004006100000009ffe00000190038200bf7d2ff7fefe80400060000f7d7f8fbf9401fe38e0403ffc0bdffffa51102c300d7be5ef9df4e5060007b0127ad3fa69f97d0f820b6605ff617ddf7f32ad7a05c0d03f2e7bc78a6000e087a8bbcdc59e07a5a079128a7861f553ddebed7e8e56701756f9ead39b48cd1b0831889ea6ec1fddf643d0565b075ff07e6caea4e2854ec9227fd635ed60a2f5eef2893052ffd54718fa08604acbf6a15e78a467c4a3c53c0278af06c4416573f925491b195e8fd79302cb1aaf7caf4ecfc9aec1254cc969786363ac729f914c6ddcc26738d6b0facd54eba026580aba2eb6482a088b0d224a8852420b91ec1"));
1843 const y0_len = llnormalize(y0);
1844 const y1_len = llnormalize(y1);
1845 var j1 = try allocator.alloc(Limb, math.max(y0_len, y1_len));
1846 defer allocator.free(j1);
1847 if (y_cmp == 1) {
1848 llsub(j1, y1[0..y1_len], y0[0..y0_len]);
1849 } else {
1850 llsub(j1, y0[0..y0_len], y1[0..y1_len]);
1851 }
1852 const j0_len = llnormalize(j0);
1853 const j1_len = llnormalize(j1);
1854 if (x_cmp == y_cmp) {
1855 mem.set(Limb, tmp[0..length], 0);
1856 llmulacc(allocator, tmp, j0, j1);
27551857
2756 const rs = try r.toString(testing.allocator, 16, false);
2757 defer testing.allocator.free(rs);
2758 testing.expect(std.mem.eql(u8, rs, "310d1d4c414426b4836c2635bad1df3a424e50cbdd167ffccb4dfff57d36b4aae0d6ca0910698220171a0f3373c1060a046c2812f0027e321f72979daa5e7973214170d49e885de0c0ecc167837d44502430674a82522e5df6a0759548052420b91ec1"));
1858 length = llnormalize(tmp);
1859 llsub(r[split..], r[split..], tmp[0..length]);
1860 } else {
1861 llmulacc(allocator, r[split..], j0, j1);
1862 }
27591863}
27601864
2761test "big.int div multi-multi fuzz case #2" {
2762 var a = try Int.init(testing.allocator);
2763 defer a.deinit();
2764 var b = try Int.init(testing.allocator);
2765 defer b.deinit();
1865// r = r + a
1866fn llaccum(r: []Limb, a: []const Limb) Limb {
1867 @setRuntimeSafety(false);
1868 assert(r.len != 0 and a.len != 0);
1869 assert(r.len >= a.len);
27661870
2767 try a.setString(16, "3ffffffffe00000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000000000000000000000000000000000000000000000000000000000000001fffffffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffc000000000000000000000000000000000000000000000000000000000000000");
2768 try b.setString(16, "ffc0000000000000000000000000000000000000000000000000");
1871 var i: usize = 0;
1872 var carry: Limb = 0;
27691873
2770 var q = try Int.init(testing.allocator);
2771 defer q.deinit();
2772 var r = try Int.init(testing.allocator);
2773 defer r.deinit();
2774 try Int.divTrunc(&q, &r, a, b);
1874 while (i < a.len) : (i += 1) {
1875 var c: Limb = 0;
1876 c += @boolToInt(@addWithOverflow(Limb, r[i], a[i], &r[i]));
1877 c += @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i]));
1878 carry = c;
1879 }
27751880
2776 const qs = try q.toString(testing.allocator, 16, false);
2777 defer testing.allocator.free(qs);
2778 testing.expect(std.mem.eql(u8, qs, "40100400fe3f8fe3f8fe3f8fe3f8fe3f8fe4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f91e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4992649926499264991e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4792e4b92e4b92e4b92e4b92a4a92a4a92a4"));
1881 while ((carry != 0) and i < r.len) : (i += 1) {
1882 carry = @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i]));
1883 }
27791884
2780 const rs = try r.toString(testing.allocator, 16, false);
2781 defer testing.allocator.free(rs);
2782 testing.expect(std.mem.eql(u8, rs, "a900000000000000000000000000000000000000000000000000"));
1885 return carry;
27831886}
27841887
2785test "big.int shift-right single" {
2786 var a = try Int.initSet(testing.allocator, 0xffff0000);
2787 defer a.deinit();
2788 try a.shiftRight(a, 16);
2789
2790 testing.expect((try a.to(u32)) == 0xffff);
2791}
1888/// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively for limbs.
1889pub fn llcmp(a: []const Limb, b: []const Limb) i8 {
1890 @setRuntimeSafety(false);
1891 const a_len = llnormalize(a);
1892 const b_len = llnormalize(b);
1893 if (a_len < b_len) {
1894 return -1;
1895 }
1896 if (a_len > b_len) {
1897 return 1;
1898 }
27921899
2793test "big.int shift-right multi" {
2794 var a = try Int.initSet(testing.allocator, 0xffff0000eeee1111dddd2222cccc3333);
2795 defer a.deinit();
2796 try a.shiftRight(a, 67);
1900 var i: usize = a_len - 1;
1901 while (i != 0) : (i -= 1) {
1902 if (a[i] != b[i]) {
1903 break;
1904 }
1905 }
27971906
2798 testing.expect((try a.to(u64)) == 0x1fffe0001dddc222);
1907 if (a[i] < b[i]) {
1908 return -1;
1909 } else if (a[i] > b[i]) {
1910 return 1;
1911 } else {
1912 return 0;
1913 }
27991914}
28001915
2801test "big.int shift-left single" {
2802 var a = try Int.initSet(testing.allocator, 0xffff);
2803 defer a.deinit();
2804 try a.shiftLeft(a, 16);
1916fn llmulDigit(acc: []Limb, y: []const Limb, xi: Limb) void {
1917 @setRuntimeSafety(false);
1918 if (xi == 0) {
1919 return;
1920 }
28051921
2806 testing.expect((try a.to(u64)) == 0xffff0000);
2807}
1922 var carry: usize = 0;
1923 var a_lo = acc[0..y.len];
1924 var a_hi = acc[y.len..];
28081925
2809test "big.int shift-left multi" {
2810 var a = try Int.initSet(testing.allocator, 0x1fffe0001dddc222);
2811 defer a.deinit();
2812 try a.shiftLeft(a, 67);
1926 var j: usize = 0;
1927 while (j < a_lo.len) : (j += 1) {
1928 a_lo[j] = @call(.{ .modifier = .always_inline }, addMulLimbWithCarry, .{ a_lo[j], y[j], xi, &carry });
1929 }
28131930
2814 testing.expect((try a.to(u128)) == 0xffff0000eeee11100000000000000000);
1931 j = 0;
1932 while ((carry != 0) and (j < a_hi.len)) : (j += 1) {
1933 carry = @boolToInt(@addWithOverflow(Limb, a_hi[j], carry, &a_hi[j]));
1934 }
28151935}
28161936
2817test "big.int shift-right negative" {
2818 var a = try Int.init(testing.allocator);
2819 defer a.deinit();
2820
2821 try a.shiftRight(try Int.initSet(testing.allocator, -20), 2);
2822 defer a.deinit();
2823 testing.expect((try a.to(i32)) == -20 >> 2);
1937/// returns the min length the limb could be.
1938fn llnormalize(a: []const Limb) usize {
1939 @setRuntimeSafety(false);
1940 var j = a.len;
1941 while (j > 0) : (j -= 1) {
1942 if (a[j - 1] != 0) {
1943 break;
1944 }
1945 }
28241946
2825 try a.shiftRight(try Int.initSet(testing.allocator, -5), 10);
2826 defer a.deinit();
2827 testing.expect((try a.to(i32)) == -5 >> 10);
1947 // Handle zero
1948 return if (j != 0) j else 1;
28281949}
28291950
2830test "big.int shift-left negative" {
2831 var a = try Int.init(testing.allocator);
2832 defer a.deinit();
1951/// Knuth 4.3.1, Algorithm S.
1952fn llsub(r: []Limb, a: []const Limb, b: []const Limb) void {
1953 @setRuntimeSafety(false);
1954 assert(a.len != 0 and b.len != 0);
1955 assert(a.len > b.len or (a.len == b.len and a[a.len - 1] >= b[b.len - 1]));
1956 assert(r.len >= a.len);
28331957
2834 try a.shiftRight(try Int.initSet(testing.allocator, -10), 1232);
2835 defer a.deinit();
2836 testing.expect((try a.to(i32)) == -10 >> 1232);
2837}
1958 var i: usize = 0;
1959 var borrow: Limb = 0;
28381960
2839test "big.int bitwise and simple" {
2840 var a = try Int.initSet(testing.allocator, 0xffffffff11111111);
2841 defer a.deinit();
2842 var b = try Int.initSet(testing.allocator, 0xeeeeeeee22222222);
2843 defer b.deinit();
1961 while (i < b.len) : (i += 1) {
1962 var c: Limb = 0;
1963 c += @boolToInt(@subWithOverflow(Limb, a[i], b[i], &r[i]));
1964 c += @boolToInt(@subWithOverflow(Limb, r[i], borrow, &r[i]));
1965 borrow = c;
1966 }
28441967
2845 try a.bitAnd(a, b);
1968 while (i < a.len) : (i += 1) {
1969 borrow = @boolToInt(@subWithOverflow(Limb, a[i], borrow, &r[i]));
1970 }
28461971
2847 testing.expect((try a.to(u64)) == 0xeeeeeeee00000000);
1972 assert(borrow == 0);
28481973}
28491974
2850test "big.int bitwise and multi-limb" {
2851 var a = try Int.initSet(testing.allocator, maxInt(Limb) + 1);
2852 defer a.deinit();
2853 var b = try Int.initSet(testing.allocator, maxInt(Limb));
2854 defer b.deinit();
2855
2856 try a.bitAnd(a, b);
1975/// Knuth 4.3.1, Algorithm A.
1976fn lladd(r: []Limb, a: []const Limb, b: []const Limb) void {
1977 @setRuntimeSafety(false);
1978 assert(a.len != 0 and b.len != 0);
1979 assert(a.len >= b.len);
1980 assert(r.len >= a.len + 1);
28571981
2858 testing.expect((try a.to(u128)) == 0);
2859}
1982 var i: usize = 0;
1983 var carry: Limb = 0;
28601984
2861test "big.int bitwise xor simple" {
2862 var a = try Int.initSet(testing.allocator, 0xffffffff11111111);
2863 defer a.deinit();
2864 var b = try Int.initSet(testing.allocator, 0xeeeeeeee22222222);
2865 defer b.deinit();
1985 while (i < b.len) : (i += 1) {
1986 var c: Limb = 0;
1987 c += @boolToInt(@addWithOverflow(Limb, a[i], b[i], &r[i]));
1988 c += @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i]));
1989 carry = c;
1990 }
28661991
2867 try a.bitXor(a, b);
1992 while (i < a.len) : (i += 1) {
1993 carry = @boolToInt(@addWithOverflow(Limb, a[i], carry, &r[i]));
1994 }
28681995
2869 testing.expect((try a.to(u64)) == 0x1111111133333333);
1996 r[i] = carry;
28701997}
28711998
2872test "big.int bitwise xor multi-limb" {
2873 var a = try Int.initSet(testing.allocator, maxInt(Limb) + 1);
2874 defer a.deinit();
2875 var b = try Int.initSet(testing.allocator, maxInt(Limb));
2876 defer b.deinit();
1999/// Knuth 4.3.1, Exercise 16.
2000fn lldiv1(quo: []Limb, rem: *Limb, a: []const Limb, b: Limb) void {
2001 @setRuntimeSafety(false);
2002 assert(a.len > 1 or a[0] >= b);
2003 assert(quo.len >= a.len);
28772004
2878 try a.bitXor(a, b);
2005 rem.* = 0;
2006 for (a) |_, ri| {
2007 const i = a.len - ri - 1;
2008 const pdiv = ((@as(DoubleLimb, rem.*) << Limb.bit_count) | a[i]);
28792009
2880 testing.expect((try a.to(DoubleLimb)) == (maxInt(Limb) + 1) ^ maxInt(Limb));
2010 if (pdiv == 0) {
2011 quo[i] = 0;
2012 rem.* = 0;
2013 } else if (pdiv < b) {
2014 quo[i] = 0;
2015 rem.* = @truncate(Limb, pdiv);
2016 } else if (pdiv == b) {
2017 quo[i] = 1;
2018 rem.* = 0;
2019 } else {
2020 quo[i] = @truncate(Limb, @divTrunc(pdiv, b));
2021 rem.* = @truncate(Limb, pdiv - (quo[i] *% b));
2022 }
2023 }
28812024}
28822025
2883test "big.int bitwise or simple" {
2884 var a = try Int.initSet(testing.allocator, 0xffffffff11111111);
2885 defer a.deinit();
2886 var b = try Int.initSet(testing.allocator, 0xeeeeeeee22222222);
2887 defer b.deinit();
2026fn llshl(r: []Limb, a: []const Limb, shift: usize) void {
2027 @setRuntimeSafety(false);
2028 assert(a.len >= 1);
2029 assert(r.len >= a.len + (shift / Limb.bit_count) + 1);
28882030
2889 try a.bitOr(a, b);
2031 const limb_shift = shift / Limb.bit_count + 1;
2032 const interior_limb_shift = @intCast(Log2Limb, shift % Limb.bit_count);
28902033
2891 testing.expect((try a.to(u64)) == 0xffffffff33333333);
2892}
2893
2894test "big.int bitwise or multi-limb" {
2895 var a = try Int.initSet(testing.allocator, maxInt(Limb) + 1);
2896 defer a.deinit();
2897 var b = try Int.initSet(testing.allocator, maxInt(Limb));
2898 defer b.deinit();
2034 var carry: Limb = 0;
2035 var i: usize = 0;
2036 while (i < a.len) : (i += 1) {
2037 const src_i = a.len - i - 1;
2038 const dst_i = src_i + limb_shift;
28992039
2900 try a.bitOr(a, b);
2040 const src_digit = a[src_i];
2041 r[dst_i] = carry | @call(.{ .modifier = .always_inline }, math.shr, .{
2042 Limb,
2043 src_digit,
2044 Limb.bit_count - @intCast(Limb, interior_limb_shift),
2045 });
2046 carry = (src_digit << interior_limb_shift);
2047 }
29012048
2902 // TODO: big.int.cpp or is wrong on multi-limb.
2903 testing.expect((try a.to(DoubleLimb)) == (maxInt(Limb) + 1) + maxInt(Limb));
2049 r[limb_shift - 1] = carry;
2050 mem.set(Limb, r[0 .. limb_shift - 1], 0);
29042051}
29052052
2906test "big.int var args" {
2907 var a = try Int.initSet(testing.allocator, 5);
2908 defer a.deinit();
2053fn llshr(r: []Limb, a: []const Limb, shift: usize) void {
2054 @setRuntimeSafety(false);
2055 assert(a.len >= 1);
2056 assert(r.len >= a.len - (shift / Limb.bit_count));
29092057
2910 const b = try Int.initSet(testing.allocator, 6);
2911 defer b.deinit();
2912 try a.add(a, b);
2913 testing.expect((try a.to(u64)) == 11);
2058 const limb_shift = shift / Limb.bit_count;
2059 const interior_limb_shift = @intCast(Log2Limb, shift % Limb.bit_count);
29142060
2915 const c = try Int.initSet(testing.allocator, 11);
2916 defer c.deinit();
2917 testing.expect(a.cmp(c) == .eq);
2061 var carry: Limb = 0;
2062 var i: usize = 0;
2063 while (i < a.len - limb_shift) : (i += 1) {
2064 const src_i = a.len - i - 1;
2065 const dst_i = src_i - limb_shift;
29182066
2919 const d = try Int.initSet(testing.allocator, 14);
2920 defer d.deinit();
2921 testing.expect(a.cmp(d) != .gt);
2067 const src_digit = a[src_i];
2068 r[dst_i] = carry | (src_digit >> interior_limb_shift);
2069 carry = @call(.{ .modifier = .always_inline }, math.shl, .{
2070 Limb,
2071 src_digit,
2072 Limb.bit_count - @intCast(Limb, interior_limb_shift),
2073 });
2074 }
29222075}
29232076
2924test "big.int gcd non-one small" {
2925 var a = try Int.initSet(testing.allocator, 17);
2926 defer a.deinit();
2927 var b = try Int.initSet(testing.allocator, 97);
2928 defer b.deinit();
2929 var r = try Int.init(testing.allocator);
2930 defer r.deinit();
2077fn llor(r: []Limb, a: []const Limb, b: []const Limb) void {
2078 @setRuntimeSafety(false);
2079 assert(r.len >= a.len);
2080 assert(a.len >= b.len);
29312081
2932 try r.gcd(a, b);
2933
2934 testing.expect((try r.to(u32)) == 1);
2082 var i: usize = 0;
2083 while (i < b.len) : (i += 1) {
2084 r[i] = a[i] | b[i];
2085 }
2086 while (i < a.len) : (i += 1) {
2087 r[i] = a[i];
2088 }
29352089}
29362090
2937test "big.int gcd non-one small" {
2938 var a = try Int.initSet(testing.allocator, 4864);
2939 defer a.deinit();
2940 var b = try Int.initSet(testing.allocator, 3458);
2941 defer b.deinit();
2942 var r = try Int.init(testing.allocator);
2943 defer r.deinit();
2944
2945 try r.gcd(a, b);
2091fn lland(r: []Limb, a: []const Limb, b: []const Limb) void {
2092 @setRuntimeSafety(false);
2093 assert(r.len >= b.len);
2094 assert(a.len >= b.len);
29462095
2947 testing.expect((try r.to(u32)) == 38);
2096 var i: usize = 0;
2097 while (i < b.len) : (i += 1) {
2098 r[i] = a[i] & b[i];
2099 }
29482100}
29492101
2950test "big.int gcd non-one large" {
2951 var a = try Int.initSet(testing.allocator, 0xffffffffffffffff);
2952 defer a.deinit();
2953 var b = try Int.initSet(testing.allocator, 0xffffffffffffffff7777);
2954 defer b.deinit();
2955 var r = try Int.init(testing.allocator);
2956 defer r.deinit();
2957
2958 try r.gcd(a, b);
2102fn llxor(r: []Limb, a: []const Limb, b: []const Limb) void {
2103 assert(r.len >= a.len);
2104 assert(a.len >= b.len);
29592105
2960 testing.expect((try r.to(u32)) == 4369);
2106 var i: usize = 0;
2107 while (i < b.len) : (i += 1) {
2108 r[i] = a[i] ^ b[i];
2109 }
2110 while (i < a.len) : (i += 1) {
2111 r[i] = a[i];
2112 }
29612113}
29622114
2963test "big.int gcd large multi-limb result" {
2964 var a = try Int.initSet(testing.allocator, 0x12345678123456781234567812345678123456781234567812345678);
2965 defer a.deinit();
2966 var b = try Int.initSet(testing.allocator, 0x12345671234567123456712345671234567123456712345671234567);
2967 defer b.deinit();
2968 var r = try Int.init(testing.allocator);
2969 defer r.deinit();
2970
2971 try r.gcd(a, b);
2115// Storage must live for the lifetime of the returned value
2116fn fixedIntFromSignedDoubleLimb(A: SignedDoubleLimb, storage: []Limb) Mutable {
2117 assert(storage.len >= 2);
29722118
2973 testing.expect((try r.to(u256)) == 0xf000000ff00000fff0000ffff000fffff00ffffff1);
2119 const A_is_positive = A >= 0;
2120 const Au = @intCast(DoubleLimb, if (A < 0) -A else A);
2121 storage[0] = @truncate(Limb, Au);
2122 storage[1] = @truncate(Limb, Au >> Limb.bit_count);
2123 return .{
2124 .limbs = storage[0..2],
2125 .positive = A_is_positive,
2126 .len = 2,
2127 };
29742128}
29752129
2976test "big.int gcd one large" {
2977 var a = try Int.initSet(testing.allocator, 1897056385327307);
2978 defer a.deinit();
2979 var b = try Int.initSet(testing.allocator, 2251799813685248);
2980 defer b.deinit();
2981 var r = try Int.init(testing.allocator);
2982 defer r.deinit();
2983
2984 try r.gcd(a, b);
2985
2986 testing.expect((try r.to(u64)) == 1);
2130test "" {
2131 _ = @import("int_test.zig");
29872132}
lib/std/math/big/int_test.zig created+1455
......@@ -0,0 +1,1455 @@
1const std = @import("../../std.zig");
2const mem = std.mem;
3const testing = std.testing;
4const Managed = std.math.big.int.Managed;
5const Limb = std.math.big.Limb;
6const DoubleLimb = std.math.big.DoubleLimb;
7const maxInt = std.math.maxInt;
8const minInt = std.math.minInt;
9
10// NOTE: All the following tests assume the max machine-word will be 64-bit.
11//
12// They will still run on larger than this and should pass, but the multi-limb code-paths
13// may be untested in some cases.
14
15test "big.int comptime_int set" {
16 comptime var s = 0xefffffff00000001eeeeeeefaaaaaaab;
17 var a = try Managed.initSet(testing.allocator, s);
18 defer a.deinit();
19
20 const s_limb_count = 128 / Limb.bit_count;
21
22 comptime var i: usize = 0;
23 inline while (i < s_limb_count) : (i += 1) {
24 const result = @as(Limb, s & maxInt(Limb));
25 s >>= Limb.bit_count / 2;
26 s >>= Limb.bit_count / 2;
27 testing.expect(a.limbs[i] == result);
28 }
29}
30
31test "big.int comptime_int set negative" {
32 var a = try Managed.initSet(testing.allocator, -10);
33 defer a.deinit();
34
35 testing.expect(a.limbs[0] == 10);
36 testing.expect(a.isPositive() == false);
37}
38
39test "big.int int set unaligned small" {
40 var a = try Managed.initSet(testing.allocator, @as(u7, 45));
41 defer a.deinit();
42
43 testing.expect(a.limbs[0] == 45);
44 testing.expect(a.isPositive() == true);
45}
46
47test "big.int comptime_int to" {
48 var a = try Managed.initSet(testing.allocator, 0xefffffff00000001eeeeeeefaaaaaaab);
49 defer a.deinit();
50
51 testing.expect((try a.to(u128)) == 0xefffffff00000001eeeeeeefaaaaaaab);
52}
53
54test "big.int sub-limb to" {
55 var a = try Managed.initSet(testing.allocator, 10);
56 defer a.deinit();
57
58 testing.expect((try a.to(u8)) == 10);
59}
60
61test "big.int to target too small error" {
62 var a = try Managed.initSet(testing.allocator, 0xffffffff);
63 defer a.deinit();
64
65 testing.expectError(error.TargetTooSmall, a.to(u8));
66}
67
68test "big.int normalize" {
69 var a = try Managed.init(testing.allocator);
70 defer a.deinit();
71 try a.ensureCapacity(8);
72
73 a.limbs[0] = 1;
74 a.limbs[1] = 2;
75 a.limbs[2] = 3;
76 a.limbs[3] = 0;
77 a.normalize(4);
78 testing.expect(a.len() == 3);
79
80 a.limbs[0] = 1;
81 a.limbs[1] = 2;
82 a.limbs[2] = 3;
83 a.normalize(3);
84 testing.expect(a.len() == 3);
85
86 a.limbs[0] = 0;
87 a.limbs[1] = 0;
88 a.normalize(2);
89 testing.expect(a.len() == 1);
90
91 a.limbs[0] = 0;
92 a.normalize(1);
93 testing.expect(a.len() == 1);
94}
95
96test "big.int normalize multi" {
97 var a = try Managed.init(testing.allocator);
98 defer a.deinit();
99 try a.ensureCapacity(8);
100
101 a.limbs[0] = 1;
102 a.limbs[1] = 2;
103 a.limbs[2] = 0;
104 a.limbs[3] = 0;
105 a.normalize(4);
106 testing.expect(a.len() == 2);
107
108 a.limbs[0] = 1;
109 a.limbs[1] = 2;
110 a.limbs[2] = 3;
111 a.normalize(3);
112 testing.expect(a.len() == 3);
113
114 a.limbs[0] = 0;
115 a.limbs[1] = 0;
116 a.limbs[2] = 0;
117 a.limbs[3] = 0;
118 a.normalize(4);
119 testing.expect(a.len() == 1);
120
121 a.limbs[0] = 0;
122 a.normalize(1);
123 testing.expect(a.len() == 1);
124}
125
126test "big.int parity" {
127 var a = try Managed.init(testing.allocator);
128 defer a.deinit();
129
130 try a.set(0);
131 testing.expect(a.isEven());
132 testing.expect(!a.isOdd());
133
134 try a.set(7);
135 testing.expect(!a.isEven());
136 testing.expect(a.isOdd());
137}
138
139test "big.int bitcount + sizeInBaseUpperBound" {
140 var a = try Managed.init(testing.allocator);
141 defer a.deinit();
142
143 try a.set(0b100);
144 testing.expect(a.bitCountAbs() == 3);
145 testing.expect(a.sizeInBaseUpperBound(2) >= 3);
146 testing.expect(a.sizeInBaseUpperBound(10) >= 1);
147
148 a.negate();
149 testing.expect(a.bitCountAbs() == 3);
150 testing.expect(a.sizeInBaseUpperBound(2) >= 4);
151 testing.expect(a.sizeInBaseUpperBound(10) >= 2);
152
153 try a.set(0xffffffff);
154 testing.expect(a.bitCountAbs() == 32);
155 testing.expect(a.sizeInBaseUpperBound(2) >= 32);
156 testing.expect(a.sizeInBaseUpperBound(10) >= 10);
157
158 try a.shiftLeft(a, 5000);
159 testing.expect(a.bitCountAbs() == 5032);
160 testing.expect(a.sizeInBaseUpperBound(2) >= 5032);
161 a.setSign(false);
162
163 testing.expect(a.bitCountAbs() == 5032);
164 testing.expect(a.sizeInBaseUpperBound(2) >= 5033);
165}
166
167test "big.int bitcount/to" {
168 var a = try Managed.init(testing.allocator);
169 defer a.deinit();
170
171 try a.set(0);
172 testing.expect(a.bitCountTwosComp() == 0);
173
174 testing.expect((try a.to(u0)) == 0);
175 testing.expect((try a.to(i0)) == 0);
176
177 try a.set(-1);
178 testing.expect(a.bitCountTwosComp() == 1);
179 testing.expect((try a.to(i1)) == -1);
180
181 try a.set(-8);
182 testing.expect(a.bitCountTwosComp() == 4);
183 testing.expect((try a.to(i4)) == -8);
184
185 try a.set(127);
186 testing.expect(a.bitCountTwosComp() == 7);
187 testing.expect((try a.to(u7)) == 127);
188
189 try a.set(-128);
190 testing.expect(a.bitCountTwosComp() == 8);
191 testing.expect((try a.to(i8)) == -128);
192
193 try a.set(-129);
194 testing.expect(a.bitCountTwosComp() == 9);
195 testing.expect((try a.to(i9)) == -129);
196}
197
198test "big.int fits" {
199 var a = try Managed.init(testing.allocator);
200 defer a.deinit();
201
202 try a.set(0);
203 testing.expect(a.fits(u0));
204 testing.expect(a.fits(i0));
205
206 try a.set(255);
207 testing.expect(!a.fits(u0));
208 testing.expect(!a.fits(u1));
209 testing.expect(!a.fits(i8));
210 testing.expect(a.fits(u8));
211 testing.expect(a.fits(u9));
212 testing.expect(a.fits(i9));
213
214 try a.set(-128);
215 testing.expect(!a.fits(i7));
216 testing.expect(a.fits(i8));
217 testing.expect(a.fits(i9));
218 testing.expect(!a.fits(u9));
219
220 try a.set(0x1ffffffffeeeeeeee);
221 testing.expect(!a.fits(u32));
222 testing.expect(!a.fits(u64));
223 testing.expect(a.fits(u65));
224}
225
226test "big.int string set" {
227 var a = try Managed.init(testing.allocator);
228 defer a.deinit();
229
230 try a.setString(10, "120317241209124781241290847124");
231 testing.expect((try a.to(u128)) == 120317241209124781241290847124);
232}
233
234test "big.int string negative" {
235 var a = try Managed.init(testing.allocator);
236 defer a.deinit();
237
238 try a.setString(10, "-1023");
239 testing.expect((try a.to(i32)) == -1023);
240}
241
242test "big.int string set number with underscores" {
243 var a = try Managed.init(testing.allocator);
244 defer a.deinit();
245
246 try a.setString(10, "__1_2_0_3_1_7_2_4_1_2_0_____9_1__2__4_7_8_1_2_4_1_2_9_0_8_4_7_1_2_4___");
247 testing.expect((try a.to(u128)) == 120317241209124781241290847124);
248}
249
250test "big.int string set case insensitive number" {
251 var a = try Managed.init(testing.allocator);
252 defer a.deinit();
253
254 try a.setString(16, "aB_cD_eF");
255 testing.expect((try a.to(u32)) == 0xabcdef);
256}
257
258test "big.int string set bad char error" {
259 var a = try Managed.init(testing.allocator);
260 defer a.deinit();
261 testing.expectError(error.InvalidCharacter, a.setString(10, "x"));
262}
263
264test "big.int string set bad base error" {
265 var a = try Managed.init(testing.allocator);
266 defer a.deinit();
267 testing.expectError(error.InvalidBase, a.setString(45, "10"));
268}
269
270test "big.int string to" {
271 var a = try Managed.initSet(testing.allocator, 120317241209124781241290847124);
272 defer a.deinit();
273
274 const as = try a.toString(testing.allocator, 10, false);
275 defer testing.allocator.free(as);
276 const es = "120317241209124781241290847124";
277
278 testing.expect(mem.eql(u8, as, es));
279}
280
281test "big.int string to base base error" {
282 var a = try Managed.initSet(testing.allocator, 0xffffffff);
283 defer a.deinit();
284
285 testing.expectError(error.InvalidBase, a.toString(testing.allocator, 45, false));
286}
287
288test "big.int string to base 2" {
289 var a = try Managed.initSet(testing.allocator, -0b1011);
290 defer a.deinit();
291
292 const as = try a.toString(testing.allocator, 2, false);
293 defer testing.allocator.free(as);
294 const es = "-1011";
295
296 testing.expect(mem.eql(u8, as, es));
297}
298
299test "big.int string to base 16" {
300 var a = try Managed.initSet(testing.allocator, 0xefffffff00000001eeeeeeefaaaaaaab);
301 defer a.deinit();
302
303 const as = try a.toString(testing.allocator, 16, false);
304 defer testing.allocator.free(as);
305 const es = "efffffff00000001eeeeeeefaaaaaaab";
306
307 testing.expect(mem.eql(u8, as, es));
308}
309
310test "big.int neg string to" {
311 var a = try Managed.initSet(testing.allocator, -123907434);
312 defer a.deinit();
313
314 const as = try a.toString(testing.allocator, 10, false);
315 defer testing.allocator.free(as);
316 const es = "-123907434";
317
318 testing.expect(mem.eql(u8, as, es));
319}
320
321test "big.int zero string to" {
322 var a = try Managed.initSet(testing.allocator, 0);
323 defer a.deinit();
324
325 const as = try a.toString(testing.allocator, 10, false);
326 defer testing.allocator.free(as);
327 const es = "0";
328
329 testing.expect(mem.eql(u8, as, es));
330}
331
332test "big.int clone" {
333 var a = try Managed.initSet(testing.allocator, 1234);
334 defer a.deinit();
335 var b = try a.clone();
336 defer b.deinit();
337
338 testing.expect((try a.to(u32)) == 1234);
339 testing.expect((try b.to(u32)) == 1234);
340
341 try a.set(77);
342 testing.expect((try a.to(u32)) == 77);
343 testing.expect((try b.to(u32)) == 1234);
344}
345
346test "big.int swap" {
347 var a = try Managed.initSet(testing.allocator, 1234);
348 defer a.deinit();
349 var b = try Managed.initSet(testing.allocator, 5678);
350 defer b.deinit();
351
352 testing.expect((try a.to(u32)) == 1234);
353 testing.expect((try b.to(u32)) == 5678);
354
355 a.swap(&b);
356
357 testing.expect((try a.to(u32)) == 5678);
358 testing.expect((try b.to(u32)) == 1234);
359}
360
361test "big.int to negative" {
362 var a = try Managed.initSet(testing.allocator, -10);
363 defer a.deinit();
364
365 testing.expect((try a.to(i32)) == -10);
366}
367
368test "big.int compare" {
369 var a = try Managed.initSet(testing.allocator, -11);
370 defer a.deinit();
371 var b = try Managed.initSet(testing.allocator, 10);
372 defer b.deinit();
373
374 testing.expect(a.orderAbs(b) == .gt);
375 testing.expect(a.order(b) == .lt);
376}
377
378test "big.int compare similar" {
379 var a = try Managed.initSet(testing.allocator, 0xffffffffeeeeeeeeffffffffeeeeeeee);
380 defer a.deinit();
381 var b = try Managed.initSet(testing.allocator, 0xffffffffeeeeeeeeffffffffeeeeeeef);
382 defer b.deinit();
383
384 testing.expect(a.orderAbs(b) == .lt);
385 testing.expect(b.orderAbs(a) == .gt);
386}
387
388test "big.int compare different limb size" {
389 var a = try Managed.initSet(testing.allocator, maxInt(Limb) + 1);
390 defer a.deinit();
391 var b = try Managed.initSet(testing.allocator, 1);
392 defer b.deinit();
393
394 testing.expect(a.orderAbs(b) == .gt);
395 testing.expect(b.orderAbs(a) == .lt);
396}
397
398test "big.int compare multi-limb" {
399 var a = try Managed.initSet(testing.allocator, -0x7777777799999999ffffeeeeffffeeeeffffeeeef);
400 defer a.deinit();
401 var b = try Managed.initSet(testing.allocator, 0x7777777799999999ffffeeeeffffeeeeffffeeeee);
402 defer b.deinit();
403
404 testing.expect(a.orderAbs(b) == .gt);
405 testing.expect(a.order(b) == .lt);
406}
407
408test "big.int equality" {
409 var a = try Managed.initSet(testing.allocator, 0xffffffff1);
410 defer a.deinit();
411 var b = try Managed.initSet(testing.allocator, -0xffffffff1);
412 defer b.deinit();
413
414 testing.expect(a.eqAbs(b));
415 testing.expect(!a.eq(b));
416}
417
418test "big.int abs" {
419 var a = try Managed.initSet(testing.allocator, -5);
420 defer a.deinit();
421
422 a.abs();
423 testing.expect((try a.to(u32)) == 5);
424
425 a.abs();
426 testing.expect((try a.to(u32)) == 5);
427}
428
429test "big.int negate" {
430 var a = try Managed.initSet(testing.allocator, 5);
431 defer a.deinit();
432
433 a.negate();
434 testing.expect((try a.to(i32)) == -5);
435
436 a.negate();
437 testing.expect((try a.to(i32)) == 5);
438}
439
440test "big.int add single-single" {
441 var a = try Managed.initSet(testing.allocator, 50);
442 defer a.deinit();
443 var b = try Managed.initSet(testing.allocator, 5);
444 defer b.deinit();
445
446 var c = try Managed.init(testing.allocator);
447 defer c.deinit();
448 try c.add(a.toConst(), b.toConst());
449
450 testing.expect((try c.to(u32)) == 55);
451}
452
453test "big.int add multi-single" {
454 var a = try Managed.initSet(testing.allocator, maxInt(Limb) + 1);
455 defer a.deinit();
456 var b = try Managed.initSet(testing.allocator, 1);
457 defer b.deinit();
458
459 var c = try Managed.init(testing.allocator);
460 defer c.deinit();
461
462 try c.add(a.toConst(), b.toConst());
463 testing.expect((try c.to(DoubleLimb)) == maxInt(Limb) + 2);
464
465 try c.add(b.toConst(), a.toConst());
466 testing.expect((try c.to(DoubleLimb)) == maxInt(Limb) + 2);
467}
468
469test "big.int add multi-multi" {
470 const op1 = 0xefefefef7f7f7f7f;
471 const op2 = 0xfefefefe9f9f9f9f;
472 var a = try Managed.initSet(testing.allocator, op1);
473 defer a.deinit();
474 var b = try Managed.initSet(testing.allocator, op2);
475 defer b.deinit();
476
477 var c = try Managed.init(testing.allocator);
478 defer c.deinit();
479 try c.add(a.toConst(), b.toConst());
480
481 testing.expect((try c.to(u128)) == op1 + op2);
482}
483
484test "big.int add zero-zero" {
485 var a = try Managed.initSet(testing.allocator, 0);
486 defer a.deinit();
487 var b = try Managed.initSet(testing.allocator, 0);
488 defer b.deinit();
489
490 var c = try Managed.init(testing.allocator);
491 defer c.deinit();
492 try c.add(a.toConst(), b.toConst());
493
494 testing.expect((try c.to(u32)) == 0);
495}
496
497test "big.int add alias multi-limb nonzero-zero" {
498 const op1 = 0xffffffff777777771;
499 var a = try Managed.initSet(testing.allocator, op1);
500 defer a.deinit();
501 var b = try Managed.initSet(testing.allocator, 0);
502 defer b.deinit();
503
504 try a.add(a.toConst(), b.toConst());
505
506 testing.expect((try a.to(u128)) == op1);
507}
508
509test "big.int add sign" {
510 var a = try Managed.init(testing.allocator);
511 defer a.deinit();
512
513 var one = try Managed.initSet(testing.allocator, 1);
514 defer one.deinit();
515 var two = try Managed.initSet(testing.allocator, 2);
516 defer two.deinit();
517 var neg_one = try Managed.initSet(testing.allocator, -1);
518 defer neg_one.deinit();
519 var neg_two = try Managed.initSet(testing.allocator, -2);
520 defer neg_two.deinit();
521
522 try a.add(one.toConst(), two.toConst());
523 testing.expect((try a.to(i32)) == 3);
524
525 try a.add(neg_one.toConst(), two.toConst());
526 testing.expect((try a.to(i32)) == 1);
527
528 try a.add(one.toConst(), neg_two.toConst());
529 testing.expect((try a.to(i32)) == -1);
530
531 try a.add(neg_one.toConst(), neg_two.toConst());
532 testing.expect((try a.to(i32)) == -3);
533}
534
535test "big.int sub single-single" {
536 var a = try Managed.initSet(testing.allocator, 50);
537 defer a.deinit();
538 var b = try Managed.initSet(testing.allocator, 5);
539 defer b.deinit();
540
541 var c = try Managed.init(testing.allocator);
542 defer c.deinit();
543 try c.sub(a.toConst(), b.toConst());
544
545 testing.expect((try c.to(u32)) == 45);
546}
547
548test "big.int sub multi-single" {
549 var a = try Managed.initSet(testing.allocator, maxInt(Limb) + 1);
550 defer a.deinit();
551 var b = try Managed.initSet(testing.allocator, 1);
552 defer b.deinit();
553
554 var c = try Managed.init(testing.allocator);
555 defer c.deinit();
556 try c.sub(a.toConst(), b.toConst());
557
558 testing.expect((try c.to(Limb)) == maxInt(Limb));
559}
560
561test "big.int sub multi-multi" {
562 const op1 = 0xefefefefefefefefefefefef;
563 const op2 = 0xabababababababababababab;
564
565 var a = try Managed.initSet(testing.allocator, op1);
566 defer a.deinit();
567 var b = try Managed.initSet(testing.allocator, op2);
568 defer b.deinit();
569
570 var c = try Managed.init(testing.allocator);
571 defer c.deinit();
572 try c.sub(a.toConst(), b.toConst());
573
574 testing.expect((try c.to(u128)) == op1 - op2);
575}
576
577test "big.int sub equal" {
578 var a = try Managed.initSet(testing.allocator, 0x11efefefefefefefefefefefef);
579 defer a.deinit();
580 var b = try Managed.initSet(testing.allocator, 0x11efefefefefefefefefefefef);
581 defer b.deinit();
582
583 var c = try Managed.init(testing.allocator);
584 defer c.deinit();
585 try c.sub(a.toConst(), b.toConst());
586
587 testing.expect((try c.to(u32)) == 0);
588}
589
590test "big.int sub sign" {
591 var a = try Managed.init(testing.allocator);
592 defer a.deinit();
593
594 var one = try Managed.initSet(testing.allocator, 1);
595 defer one.deinit();
596 var two = try Managed.initSet(testing.allocator, 2);
597 defer two.deinit();
598 var neg_one = try Managed.initSet(testing.allocator, -1);
599 defer neg_one.deinit();
600 var neg_two = try Managed.initSet(testing.allocator, -2);
601 defer neg_two.deinit();
602
603 try a.sub(one.toConst(), two.toConst());
604 testing.expect((try a.to(i32)) == -1);
605
606 try a.sub(neg_one.toConst(), two.toConst());
607 testing.expect((try a.to(i32)) == -3);
608
609 try a.sub(one.toConst(), neg_two.toConst());
610 testing.expect((try a.to(i32)) == 3);
611
612 try a.sub(neg_one.toConst(), neg_two.toConst());
613 testing.expect((try a.to(i32)) == 1);
614
615 try a.sub(neg_two.toConst(), neg_one.toConst());
616 testing.expect((try a.to(i32)) == -1);
617}
618
619test "big.int mul single-single" {
620 var a = try Managed.initSet(testing.allocator, 50);
621 defer a.deinit();
622 var b = try Managed.initSet(testing.allocator, 5);
623 defer b.deinit();
624
625 var c = try Managed.init(testing.allocator);
626 defer c.deinit();
627 try c.mul(a.toConst(), b.toConst());
628
629 testing.expect((try c.to(u64)) == 250);
630}
631
632test "big.int mul multi-single" {
633 var a = try Managed.initSet(testing.allocator, maxInt(Limb));
634 defer a.deinit();
635 var b = try Managed.initSet(testing.allocator, 2);
636 defer b.deinit();
637
638 var c = try Managed.init(testing.allocator);
639 defer c.deinit();
640 try c.mul(a.toConst(), b.toConst());
641
642 testing.expect((try c.to(DoubleLimb)) == 2 * maxInt(Limb));
643}
644
645test "big.int mul multi-multi" {
646 const op1 = 0x998888efefefefefefefef;
647 const op2 = 0x333000abababababababab;
648 var a = try Managed.initSet(testing.allocator, op1);
649 defer a.deinit();
650 var b = try Managed.initSet(testing.allocator, op2);
651 defer b.deinit();
652
653 var c = try Managed.init(testing.allocator);
654 defer c.deinit();
655 try c.mul(a.toConst(), b.toConst());
656
657 testing.expect((try c.to(u256)) == op1 * op2);
658}
659
660test "big.int mul alias r with a" {
661 var a = try Managed.initSet(testing.allocator, maxInt(Limb));
662 defer a.deinit();
663 var b = try Managed.initSet(testing.allocator, 2);
664 defer b.deinit();
665
666 try a.mul(a.toConst(), b.toConst());
667
668 testing.expect((try a.to(DoubleLimb)) == 2 * maxInt(Limb));
669}
670
671test "big.int mul alias r with b" {
672 var a = try Managed.initSet(testing.allocator, maxInt(Limb));
673 defer a.deinit();
674 var b = try Managed.initSet(testing.allocator, 2);
675 defer b.deinit();
676
677 try a.mul(b.toConst(), a.toConst());
678
679 testing.expect((try a.to(DoubleLimb)) == 2 * maxInt(Limb));
680}
681
682test "big.int mul alias r with a and b" {
683 var a = try Managed.initSet(testing.allocator, maxInt(Limb));
684 defer a.deinit();
685
686 try a.mul(a.toConst(), a.toConst());
687
688 testing.expect((try a.to(DoubleLimb)) == maxInt(Limb) * maxInt(Limb));
689}
690
691test "big.int mul a*0" {
692 var a = try Managed.initSet(testing.allocator, 0xefefefefefefefef);
693 defer a.deinit();
694 var b = try Managed.initSet(testing.allocator, 0);
695 defer b.deinit();
696
697 var c = try Managed.init(testing.allocator);
698 defer c.deinit();
699 try c.mul(a.toConst(), b.toConst());
700
701 testing.expect((try c.to(u32)) == 0);
702}
703
704test "big.int mul 0*0" {
705 var a = try Managed.initSet(testing.allocator, 0);
706 defer a.deinit();
707 var b = try Managed.initSet(testing.allocator, 0);
708 defer b.deinit();
709
710 var c = try Managed.init(testing.allocator);
711 defer c.deinit();
712 try c.mul(a.toConst(), b.toConst());
713
714 testing.expect((try c.to(u32)) == 0);
715}
716
717test "big.int div single-single no rem" {
718 var a = try Managed.initSet(testing.allocator, 50);
719 defer a.deinit();
720 var b = try Managed.initSet(testing.allocator, 5);
721 defer b.deinit();
722
723 var q = try Managed.init(testing.allocator);
724 defer q.deinit();
725 var r = try Managed.init(testing.allocator);
726 defer r.deinit();
727 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
728
729 testing.expect((try q.to(u32)) == 10);
730 testing.expect((try r.to(u32)) == 0);
731}
732
733test "big.int div single-single with rem" {
734 var a = try Managed.initSet(testing.allocator, 49);
735 defer a.deinit();
736 var b = try Managed.initSet(testing.allocator, 5);
737 defer b.deinit();
738
739 var q = try Managed.init(testing.allocator);
740 defer q.deinit();
741 var r = try Managed.init(testing.allocator);
742 defer r.deinit();
743 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
744
745 testing.expect((try q.to(u32)) == 9);
746 testing.expect((try r.to(u32)) == 4);
747}
748
749test "big.int div multi-single no rem" {
750 const op1 = 0xffffeeeeddddcccc;
751 const op2 = 34;
752
753 var a = try Managed.initSet(testing.allocator, op1);
754 defer a.deinit();
755 var b = try Managed.initSet(testing.allocator, op2);
756 defer b.deinit();
757
758 var q = try Managed.init(testing.allocator);
759 defer q.deinit();
760 var r = try Managed.init(testing.allocator);
761 defer r.deinit();
762 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
763
764 testing.expect((try q.to(u64)) == op1 / op2);
765 testing.expect((try r.to(u64)) == 0);
766}
767
768test "big.int div multi-single with rem" {
769 const op1 = 0xffffeeeeddddcccf;
770 const op2 = 34;
771
772 var a = try Managed.initSet(testing.allocator, op1);
773 defer a.deinit();
774 var b = try Managed.initSet(testing.allocator, op2);
775 defer b.deinit();
776
777 var q = try Managed.init(testing.allocator);
778 defer q.deinit();
779 var r = try Managed.init(testing.allocator);
780 defer r.deinit();
781 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
782
783 testing.expect((try q.to(u64)) == op1 / op2);
784 testing.expect((try r.to(u64)) == 3);
785}
786
787test "big.int div multi>2-single" {
788 const op1 = 0xfefefefefefefefefefefefefefefefe;
789 const op2 = 0xefab8;
790
791 var a = try Managed.initSet(testing.allocator, op1);
792 defer a.deinit();
793 var b = try Managed.initSet(testing.allocator, op2);
794 defer b.deinit();
795
796 var q = try Managed.init(testing.allocator);
797 defer q.deinit();
798 var r = try Managed.init(testing.allocator);
799 defer r.deinit();
800 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
801
802 testing.expect((try q.to(u128)) == op1 / op2);
803 testing.expect((try r.to(u32)) == 0x3e4e);
804}
805
806test "big.int div single-single q < r" {
807 var a = try Managed.initSet(testing.allocator, 0x0078f432);
808 defer a.deinit();
809 var b = try Managed.initSet(testing.allocator, 0x01000000);
810 defer b.deinit();
811
812 var q = try Managed.init(testing.allocator);
813 defer q.deinit();
814 var r = try Managed.init(testing.allocator);
815 defer r.deinit();
816 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
817
818 testing.expect((try q.to(u64)) == 0);
819 testing.expect((try r.to(u64)) == 0x0078f432);
820}
821
822test "big.int div single-single q == r" {
823 var a = try Managed.initSet(testing.allocator, 10);
824 defer a.deinit();
825 var b = try Managed.initSet(testing.allocator, 10);
826 defer b.deinit();
827
828 var q = try Managed.init(testing.allocator);
829 defer q.deinit();
830 var r = try Managed.init(testing.allocator);
831 defer r.deinit();
832 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
833
834 testing.expect((try q.to(u64)) == 1);
835 testing.expect((try r.to(u64)) == 0);
836}
837
838test "big.int div q=0 alias" {
839 var a = try Managed.initSet(testing.allocator, 3);
840 defer a.deinit();
841 var b = try Managed.initSet(testing.allocator, 10);
842 defer b.deinit();
843
844 try Managed.divTrunc(&a, &b, a.toConst(), b.toConst());
845
846 testing.expect((try a.to(u64)) == 0);
847 testing.expect((try b.to(u64)) == 3);
848}
849
850test "big.int div multi-multi q < r" {
851 const op1 = 0x1ffffffff0078f432;
852 const op2 = 0x1ffffffff01000000;
853 var a = try Managed.initSet(testing.allocator, op1);
854 defer a.deinit();
855 var b = try Managed.initSet(testing.allocator, op2);
856 defer b.deinit();
857
858 var q = try Managed.init(testing.allocator);
859 defer q.deinit();
860 var r = try Managed.init(testing.allocator);
861 defer r.deinit();
862 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
863
864 testing.expect((try q.to(u128)) == 0);
865 testing.expect((try r.to(u128)) == op1);
866}
867
868test "big.int div trunc single-single +/+" {
869 const u: i32 = 5;
870 const v: i32 = 3;
871
872 var a = try Managed.initSet(testing.allocator, u);
873 defer a.deinit();
874 var b = try Managed.initSet(testing.allocator, v);
875 defer b.deinit();
876
877 var q = try Managed.init(testing.allocator);
878 defer q.deinit();
879 var r = try Managed.init(testing.allocator);
880 defer r.deinit();
881 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
882
883 // n = q * d + r
884 // 5 = 1 * 3 + 2
885 const eq = @divTrunc(u, v);
886 const er = @mod(u, v);
887
888 testing.expect((try q.to(i32)) == eq);
889 testing.expect((try r.to(i32)) == er);
890}
891
892test "big.int div trunc single-single -/+" {
893 const u: i32 = -5;
894 const v: i32 = 3;
895
896 var a = try Managed.initSet(testing.allocator, u);
897 defer a.deinit();
898 var b = try Managed.initSet(testing.allocator, v);
899 defer b.deinit();
900
901 var q = try Managed.init(testing.allocator);
902 defer q.deinit();
903 var r = try Managed.init(testing.allocator);
904 defer r.deinit();
905 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
906
907 // n = q * d + r
908 // -5 = 1 * -3 - 2
909 const eq = -1;
910 const er = -2;
911
912 testing.expect((try q.to(i32)) == eq);
913 testing.expect((try r.to(i32)) == er);
914}
915
916test "big.int div trunc single-single +/-" {
917 const u: i32 = 5;
918 const v: i32 = -3;
919
920 var a = try Managed.initSet(testing.allocator, u);
921 defer a.deinit();
922 var b = try Managed.initSet(testing.allocator, v);
923 defer b.deinit();
924
925 var q = try Managed.init(testing.allocator);
926 defer q.deinit();
927 var r = try Managed.init(testing.allocator);
928 defer r.deinit();
929 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
930
931 // n = q * d + r
932 // 5 = -1 * -3 + 2
933 const eq = -1;
934 const er = 2;
935
936 testing.expect((try q.to(i32)) == eq);
937 testing.expect((try r.to(i32)) == er);
938}
939
940test "big.int div trunc single-single -/-" {
941 const u: i32 = -5;
942 const v: i32 = -3;
943
944 var a = try Managed.initSet(testing.allocator, u);
945 defer a.deinit();
946 var b = try Managed.initSet(testing.allocator, v);
947 defer b.deinit();
948
949 var q = try Managed.init(testing.allocator);
950 defer q.deinit();
951 var r = try Managed.init(testing.allocator);
952 defer r.deinit();
953 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
954
955 // n = q * d + r
956 // -5 = 1 * -3 - 2
957 const eq = 1;
958 const er = -2;
959
960 testing.expect((try q.to(i32)) == eq);
961 testing.expect((try r.to(i32)) == er);
962}
963
964test "big.int div floor single-single +/+" {
965 const u: i32 = 5;
966 const v: i32 = 3;
967
968 var a = try Managed.initSet(testing.allocator, u);
969 defer a.deinit();
970 var b = try Managed.initSet(testing.allocator, v);
971 defer b.deinit();
972
973 var q = try Managed.init(testing.allocator);
974 defer q.deinit();
975 var r = try Managed.init(testing.allocator);
976 defer r.deinit();
977 try Managed.divFloor(&q, &r, a.toConst(), b.toConst());
978
979 // n = q * d + r
980 // 5 = 1 * 3 + 2
981 const eq = 1;
982 const er = 2;
983
984 testing.expect((try q.to(i32)) == eq);
985 testing.expect((try r.to(i32)) == er);
986}
987
988test "big.int div floor single-single -/+" {
989 const u: i32 = -5;
990 const v: i32 = 3;
991
992 var a = try Managed.initSet(testing.allocator, u);
993 defer a.deinit();
994 var b = try Managed.initSet(testing.allocator, v);
995 defer b.deinit();
996
997 var q = try Managed.init(testing.allocator);
998 defer q.deinit();
999 var r = try Managed.init(testing.allocator);
1000 defer r.deinit();
1001 try Managed.divFloor(&q, &r, a.toConst(), b.toConst());
1002
1003 // n = q * d + r
1004 // -5 = -2 * 3 + 1
1005 const eq = -2;
1006 const er = 1;
1007
1008 testing.expect((try q.to(i32)) == eq);
1009 testing.expect((try r.to(i32)) == er);
1010}
1011
1012test "big.int div floor single-single +/-" {
1013 const u: i32 = 5;
1014 const v: i32 = -3;
1015
1016 var a = try Managed.initSet(testing.allocator, u);
1017 defer a.deinit();
1018 var b = try Managed.initSet(testing.allocator, v);
1019 defer b.deinit();
1020
1021 var q = try Managed.init(testing.allocator);
1022 defer q.deinit();
1023 var r = try Managed.init(testing.allocator);
1024 defer r.deinit();
1025 try Managed.divFloor(&q, &r, a.toConst(), b.toConst());
1026
1027 // n = q * d + r
1028 // 5 = -2 * -3 - 1
1029 const eq = -2;
1030 const er = -1;
1031
1032 testing.expect((try q.to(i32)) == eq);
1033 testing.expect((try r.to(i32)) == er);
1034}
1035
1036test "big.int div floor single-single -/-" {
1037 const u: i32 = -5;
1038 const v: i32 = -3;
1039
1040 var a = try Managed.initSet(testing.allocator, u);
1041 defer a.deinit();
1042 var b = try Managed.initSet(testing.allocator, v);
1043 defer b.deinit();
1044
1045 var q = try Managed.init(testing.allocator);
1046 defer q.deinit();
1047 var r = try Managed.init(testing.allocator);
1048 defer r.deinit();
1049 try Managed.divFloor(&q, &r, a.toConst(), b.toConst());
1050
1051 // n = q * d + r
1052 // -5 = 2 * -3 + 1
1053 const eq = 1;
1054 const er = -2;
1055
1056 testing.expect((try q.to(i32)) == eq);
1057 testing.expect((try r.to(i32)) == er);
1058}
1059
1060test "big.int div multi-multi with rem" {
1061 var a = try Managed.initSet(testing.allocator, 0x8888999911110000ffffeeeeddddccccbbbbaaaa9999);
1062 defer a.deinit();
1063 var b = try Managed.initSet(testing.allocator, 0x99990000111122223333);
1064 defer b.deinit();
1065
1066 var q = try Managed.init(testing.allocator);
1067 defer q.deinit();
1068 var r = try Managed.init(testing.allocator);
1069 defer r.deinit();
1070 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
1071
1072 testing.expect((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b);
1073 testing.expect((try r.to(u128)) == 0x28de0acacd806823638);
1074}
1075
1076test "big.int div multi-multi no rem" {
1077 var a = try Managed.initSet(testing.allocator, 0x8888999911110000ffffeeeedb4fec200ee3a4286361);
1078 defer a.deinit();
1079 var b = try Managed.initSet(testing.allocator, 0x99990000111122223333);
1080 defer b.deinit();
1081
1082 var q = try Managed.init(testing.allocator);
1083 defer q.deinit();
1084 var r = try Managed.init(testing.allocator);
1085 defer r.deinit();
1086 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
1087
1088 testing.expect((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b);
1089 testing.expect((try r.to(u128)) == 0);
1090}
1091
1092test "big.int div multi-multi (2 branch)" {
1093 var a = try Managed.initSet(testing.allocator, 0x866666665555555588888887777777761111111111111111);
1094 defer a.deinit();
1095 var b = try Managed.initSet(testing.allocator, 0x86666666555555554444444433333333);
1096 defer b.deinit();
1097
1098 var q = try Managed.init(testing.allocator);
1099 defer q.deinit();
1100 var r = try Managed.init(testing.allocator);
1101 defer r.deinit();
1102 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
1103
1104 testing.expect((try q.to(u128)) == 0x10000000000000000);
1105 testing.expect((try r.to(u128)) == 0x44444443444444431111111111111111);
1106}
1107
1108test "big.int div multi-multi (3.1/3.3 branch)" {
1109 var a = try Managed.initSet(testing.allocator, 0x11111111111111111111111111111111111111111111111111111111111111);
1110 defer a.deinit();
1111 var b = try Managed.initSet(testing.allocator, 0x1111111111111111111111111111111111111111171);
1112 defer b.deinit();
1113
1114 var q = try Managed.init(testing.allocator);
1115 defer q.deinit();
1116 var r = try Managed.init(testing.allocator);
1117 defer r.deinit();
1118 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
1119
1120 testing.expect((try q.to(u128)) == 0xfffffffffffffffffff);
1121 testing.expect((try r.to(u256)) == 0x1111111111111111111110b12222222222222222282);
1122}
1123
1124test "big.int div multi-single zero-limb trailing" {
1125 var a = try Managed.initSet(testing.allocator, 0x60000000000000000000000000000000000000000000000000000000000000000);
1126 defer a.deinit();
1127 var b = try Managed.initSet(testing.allocator, 0x10000000000000000);
1128 defer b.deinit();
1129
1130 var q = try Managed.init(testing.allocator);
1131 defer q.deinit();
1132 var r = try Managed.init(testing.allocator);
1133 defer r.deinit();
1134 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
1135
1136 var expected = try Managed.initSet(testing.allocator, 0x6000000000000000000000000000000000000000000000000);
1137 defer expected.deinit();
1138 testing.expect(q.eq(expected));
1139 testing.expect(r.eqZero());
1140}
1141
1142test "big.int div multi-multi zero-limb trailing (with rem)" {
1143 var a = try Managed.initSet(testing.allocator, 0x86666666555555558888888777777776111111111111111100000000000000000000000000000000);
1144 defer a.deinit();
1145 var b = try Managed.initSet(testing.allocator, 0x8666666655555555444444443333333300000000000000000000000000000000);
1146 defer b.deinit();
1147
1148 var q = try Managed.init(testing.allocator);
1149 defer q.deinit();
1150 var r = try Managed.init(testing.allocator);
1151 defer r.deinit();
1152 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
1153
1154 testing.expect((try q.to(u128)) == 0x10000000000000000);
1155
1156 const rs = try r.toString(testing.allocator, 16, false);
1157 defer testing.allocator.free(rs);
1158 testing.expect(std.mem.eql(u8, rs, "4444444344444443111111111111111100000000000000000000000000000000"));
1159}
1160
1161test "big.int div multi-multi zero-limb trailing (with rem) and dividend zero-limb count > divisor zero-limb count" {
1162 var a = try Managed.initSet(testing.allocator, 0x8666666655555555888888877777777611111111111111110000000000000000);
1163 defer a.deinit();
1164 var b = try Managed.initSet(testing.allocator, 0x8666666655555555444444443333333300000000000000000000000000000000);
1165 defer b.deinit();
1166
1167 var q = try Managed.init(testing.allocator);
1168 defer q.deinit();
1169 var r = try Managed.init(testing.allocator);
1170 defer r.deinit();
1171 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
1172
1173 testing.expect((try q.to(u128)) == 0x1);
1174
1175 const rs = try r.toString(testing.allocator, 16, false);
1176 defer testing.allocator.free(rs);
1177 testing.expect(std.mem.eql(u8, rs, "444444434444444311111111111111110000000000000000"));
1178}
1179
1180test "big.int div multi-multi zero-limb trailing (with rem) and dividend zero-limb count < divisor zero-limb count" {
1181 var a = try Managed.initSet(testing.allocator, 0x86666666555555558888888777777776111111111111111100000000000000000000000000000000);
1182 defer a.deinit();
1183 var b = try Managed.initSet(testing.allocator, 0x866666665555555544444444333333330000000000000000);
1184 defer b.deinit();
1185
1186 var q = try Managed.init(testing.allocator);
1187 defer q.deinit();
1188 var r = try Managed.init(testing.allocator);
1189 defer r.deinit();
1190 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
1191
1192 const qs = try q.toString(testing.allocator, 16, false);
1193 defer testing.allocator.free(qs);
1194 testing.expect(std.mem.eql(u8, qs, "10000000000000000820820803105186f"));
1195
1196 const rs = try r.toString(testing.allocator, 16, false);
1197 defer testing.allocator.free(rs);
1198 testing.expect(std.mem.eql(u8, rs, "4e11f2baa5896a321d463b543d0104e30000000000000000"));
1199}
1200
1201test "big.int div multi-multi fuzz case #1" {
1202 var a = try Managed.init(testing.allocator);
1203 defer a.deinit();
1204 var b = try Managed.init(testing.allocator);
1205 defer b.deinit();
1206
1207 try a.setString(16, "ffffffffffffffffffffffffffffc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
1208 try b.setString(16, "3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffc000000000000000000000000000000007fffffffffff");
1209
1210 var q = try Managed.init(testing.allocator);
1211 defer q.deinit();
1212 var r = try Managed.init(testing.allocator);
1213 defer r.deinit();
1214 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
1215
1216 const qs = try q.toString(testing.allocator, 16, false);
1217 defer testing.allocator.free(qs);
1218 testing.expect(std.mem.eql(u8, qs, "3ffffffffffffffffffffffffffff0000000000000000000000000000000000001ffffffffffffffffffffffffffff7fffffffe000000000000000000000000000180000000000000000000003fffffbfffffffdfffffffffffffeffff800000100101000000100000000020003fffffdfbfffffe3ffffffffffffeffff7fffc00800a100000017ffe000002000400007efbfff7fe9f00000037ffff3fff7fffa004006100000009ffe00000190038200bf7d2ff7fefe80400060000f7d7f8fbf9401fe38e0403ffc0bdffffa51102c300d7be5ef9df4e5060007b0127ad3fa69f97d0f820b6605ff617ddf7f32ad7a05c0d03f2e7bc78a6000e087a8bbcdc59e07a5a079128a7861f553ddebed7e8e56701756f9ead39b48cd1b0831889ea6ec1fddf643d0565b075ff07e6caea4e2854ec9227fd635ed60a2f5eef2893052ffd54718fa08604acbf6a15e78a467c4a3c53c0278af06c4416573f925491b195e8fd79302cb1aaf7caf4ecfc9aec1254cc969786363ac729f914c6ddcc26738d6b0facd54eba026580aba2eb6482a088b0d224a8852420b91ec1"));
1219
1220 const rs = try r.toString(testing.allocator, 16, false);
1221 defer testing.allocator.free(rs);
1222 testing.expect(std.mem.eql(u8, rs, "310d1d4c414426b4836c2635bad1df3a424e50cbdd167ffccb4dfff57d36b4aae0d6ca0910698220171a0f3373c1060a046c2812f0027e321f72979daa5e7973214170d49e885de0c0ecc167837d44502430674a82522e5df6a0759548052420b91ec1"));
1223}
1224
1225test "big.int div multi-multi fuzz case #2" {
1226 var a = try Managed.init(testing.allocator);
1227 defer a.deinit();
1228 var b = try Managed.init(testing.allocator);
1229 defer b.deinit();
1230
1231 try a.setString(16, "3ffffffffe00000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000000000000000000000000000000000000000000000000000000000000001fffffffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffc000000000000000000000000000000000000000000000000000000000000000");
1232 try b.setString(16, "ffc0000000000000000000000000000000000000000000000000");
1233
1234 var q = try Managed.init(testing.allocator);
1235 defer q.deinit();
1236 var r = try Managed.init(testing.allocator);
1237 defer r.deinit();
1238 try Managed.divTrunc(&q, &r, a.toConst(), b.toConst());
1239
1240 const qs = try q.toString(testing.allocator, 16, false);
1241 defer testing.allocator.free(qs);
1242 testing.expect(std.mem.eql(u8, qs, "40100400fe3f8fe3f8fe3f8fe3f8fe3f8fe4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f91e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4992649926499264991e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4792e4b92e4b92e4b92e4b92a4a92a4a92a4"));
1243
1244 const rs = try r.toString(testing.allocator, 16, false);
1245 defer testing.allocator.free(rs);
1246 testing.expect(std.mem.eql(u8, rs, "a900000000000000000000000000000000000000000000000000"));
1247}
1248
1249test "big.int shift-right single" {
1250 var a = try Managed.initSet(testing.allocator, 0xffff0000);
1251 defer a.deinit();
1252 try a.shiftRight(a, 16);
1253
1254 testing.expect((try a.to(u32)) == 0xffff);
1255}
1256
1257test "big.int shift-right multi" {
1258 var a = try Managed.initSet(testing.allocator, 0xffff0000eeee1111dddd2222cccc3333);
1259 defer a.deinit();
1260 try a.shiftRight(a, 67);
1261
1262 testing.expect((try a.to(u64)) == 0x1fffe0001dddc222);
1263}
1264
1265test "big.int shift-left single" {
1266 var a = try Managed.initSet(testing.allocator, 0xffff);
1267 defer a.deinit();
1268 try a.shiftLeft(a, 16);
1269
1270 testing.expect((try a.to(u64)) == 0xffff0000);
1271}
1272
1273test "big.int shift-left multi" {
1274 var a = try Managed.initSet(testing.allocator, 0x1fffe0001dddc222);
1275 defer a.deinit();
1276 try a.shiftLeft(a, 67);
1277
1278 testing.expect((try a.to(u128)) == 0xffff0000eeee11100000000000000000);
1279}
1280
1281test "big.int shift-right negative" {
1282 var a = try Managed.init(testing.allocator);
1283 defer a.deinit();
1284
1285 var arg = try Managed.initSet(testing.allocator, -20);
1286 defer arg.deinit();
1287 try a.shiftRight(arg, 2);
1288 testing.expect((try a.to(i32)) == -20 >> 2);
1289
1290 var arg2 = try Managed.initSet(testing.allocator, -5);
1291 defer arg2.deinit();
1292 try a.shiftRight(arg2, 10);
1293 testing.expect((try a.to(i32)) == -5 >> 10);
1294}
1295
1296test "big.int shift-left negative" {
1297 var a = try Managed.init(testing.allocator);
1298 defer a.deinit();
1299
1300 var arg = try Managed.initSet(testing.allocator, -10);
1301 defer arg.deinit();
1302 try a.shiftRight(arg, 1232);
1303 testing.expect((try a.to(i32)) == -10 >> 1232);
1304}
1305
1306test "big.int bitwise and simple" {
1307 var a = try Managed.initSet(testing.allocator, 0xffffffff11111111);
1308 defer a.deinit();
1309 var b = try Managed.initSet(testing.allocator, 0xeeeeeeee22222222);
1310 defer b.deinit();
1311
1312 try a.bitAnd(a, b);
1313
1314 testing.expect((try a.to(u64)) == 0xeeeeeeee00000000);
1315}
1316
1317test "big.int bitwise and multi-limb" {
1318 var a = try Managed.initSet(testing.allocator, maxInt(Limb) + 1);
1319 defer a.deinit();
1320 var b = try Managed.initSet(testing.allocator, maxInt(Limb));
1321 defer b.deinit();
1322
1323 try a.bitAnd(a, b);
1324
1325 testing.expect((try a.to(u128)) == 0);
1326}
1327
1328test "big.int bitwise xor simple" {
1329 var a = try Managed.initSet(testing.allocator, 0xffffffff11111111);
1330 defer a.deinit();
1331 var b = try Managed.initSet(testing.allocator, 0xeeeeeeee22222222);
1332 defer b.deinit();
1333
1334 try a.bitXor(a, b);
1335
1336 testing.expect((try a.to(u64)) == 0x1111111133333333);
1337}
1338
1339test "big.int bitwise xor multi-limb" {
1340 var a = try Managed.initSet(testing.allocator, maxInt(Limb) + 1);
1341 defer a.deinit();
1342 var b = try Managed.initSet(testing.allocator, maxInt(Limb));
1343 defer b.deinit();
1344
1345 try a.bitXor(a, b);
1346
1347 testing.expect((try a.to(DoubleLimb)) == (maxInt(Limb) + 1) ^ maxInt(Limb));
1348}
1349
1350test "big.int bitwise or simple" {
1351 var a = try Managed.initSet(testing.allocator, 0xffffffff11111111);
1352 defer a.deinit();
1353 var b = try Managed.initSet(testing.allocator, 0xeeeeeeee22222222);
1354 defer b.deinit();
1355
1356 try a.bitOr(a, b);
1357
1358 testing.expect((try a.to(u64)) == 0xffffffff33333333);
1359}
1360
1361test "big.int bitwise or multi-limb" {
1362 var a = try Managed.initSet(testing.allocator, maxInt(Limb) + 1);
1363 defer a.deinit();
1364 var b = try Managed.initSet(testing.allocator, maxInt(Limb));
1365 defer b.deinit();
1366
1367 try a.bitOr(a, b);
1368
1369 // TODO: big.int.cpp or is wrong on multi-limb.
1370 testing.expect((try a.to(DoubleLimb)) == (maxInt(Limb) + 1) + maxInt(Limb));
1371}
1372
1373test "big.int var args" {
1374 var a = try Managed.initSet(testing.allocator, 5);
1375 defer a.deinit();
1376
1377 var b = try Managed.initSet(testing.allocator, 6);
1378 defer b.deinit();
1379 try a.add(a.toConst(), b.toConst());
1380 testing.expect((try a.to(u64)) == 11);
1381
1382 var c = try Managed.initSet(testing.allocator, 11);
1383 defer c.deinit();
1384 testing.expect(a.order(c) == .eq);
1385
1386 var d = try Managed.initSet(testing.allocator, 14);
1387 defer d.deinit();
1388 testing.expect(a.order(d) != .gt);
1389}
1390
1391test "big.int gcd non-one small" {
1392 var a = try Managed.initSet(testing.allocator, 17);
1393 defer a.deinit();
1394 var b = try Managed.initSet(testing.allocator, 97);
1395 defer b.deinit();
1396 var r = try Managed.init(testing.allocator);
1397 defer r.deinit();
1398
1399 try r.gcd(a, b);
1400
1401 testing.expect((try r.to(u32)) == 1);
1402}
1403
1404test "big.int gcd non-one small" {
1405 var a = try Managed.initSet(testing.allocator, 4864);
1406 defer a.deinit();
1407 var b = try Managed.initSet(testing.allocator, 3458);
1408 defer b.deinit();
1409 var r = try Managed.init(testing.allocator);
1410 defer r.deinit();
1411
1412 try r.gcd(a, b);
1413
1414 testing.expect((try r.to(u32)) == 38);
1415}
1416
1417test "big.int gcd non-one large" {
1418 var a = try Managed.initSet(testing.allocator, 0xffffffffffffffff);
1419 defer a.deinit();
1420 var b = try Managed.initSet(testing.allocator, 0xffffffffffffffff7777);
1421 defer b.deinit();
1422 var r = try Managed.init(testing.allocator);
1423 defer r.deinit();
1424
1425 try r.gcd(a, b);
1426
1427 testing.expect((try r.to(u32)) == 4369);
1428}
1429
1430test "big.int gcd large multi-limb result" {
1431 var a = try Managed.initSet(testing.allocator, 0x12345678123456781234567812345678123456781234567812345678);
1432 defer a.deinit();
1433 var b = try Managed.initSet(testing.allocator, 0x12345671234567123456712345671234567123456712345671234567);
1434 defer b.deinit();
1435 var r = try Managed.init(testing.allocator);
1436 defer r.deinit();
1437
1438 try r.gcd(a, b);
1439
1440 const answer = (try r.to(u256));
1441 testing.expect(answer == 0xf000000ff00000fff0000ffff000fffff00ffffff1);
1442}
1443
1444test "big.int gcd one large" {
1445 var a = try Managed.initSet(testing.allocator, 1897056385327307);
1446 defer a.deinit();
1447 var b = try Managed.initSet(testing.allocator, 2251799813685248);
1448 defer b.deinit();
1449 var r = try Managed.init(testing.allocator);
1450 defer r.deinit();
1451
1452 try r.gcd(a, b);
1453
1454 testing.expect((try r.to(u64)) == 1);
1455}
lib/std/math/big/rational.zig+60-57
......@@ -5,10 +5,10 @@ const mem = std.mem;
55const testing = std.testing;
66const Allocator = mem.Allocator;
77
8const bn = @import("int.zig");
9const Limb = bn.Limb;
10const DoubleLimb = bn.DoubleLimb;
11const Int = bn.Int;
8const Limb = std.math.big.Limb;
9const DoubleLimb = std.math.big.DoubleLimb;
10const Int = std.math.big.int.Managed;
11const IntConst = std.math.big.int.Const;
1212
1313/// An arbitrary-precision rational number.
1414///
......@@ -17,6 +17,9 @@ const Int = bn.Int;
1717///
1818/// Rational's are always normalized. That is, for a Rational r = p/q where p and q are integers,
1919/// gcd(p, q) = 1 always.
20///
21/// TODO rework this to store its own allocator and use a non-managed big int, to avoid double
22/// allocator storage.
2023pub const Rational = struct {
2124 /// Numerator. Determines the sign of the Rational.
2225 p: Int,
......@@ -98,20 +101,20 @@ pub const Rational = struct {
98101 if (point) |i| {
99102 try self.p.setString(10, str[0..i]);
100103
101 const base = Int.initFixed(([_]Limb{10})[0..]);
104 const base = IntConst{ .limbs = &[_]Limb{10}, .positive = true };
102105
103106 var j: usize = start;
104107 while (j < str.len - i - 1) : (j += 1) {
105 try self.p.mul(self.p, base);
108 try self.p.mul(self.p.toConst(), base);
106109 }
107110
108111 try self.q.setString(10, str[i + 1 ..]);
109 try self.p.add(self.p, self.q);
112 try self.p.add(self.p.toConst(), self.q.toConst());
110113
111114 try self.q.set(1);
112115 var k: usize = i + 1;
113116 while (k < str.len) : (k += 1) {
114 try self.q.mul(self.q, base);
117 try self.q.mul(self.q.toConst(), base);
115118 }
116119
117120 try self.reduce();
......@@ -218,14 +221,14 @@ pub const Rational = struct {
218221 }
219222
220223 // 2. compute quotient and remainder
221 var q = try Int.init(self.p.allocator.?);
224 var q = try Int.init(self.p.allocator);
222225 defer q.deinit();
223226
224227 // unused
225 var r = try Int.init(self.p.allocator.?);
228 var r = try Int.init(self.p.allocator);
226229 defer r.deinit();
227230
228 try Int.divTrunc(&q, &r, a2, b2);
231 try Int.divTrunc(&q, &r, a2.toConst(), b2.toConst());
229232
230233 var mantissa = extractLowBits(q, BitReprType);
231234 var have_rem = r.len() > 0;
......@@ -293,14 +296,14 @@ pub const Rational = struct {
293296
294297 /// Set a Rational directly from an Int.
295298 pub fn copyInt(self: *Rational, a: Int) !void {
296 try self.p.copy(a);
299 try self.p.copy(a.toConst());
297300 try self.q.set(1);
298301 }
299302
300303 /// Set a Rational directly from a ratio of two Int's.
301304 pub fn copyRatio(self: *Rational, a: Int, b: Int) !void {
302 try self.p.copy(a);
303 try self.q.copy(b);
305 try self.p.copy(a.toConst());
306 try self.q.copy(b.toConst());
304307
305308 self.p.setSign(@boolToInt(self.p.isPositive()) ^ @boolToInt(self.q.isPositive()) == 0);
306309 self.q.setSign(true);
......@@ -327,13 +330,13 @@ pub const Rational = struct {
327330
328331 /// Returns math.Order.lt, math.Order.eq, math.Order.gt if a < b, a == b or a
329332 /// > b respectively.
330 pub fn cmp(a: Rational, b: Rational) !math.Order {
333 pub fn order(a: Rational, b: Rational) !math.Order {
331334 return cmpInternal(a, b, true);
332335 }
333336
334337 /// Returns math.Order.lt, math.Order.eq, math.Order.gt if |a| < |b|, |a| ==
335338 /// |b| or |a| > |b| respectively.
336 pub fn cmpAbs(a: Rational, b: Rational) !math.Order {
339 pub fn orderAbs(a: Rational, b: Rational) !math.Order {
337340 return cmpInternal(a, b, false);
338341 }
339342
......@@ -341,16 +344,16 @@ pub const Rational = struct {
341344 fn cmpInternal(a: Rational, b: Rational, is_abs: bool) !math.Order {
342345 // TODO: Would a div compare algorithm of sorts be viable and quicker? Can we avoid
343346 // the memory allocations here?
344 var q = try Int.init(a.p.allocator.?);
347 var q = try Int.init(a.p.allocator);
345348 defer q.deinit();
346349
347 var p = try Int.init(b.p.allocator.?);
350 var p = try Int.init(b.p.allocator);
348351 defer p.deinit();
349352
350 try q.mul(a.p, b.q);
351 try p.mul(b.p, a.q);
353 try q.mul(a.p.toConst(), b.q.toConst());
354 try p.mul(b.p.toConst(), a.q.toConst());
352355
353 return if (is_abs) q.cmpAbs(p) else q.cmp(p);
356 return if (is_abs) q.orderAbs(p) else q.order(p);
354357 }
355358
356359 /// rma = a + b.
......@@ -364,7 +367,7 @@ pub const Rational = struct {
364367
365368 var sr: Rational = undefined;
366369 if (aliased) {
367 sr = try Rational.init(rma.p.allocator.?);
370 sr = try Rational.init(rma.p.allocator);
368371 r = &sr;
369372 aliased = true;
370373 }
......@@ -373,11 +376,11 @@ pub const Rational = struct {
373376 r.deinit();
374377 };
375378
376 try r.p.mul(a.p, b.q);
377 try r.q.mul(b.p, a.q);
378 try r.p.add(r.p, r.q);
379 try r.p.mul(a.p.toConst(), b.q.toConst());
380 try r.q.mul(b.p.toConst(), a.q.toConst());
381 try r.p.add(r.p.toConst(), r.q.toConst());
379382
380 try r.q.mul(a.q, b.q);
383 try r.q.mul(a.q.toConst(), b.q.toConst());
381384 try r.reduce();
382385 }
383386
......@@ -392,7 +395,7 @@ pub const Rational = struct {
392395
393396 var sr: Rational = undefined;
394397 if (aliased) {
395 sr = try Rational.init(rma.p.allocator.?);
398 sr = try Rational.init(rma.p.allocator);
396399 r = &sr;
397400 aliased = true;
398401 }
......@@ -401,11 +404,11 @@ pub const Rational = struct {
401404 r.deinit();
402405 };
403406
404 try r.p.mul(a.p, b.q);
405 try r.q.mul(b.p, a.q);
406 try r.p.sub(r.p, r.q);
407 try r.p.mul(a.p.toConst(), b.q.toConst());
408 try r.q.mul(b.p.toConst(), a.q.toConst());
409 try r.p.sub(r.p.toConst(), r.q.toConst());
407410
408 try r.q.mul(a.q, b.q);
411 try r.q.mul(a.q.toConst(), b.q.toConst());
409412 try r.reduce();
410413 }
411414
......@@ -415,8 +418,8 @@ pub const Rational = struct {
415418 ///
416419 /// Returns an error if memory could not be allocated.
417420 pub fn mul(r: *Rational, a: Rational, b: Rational) !void {
418 try r.p.mul(a.p, b.p);
419 try r.q.mul(a.q, b.q);
421 try r.p.mul(a.p.toConst(), b.p.toConst());
422 try r.q.mul(a.q.toConst(), b.q.toConst());
420423 try r.reduce();
421424 }
422425
......@@ -430,8 +433,8 @@ pub const Rational = struct {
430433 @panic("division by zero");
431434 }
432435
433 try r.p.mul(a.p, b.q);
434 try r.q.mul(b.p, a.q);
436 try r.p.mul(a.p.toConst(), b.q.toConst());
437 try r.q.mul(b.p.toConst(), a.q.toConst());
435438 try r.reduce();
436439 }
437440
......@@ -442,7 +445,7 @@ pub const Rational = struct {
442445
443446 // reduce r/q such that gcd(r, q) = 1
444447 fn reduce(r: *Rational) !void {
445 var a = try Int.init(r.p.allocator.?);
448 var a = try Int.init(r.p.allocator);
446449 defer a.deinit();
447450
448451 const sign = r.p.isPositive();
......@@ -450,15 +453,15 @@ pub const Rational = struct {
450453 try a.gcd(r.p, r.q);
451454 r.p.setSign(sign);
452455
453 const one = Int.initFixed(([_]Limb{1})[0..]);
454 if (a.cmp(one) != .eq) {
455 var unused = try Int.init(r.p.allocator.?);
456 const one = IntConst{ .limbs = &[_]Limb{1}, .positive = true };
457 if (a.toConst().order(one) != .eq) {
458 var unused = try Int.init(r.p.allocator);
456459 defer unused.deinit();
457460
458461 // TODO: divexact would be useful here
459462 // TODO: don't copy r.q for div
460 try Int.divTrunc(&r.p, &unused, r.p, a);
461 try Int.divTrunc(&r.q, &unused, r.q, a);
463 try Int.divTrunc(&r.p, &unused, r.p.toConst(), a.toConst());
464 try Int.divTrunc(&r.q, &unused, r.q.toConst(), a.toConst());
462465 }
463466 }
464467};
......@@ -596,25 +599,25 @@ test "big.rational copy" {
596599 var a = try Rational.init(testing.allocator);
597600 defer a.deinit();
598601
599 const b = try Int.initSet(testing.allocator, 5);
602 var b = try Int.initSet(testing.allocator, 5);
600603 defer b.deinit();
601604
602605 try a.copyInt(b);
603606 testing.expect((try a.p.to(u32)) == 5);
604607 testing.expect((try a.q.to(u32)) == 1);
605608
606 const c = try Int.initSet(testing.allocator, 7);
609 var c = try Int.initSet(testing.allocator, 7);
607610 defer c.deinit();
608 const d = try Int.initSet(testing.allocator, 3);
611 var d = try Int.initSet(testing.allocator, 3);
609612 defer d.deinit();
610613
611614 try a.copyRatio(c, d);
612615 testing.expect((try a.p.to(u32)) == 7);
613616 testing.expect((try a.q.to(u32)) == 3);
614617
615 const e = try Int.initSet(testing.allocator, 9);
618 var e = try Int.initSet(testing.allocator, 9);
616619 defer e.deinit();
617 const f = try Int.initSet(testing.allocator, 3);
620 var f = try Int.initSet(testing.allocator, 3);
618621 defer f.deinit();
619622
620623 try a.copyRatio(e, f);
......@@ -680,7 +683,7 @@ test "big.rational swap" {
680683 testing.expect((try b.q.to(u32)) == 23);
681684}
682685
683test "big.rational cmp" {
686test "big.rational order" {
684687 var a = try Rational.init(testing.allocator);
685688 defer a.deinit();
686689 var b = try Rational.init(testing.allocator);
......@@ -688,11 +691,11 @@ test "big.rational cmp" {
688691
689692 try a.setRatio(500, 231);
690693 try b.setRatio(18903, 8584);
691 testing.expect((try a.cmp(b)) == .lt);
694 testing.expect((try a.order(b)) == .lt);
692695
693696 try a.setRatio(890, 10);
694697 try b.setRatio(89, 1);
695 testing.expect((try a.cmp(b)) == .eq);
698 testing.expect((try a.order(b)) == .eq);
696699}
697700
698701test "big.rational add single-limb" {
......@@ -703,11 +706,11 @@ test "big.rational add single-limb" {
703706
704707 try a.setRatio(500, 231);
705708 try b.setRatio(18903, 8584);
706 testing.expect((try a.cmp(b)) == .lt);
709 testing.expect((try a.order(b)) == .lt);
707710
708711 try a.setRatio(890, 10);
709712 try b.setRatio(89, 1);
710 testing.expect((try a.cmp(b)) == .eq);
713 testing.expect((try a.order(b)) == .eq);
711714}
712715
713716test "big.rational add" {
......@@ -723,7 +726,7 @@ test "big.rational add" {
723726 try a.add(a, b);
724727
725728 try r.setRatio(984786924199, 290395044174);
726 testing.expect((try a.cmp(r)) == .eq);
729 testing.expect((try a.order(r)) == .eq);
727730}
728731
729732test "big.rational sub" {
......@@ -739,7 +742,7 @@ test "big.rational sub" {
739742 try a.sub(a, b);
740743
741744 try r.setRatio(979040510045, 290395044174);
742 testing.expect((try a.cmp(r)) == .eq);
745 testing.expect((try a.order(r)) == .eq);
743746}
744747
745748test "big.rational mul" {
......@@ -755,7 +758,7 @@ test "big.rational mul" {
755758 try a.mul(a, b);
756759
757760 try r.setRatio(571481443, 17082061422);
758 testing.expect((try a.cmp(r)) == .eq);
761 testing.expect((try a.order(r)) == .eq);
759762}
760763
761764test "big.rational div" {
......@@ -771,7 +774,7 @@ test "big.rational div" {
771774 try a.div(a, b);
772775
773776 try r.setRatio(75531824394, 221015929);
774 testing.expect((try a.cmp(r)) == .eq);
777 testing.expect((try a.order(r)) == .eq);
775778}
776779
777780test "big.rational div" {
......@@ -784,11 +787,11 @@ test "big.rational div" {
784787 a.invert();
785788
786789 try r.setRatio(23341, 78923);
787 testing.expect((try a.cmp(r)) == .eq);
790 testing.expect((try a.order(r)) == .eq);
788791
789792 try a.setRatio(-78923, 23341);
790793 a.invert();
791794
792795 try r.setRatio(-23341, 78923);
793 testing.expect((try a.cmp(r)) == .eq);
796 testing.expect((try a.order(r)) == .eq);
794797}
lib/std/testing.zig+1-1
......@@ -12,7 +12,7 @@ pub const failing_allocator = &failing_allocator_instance.allocator;
1212pub var failing_allocator_instance = FailingAllocator.init(&base_allocator_instance.allocator, 0);
1313
1414pub var base_allocator_instance = std.heap.ThreadSafeFixedBufferAllocator.init(allocator_mem[0..]);
15var allocator_mem: [1024 * 1024]u8 = undefined;
15var allocator_mem: [2 * 1024 * 1024]u8 = undefined;
1616
1717/// This function is intended to be used only in tests. It prints diagnostics to stderr
1818/// and then aborts when actual_error_union is not expected_error.
src-self-hosted/ir.zig+40-22
......@@ -4,7 +4,8 @@ const Allocator = std.mem.Allocator;
44const Value = @import("value.zig").Value;
55const Type = @import("type.zig").Type;
66const assert = std.debug.assert;
7const BigInt = std.math.big.Int;
7const BigIntConst = std.math.big.int.Const;
8const BigIntMutable = std.math.big.int.Mutable;
89const Target = std.Target;
910
1011pub const text = @import("ir/text.zig");
......@@ -483,29 +484,32 @@ const Analyze = struct {
483484 });
484485 }
485486
486 fn constIntBig(self: *Analyze, src: usize, ty: Type, big_int: BigInt) !*Inst {
487 if (big_int.isPositive()) {
487 fn constIntBig(self: *Analyze, src: usize, ty: Type, big_int: BigIntConst) !*Inst {
488 const val_payload = if (big_int.positive) blk: {
488489 if (big_int.to(u64)) |x| {
489490 return self.constIntUnsigned(src, ty, x);
490491 } else |err| switch (err) {
491492 error.NegativeIntoUnsigned => unreachable,
492493 error.TargetTooSmall => {}, // handled below
493494 }
494 } else {
495 const big_int_payload = try self.arena.allocator.create(Value.Payload.IntBigPositive);
496 big_int_payload.* = .{ .limbs = big_int.limbs };
497 break :blk &big_int_payload.base;
498 } else blk: {
495499 if (big_int.to(i64)) |x| {
496500 return self.constIntSigned(src, ty, x);
497501 } else |err| switch (err) {
498502 error.NegativeIntoUnsigned => unreachable,
499503 error.TargetTooSmall => {}, // handled below
500504 }
501 }
502
503 const big_int_payload = try self.arena.allocator.create(Value.Payload.IntBig);
504 big_int_payload.* = .{ .big_int = big_int };
505 const big_int_payload = try self.arena.allocator.create(Value.Payload.IntBigNegative);
506 big_int_payload.* = .{ .limbs = big_int.limbs };
507 break :blk &big_int_payload.base;
508 };
505509
506510 return self.constInst(src, .{
507511 .ty = ty,
508 .val = Value.initPayload(&big_int_payload.base),
512 .val = Value.initPayload(val_payload),
509513 });
510514 }
511515
......@@ -745,19 +749,31 @@ const Analyze = struct {
745749 var rhs_space: Value.BigIntSpace = undefined;
746750 const lhs_bigint = lhs_val.toBigInt(&lhs_space);
747751 const rhs_bigint = rhs_val.toBigInt(&rhs_space);
748 var result_bigint = try BigInt.init(&self.arena.allocator);
749 try BigInt.add(&result_bigint, lhs_bigint, rhs_bigint);
752 const limbs = try self.arena.allocator.alloc(
753 std.math.big.Limb,
754 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
755 );
756 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
757 result_bigint.add(lhs_bigint, rhs_bigint);
758 const result_limbs = result_bigint.limbs[0..result_bigint.len];
750759
751760 if (!lhs.ty.eql(rhs.ty)) {
752761 return self.fail(inst.base.src, "TODO implement peer type resolution", .{});
753762 }
754763
755 const val_payload = try self.arena.allocator.create(Value.Payload.IntBig);
756 val_payload.* = .{ .big_int = result_bigint };
764 const val_payload = if (result_bigint.positive) blk: {
765 const val_payload = try self.arena.allocator.create(Value.Payload.IntBigPositive);
766 val_payload.* = .{ .limbs = result_limbs };
767 break :blk &val_payload.base;
768 } else blk: {
769 const val_payload = try self.arena.allocator.create(Value.Payload.IntBigNegative);
770 val_payload.* = .{ .limbs = result_limbs };
771 break :blk &val_payload.base;
772 };
757773
758774 return self.constInst(inst.base.src, .{
759775 .ty = lhs.ty,
760 .val = Value.initPayload(&val_payload.base),
776 .val = Value.initPayload(val_payload),
761777 });
762778 }
763779 }
......@@ -1076,7 +1092,8 @@ const Analyze = struct {
10761092 return self.constUndef(src, Type.initTag(.bool));
10771093 const is_unsigned = if (lhs_is_float) x: {
10781094 var bigint_space: Value.BigIntSpace = undefined;
1079 var bigint = lhs_val.toBigInt(&bigint_space);
1095 var bigint = try lhs_val.toBigInt(&bigint_space).toManaged(self.allocator);
1096 defer bigint.deinit();
10801097 const zcmp = lhs_val.orderAgainstZero();
10811098 if (lhs_val.floatHasFraction()) {
10821099 switch (op) {
......@@ -1085,12 +1102,12 @@ const Analyze = struct {
10851102 else => {},
10861103 }
10871104 if (zcmp == .lt) {
1088 try bigint.addScalar(bigint, -1);
1105 try bigint.addScalar(bigint.toConst(), -1);
10891106 } else {
1090 try bigint.addScalar(bigint, 1);
1107 try bigint.addScalar(bigint.toConst(), 1);
10911108 }
10921109 }
1093 lhs_bits = bigint.bitCountTwosComp();
1110 lhs_bits = bigint.toConst().bitCountTwosComp();
10941111 break :x (zcmp != .lt);
10951112 } else x: {
10961113 lhs_bits = lhs_val.intBitCountTwosComp();
......@@ -1110,7 +1127,8 @@ const Analyze = struct {
11101127 return self.constUndef(src, Type.initTag(.bool));
11111128 const is_unsigned = if (rhs_is_float) x: {
11121129 var bigint_space: Value.BigIntSpace = undefined;
1113 var bigint = rhs_val.toBigInt(&bigint_space);
1130 var bigint = try rhs_val.toBigInt(&bigint_space).toManaged(self.allocator);
1131 defer bigint.deinit();
11141132 const zcmp = rhs_val.orderAgainstZero();
11151133 if (rhs_val.floatHasFraction()) {
11161134 switch (op) {
......@@ -1119,12 +1137,12 @@ const Analyze = struct {
11191137 else => {},
11201138 }
11211139 if (zcmp == .lt) {
1122 try bigint.addScalar(bigint, -1);
1140 try bigint.addScalar(bigint.toConst(), -1);
11231141 } else {
1124 try bigint.addScalar(bigint, 1);
1142 try bigint.addScalar(bigint.toConst(), 1);
11251143 }
11261144 }
1127 rhs_bits = bigint.bitCountTwosComp();
1145 rhs_bits = bigint.toConst().bitCountTwosComp();
11281146 break :x (zcmp != .lt);
11291147 } else x: {
11301148 rhs_bits = rhs_val.intBitCountTwosComp();
src-self-hosted/ir/text.zig+20-15
......@@ -4,7 +4,8 @@ const std = @import("std");
44const mem = std.mem;
55const Allocator = std.mem.Allocator;
66const assert = std.debug.assert;
7const BigInt = std.math.big.Int;
7const BigIntConst = std.math.big.int.Const;
8const BigIntMutable = std.math.big.int.Mutable;
89const Type = @import("../type.zig").Type;
910const Value = @import("../value.zig").Value;
1011const ir = @import("../ir.zig");
......@@ -99,7 +100,7 @@ pub const Inst = struct {
99100 base: Inst,
100101
101102 positionals: struct {
102 int: BigInt,
103 int: BigIntConst,
103104 },
104105 kw_args: struct {},
105106 };
......@@ -521,7 +522,7 @@ pub const Module = struct {
521522 },
522523 bool => return stream.writeByte("01"[@boolToInt(param)]),
523524 []u8, []const u8 => return std.zig.renderStringLiteral(param, stream),
524 BigInt => return stream.print("{}", .{param}),
525 BigIntConst => return stream.print("{}", .{param}),
525526 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
526527 }
527528 }
......@@ -644,7 +645,7 @@ const Parser = struct {
644645 };
645646 }
646647
647 fn parseIntegerLiteral(self: *Parser) !BigInt {
648 fn parseIntegerLiteral(self: *Parser) !BigIntConst {
648649 const start = self.i;
649650 if (self.source[self.i] == '-') self.i += 1;
650651 while (true) : (self.i += 1) switch (self.source[self.i]) {
......@@ -652,17 +653,21 @@ const Parser = struct {
652653 else => break,
653654 };
654655 const number_text = self.source[start..self.i];
655 var result = try BigInt.init(&self.arena.allocator);
656 result.setString(10, number_text) catch |err| {
657 self.i = start;
658 switch (err) {
659 error.InvalidBase => unreachable,
660 error.InvalidCharForDigit => return self.fail("invalid digit in integer literal", .{}),
661 error.DigitTooLargeForBase => return self.fail("digit too large in integer literal", .{}),
662 else => |e| return e,
663 }
656 const base = 10;
657 // TODO reuse the same array list for this
658 const limbs_buffer_len = std.math.big.int.calcSetStringLimbsBufferLen(base, number_text.len);
659 const limbs_buffer = try self.allocator.alloc(std.math.big.Limb, limbs_buffer_len);
660 defer self.allocator.free(limbs_buffer);
661 const limb_len = std.math.big.int.calcSetStringLimbsBufferLen(base, number_text.len);
662 const limbs = try self.arena.allocator.alloc(std.math.big.Limb, limb_len);
663 var result = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
664 result.setString(base, number_text, limbs_buffer, self.allocator) catch |err| switch (err) {
665 error.InvalidCharacter => {
666 self.i = start;
667 return self.fail("invalid digit in integer literal", .{});
668 },
664669 };
665 return result;
670 return result.toConst();
666671 }
667672
668673 fn parseRoot(self: *Parser) !void {
......@@ -859,7 +864,7 @@ const Parser = struct {
859864 },
860865 *Inst => return parseParameterInst(self, body_ctx),
861866 []u8, []const u8 => return self.parseStringLiteral(),
862 BigInt => return self.parseIntegerLiteral(),
867 BigIntConst => return self.parseIntegerLiteral(),
863868 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
864869 }
865870 return self.fail("TODO parse parameter {}", .{@typeName(T)});
src-self-hosted/translate_c.zig+16-14
......@@ -3913,18 +3913,20 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {
39133913 };
39143914 var aps_int = int;
39153915 const is_negative = ZigClangAPSInt_isSigned(int) and ZigClangAPSInt_isNegative(int);
3916 if (is_negative)
3917 aps_int = ZigClangAPSInt_negate(aps_int);
3918 var big = try math.big.Int.initCapacity(c.a(), num_limbs);
3919 if (is_negative)
3920 big.negate();
3921 defer big.deinit();
3916 if (is_negative) aps_int = ZigClangAPSInt_negate(aps_int);
3917 defer if (is_negative) {
3918 ZigClangAPSInt_free(aps_int);
3919 };
3920
3921 const limbs = try c.a().alloc(math.big.Limb, num_limbs);
3922 defer c.a().free(limbs);
3923
39223924 const data = ZigClangAPSInt_getRawData(aps_int);
3923 switch (@sizeOf(std.math.big.Limb)) {
3925 switch (@sizeOf(math.big.Limb)) {
39243926 8 => {
39253927 var i: usize = 0;
39263928 while (i < num_limbs) : (i += 1) {
3927 big.limbs[i] = data[i];
3929 limbs[i] = data[i];
39283930 }
39293931 },
39303932 4 => {
......@@ -3934,23 +3936,23 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {
39343936 limb_i += 2;
39353937 data_i += 1;
39363938 }) {
3937 big.limbs[limb_i] = @truncate(u32, data[data_i]);
3938 big.limbs[limb_i + 1] = @truncate(u32, data[data_i] >> 32);
3939 limbs[limb_i] = @truncate(u32, data[data_i]);
3940 limbs[limb_i + 1] = @truncate(u32, data[data_i] >> 32);
39393941 }
39403942 },
39413943 else => @compileError("unimplemented"),
39423944 }
3943 const str = big.toString(c.a(), 10, false) catch |err| switch (err) {
3945
3946 const big: math.big.int.Const = .{ .limbs = limbs, .positive = !is_negative };
3947 const str = big.toStringAlloc(c.a(), 10, false) catch |err| switch (err) {
39443948 error.OutOfMemory => return error.OutOfMemory,
3945 else => unreachable,
39463949 };
3950 defer c.a().free(str);
39473951 const token = try appendToken(c, .IntegerLiteral, str);
39483952 const node = try c.a().create(ast.Node.IntegerLiteral);
39493953 node.* = .{
39503954 .token = token,
39513955 };
3952 if (is_negative)
3953 ZigClangAPSInt_free(aps_int);
39543956 return &node.base;
39553957}
39563958
src-self-hosted/value.zig+55-22
......@@ -2,7 +2,8 @@ const std = @import("std");
22const Type = @import("type.zig").Type;
33const log2 = std.math.log2;
44const assert = std.debug.assert;
5const BigInt = std.math.big.Int;
5const BigIntConst = std.math.big.int.Const;
6const BigIntMutable = std.math.big.int.Mutable;
67const Target = std.Target;
78const Allocator = std.mem.Allocator;
89
......@@ -60,7 +61,8 @@ pub const Value = extern union {
6061 ty,
6162 int_u64,
6263 int_i64,
63 int_big,
64 int_big_positive,
65 int_big_negative,
6466 function,
6567 ref,
6668 ref_val,
......@@ -148,7 +150,8 @@ pub const Value = extern union {
148150 .ty => return val.cast(Payload.Ty).?.ty.format("", options, out_stream),
149151 .int_u64 => return std.fmt.formatIntValue(val.cast(Payload.Int_u64).?.int, "", options, out_stream),
150152 .int_i64 => return std.fmt.formatIntValue(val.cast(Payload.Int_i64).?.int, "", options, out_stream),
151 .int_big => return out_stream.print("{}", .{val.cast(Payload.IntBig).?.big_int}),
153 .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}),
154 .int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}),
152155 .function => return out_stream.writeAll("(function)"),
153156 .ref => return out_stream.writeAll("(ref)"),
154157 .ref_val => {
......@@ -216,7 +219,8 @@ pub const Value = extern union {
216219 .null_value,
217220 .int_u64,
218221 .int_i64,
219 .int_big,
222 .int_big_positive,
223 .int_big_negative,
220224 .function,
221225 .ref,
222226 .ref_val,
......@@ -227,7 +231,7 @@ pub const Value = extern union {
227231 }
228232
229233 /// Asserts the value is an integer.
230 pub fn toBigInt(self: Value, space: *BigIntSpace) BigInt {
234 pub fn toBigInt(self: Value, space: *BigIntSpace) BigIntConst {
231235 switch (self.tag()) {
232236 .ty,
233237 .u8_type,
......@@ -272,11 +276,12 @@ pub const Value = extern union {
272276
273277 .the_one_possible_value, // An integer with one possible value is always zero.
274278 .zero,
275 => return BigInt.initSetFixed(&space.limbs, 0),
279 => return BigIntMutable.init(&space.limbs, 0).toConst(),
276280
277 .int_u64 => return BigInt.initSetFixed(&space.limbs, self.cast(Payload.Int_u64).?.int),
278 .int_i64 => return BigInt.initSetFixed(&space.limbs, self.cast(Payload.Int_i64).?.int),
279 .int_big => return self.cast(Payload.IntBig).?.big_int,
281 .int_u64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_u64).?.int).toConst(),
282 .int_i64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_i64).?.int).toConst(),
283 .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt(),
284 .int_big_negative => return self.cast(Payload.IntBigPositive).?.asBigInt(),
280285 }
281286 }
282287
......@@ -330,7 +335,8 @@ pub const Value = extern union {
330335
331336 .int_u64 => return self.cast(Payload.Int_u64).?.int,
332337 .int_i64 => return @intCast(u64, self.cast(Payload.Int_u64).?.int),
333 .int_big => return self.cast(Payload.IntBig).?.big_int.to(u64) catch unreachable,
338 .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().to(u64) catch unreachable,
339 .int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().to(u64) catch unreachable,
334340 }
335341 }
336342
......@@ -391,7 +397,8 @@ pub const Value = extern union {
391397 .int_i64 => {
392398 @panic("TODO implement i64 intBitCountTwosComp");
393399 },
394 .int_big => return self.cast(Payload.IntBig).?.big_int.bitCountTwosComp(),
400 .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().bitCountTwosComp(),
401 .int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().bitCountTwosComp(),
395402 }
396403 }
397404
......@@ -466,10 +473,18 @@ pub const Value = extern union {
466473 .ComptimeInt => return true,
467474 else => unreachable,
468475 },
469 .int_big => switch (ty.zigTypeTag()) {
476 .int_big_positive => switch (ty.zigTypeTag()) {
470477 .Int => {
471478 const info = ty.intInfo(target);
472 return self.cast(Payload.IntBig).?.big_int.fitsInTwosComp(info.signed, info.bits);
479 return self.cast(Payload.IntBigPositive).?.asBigInt().fitsInTwosComp(info.signed, info.bits);
480 },
481 .ComptimeInt => return true,
482 else => unreachable,
483 },
484 .int_big_negative => switch (ty.zigTypeTag()) {
485 .Int => {
486 const info = ty.intInfo(target);
487 return self.cast(Payload.IntBigNegative).?.asBigInt().fitsInTwosComp(info.signed, info.bits);
473488 },
474489 .ComptimeInt => return true,
475490 else => unreachable,
......@@ -521,7 +536,8 @@ pub const Value = extern union {
521536 .undef,
522537 .int_u64,
523538 .int_i64,
524 .int_big,
539 .int_big_positive,
540 .int_big_negative,
525541 .the_one_possible_value,
526542 => unreachable,
527543
......@@ -578,7 +594,8 @@ pub const Value = extern union {
578594
579595 .int_u64 => return std.math.order(lhs.cast(Payload.Int_u64).?.int, 0),
580596 .int_i64 => return std.math.order(lhs.cast(Payload.Int_i64).?.int, 0),
581 .int_big => return lhs.cast(Payload.IntBig).?.big_int.orderAgainstScalar(0),
597 .int_big_positive => return lhs.cast(Payload.IntBigPositive).?.asBigInt().orderAgainstScalar(0),
598 .int_big_negative => return lhs.cast(Payload.IntBigNegative).?.asBigInt().orderAgainstScalar(0),
582599 }
583600 }
584601
......@@ -597,7 +614,7 @@ pub const Value = extern union {
597614 var rhs_bigint_space: BigIntSpace = undefined;
598615 const lhs_bigint = lhs.toBigInt(&lhs_bigint_space);
599616 const rhs_bigint = rhs.toBigInt(&rhs_bigint_space);
600 return BigInt.cmp(lhs_bigint, rhs_bigint);
617 return lhs_bigint.order(rhs_bigint);
601618 }
602619
603620 /// Asserts the value is comparable.
......@@ -658,7 +675,8 @@ pub const Value = extern union {
658675 .function,
659676 .int_u64,
660677 .int_i64,
661 .int_big,
678 .int_big_positive,
679 .int_big_negative,
662680 .bytes,
663681 .undef,
664682 .repeated,
......@@ -712,7 +730,8 @@ pub const Value = extern union {
712730 .function,
713731 .int_u64,
714732 .int_i64,
715 .int_big,
733 .int_big_positive,
734 .int_big_negative,
716735 .undef,
717736 => unreachable,
718737
......@@ -775,7 +794,8 @@ pub const Value = extern union {
775794 .function,
776795 .int_u64,
777796 .int_i64,
778 .int_big,
797 .int_big_positive,
798 .int_big_negative,
779799 .ref,
780800 .ref_val,
781801 .bytes,
......@@ -801,9 +821,22 @@ pub const Value = extern union {
801821 int: i64,
802822 };
803823
804 pub const IntBig = struct {
805 base: Payload = Payload{ .tag = .int_big },
806 big_int: BigInt,
824 pub const IntBigPositive = struct {
825 base: Payload = Payload{ .tag = .int_big_positive },
826 limbs: []const std.math.big.Limb,
827
828 pub fn asBigInt(self: IntBigPositive) BigIntConst {
829 return BigIntConst{ .limbs = self.limbs, .positive = true };
830 }
831 };
832
833 pub const IntBigNegative = struct {
834 base: Payload = Payload{ .tag = .int_big_negative },
835 limbs: []const std.math.big.Limb,
836
837 pub fn asBigInt(self: IntBigNegative) BigIntConst {
838 return BigIntConst{ .limbs = self.limbs, .positive = false };
839 }
807840 };
808841
809842 pub const Function = struct {