| ... | @@ -1,298 +1,196 @@ | ... | @@ -1,298 +1,196 @@ |
| 1 | const std = @import("../../std.zig"); | 1 | const std = @import("../../std.zig"); |
| 2 | const debug = std.debug; | | |
| 3 | const testing = std.testing; | | |
| 4 | const math = std.math; | 2 | const math = std.math; |
| | 3 | const Limb = std.math.big.Limb; |
| | 4 | const DoubleLimb = std.math.big.DoubleLimb; |
| | 5 | const SignedDoubleLimb = std.math.big.SignedDoubleLimb; |
| | 6 | const Log2Limb = std.math.big.Log2Limb; |
| | 7 | const Allocator = std.mem.Allocator; |
| 5 | const mem = std.mem; | 8 | const mem = std.mem; |
| 6 | const Allocator = mem.Allocator; | | |
| 7 | const ArrayList = std.ArrayList; | | |
| 8 | const maxInt = std.math.maxInt; | 9 | const maxInt = std.math.maxInt; |
| 9 | const minInt = std.math.minInt; | 10 | const minInt = std.math.minInt; |
| | 11 | const assert = std.debug.assert; |
| 10 | | 12 | |
| 11 | pub const Limb = usize; | 13 | /// Returns the number of limbs needed to store `scalar`, which must be a |
| 12 | pub const DoubleLimb = std.meta.Int(false, 2 * Limb.bit_count); | 14 | /// primitive integer value. |
| 13 | pub const SignedDoubleLimb = std.meta.Int(true, DoubleLimb.bit_count); | 15 | pub fn calcLimbLen(scalar: var) usize { |
| 14 | pub const Log2Limb = math.Log2Int(Limb); | 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 | } |
| 15 | | 29 | |
| 16 | comptime { | 30 | pub fn calcToStringLimbsBufferLen(a_len: usize, base: u8) usize { |
| 17 | debug.assert(math.floorPowerOfTwo(usize, Limb.bit_count) == Limb.bit_count); | 31 | if (math.isPowerOfTwo(base)) |
| 18 | debug.assert(Limb.bit_count <= 64); // u128 set is unsupported | 32 | return 0; |
| 19 | debug.assert(Limb.is_signed == false); | 33 | return a_len + 2 + a_len + calcDivLimbsBufferLen(a_len, 1); |
| 20 | } | 34 | } |
| 21 | | 35 | |
| 22 | /// An arbitrary-precision big integer. | 36 | pub fn calcDivLimbsBufferLen(a_len: usize, b_len: usize) usize { |
| 23 | /// | 37 | return calcMulLimbsBufferLen(a_len, b_len, 2) * 4; |
| 24 | /// Memory is allocated by an Int as needed to ensure operations never overflow. The range of an | 38 | } |
| 25 | /// Int is bounded only by available memory. | | |
| 26 | pub const Int = struct { | | |
| 27 | const sign_bit: usize = 1 << (usize.bit_count - 1); | | |
| 28 | | 39 | |
| 29 | /// Default number of limbs to allocate on creation of an Int. | 40 | pub fn calcMulLimbsBufferLen(a_len: usize, b_len: usize, aliases: usize) usize { |
| 30 | pub const default_capacity = 4; | 41 | return aliases * math.max(a_len, b_len); |
| | 42 | } |
| | 43 | |
| | 44 | pub 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 | } |
| 31 | | 48 | |
| 32 | /// Allocator used by the Int when requesting memory. | 49 | pub fn calcSetStringLimbCount(base: u8, string_len: usize) usize { |
| 33 | allocator: ?*Allocator, | 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 |
| | 54 | pub 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 | } |
| 34 | | 75 | |
| | 76 | /// A arbitrary-precision big integer, with a fixed set of mutable limbs. |
| | 77 | pub const Mutable = struct { |
| 35 | /// Raw digits. These are: | 78 | /// Raw digits. These are: |
| 36 | /// | 79 | /// |
| 37 | /// * Little-endian ordered | 80 | /// * Little-endian ordered |
| 38 | /// * limbs.len >= 1 | 81 | /// * 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. |
| 40 | /// | 83 | /// |
| 41 | /// Accessing limbs directly should be avoided. | 84 | /// Accessing limbs directly should be avoided. |
| | 85 | /// These are allocated limbs; the `len` field tells the valid range. |
| 42 | limbs: []Limb, | 86 | limbs: []Limb, |
| | 87 | len: usize, |
| | 88 | positive: bool, |
| 43 | | 89 | |
| 44 | /// High bit is the sign bit. If set, Int is negative, else Int is positive. | 90 | pub fn toConst(self: Mutable) Const { |
| 45 | /// The remaining bits represent the number of limbs used by Int. | 91 | return .{ |
| 46 | metadata: usize, | 92 | .limbs = self.limbs[0..self.len], |
| 47 | | 93 | .positive = self.positive, |
| 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 | }, | | |
| 82 | }; | 94 | }; |
| 83 | } | 95 | } |
| 84 | | 96 | |
| 85 | /// Returns the number of limbs currently in use. | 97 | /// Asserts that the allocator owns the limbs memory. If this is not the case, |
| 86 | pub fn len(self: Int) usize { | 98 | /// use `toConst().toManaged()`. |
| 87 | return self.metadata & ~sign_bit; | 99 | pub fn toManaged(self: Mutable, allocator: *Allocator) Managed { |
| 88 | } | 100 | return .{ |
| 89 | | 101 | .allocator = allocator, |
| 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, | | |
| 119 | .limbs = limbs, | 102 | .limbs = limbs, |
| | 103 | .metadata = if (self.positive) |
| | 104 | self.len & ~Managed.sign_bit |
| | 105 | else |
| | 106 | self.len | Managed.sign_bit, |
| 120 | }; | 107 | }; |
| 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.?); | | |
| 153 | } | 108 | } |
| 154 | | 109 | |
| 155 | pub fn clone2(other: Int, allocator: *Allocator) !Int { | 110 | /// `value` is a primitive integer type. |
| 156 | return Int{ | 111 | /// Asserts the value fits within the provided `limbs_buffer`. |
| 157 | .allocator = allocator, | 112 | /// Note: `calcLimbLen` can be used to figure out how big an array to allocate for `limbs_buffer`. |
| 158 | .metadata = other.metadata, | 113 | pub fn init(limbs_buffer: []Limb, value: var) Mutable { |
| 159 | .limbs = block: { | 114 | limbs_buffer[0] = 0; |
| 160 | var limbs = try allocator.alloc(Limb, other.len()); | 115 | var self: Mutable = .{ |
| 161 | mem.copy(Limb, limbs[0..], other.limbs[0..other.len()]); | 116 | .limbs = limbs_buffer, |
| 162 | break :block limbs; | 117 | .len = 1, |
| 163 | }, | 118 | .positive = true, |
| 164 | }; | 119 | }; |
| | 120 | self.set(value); |
| | 121 | return self; |
| 165 | } | 122 | } |
| 166 | | 123 | |
| 167 | /// Copies the value of an Int to an existing Int so that they both have the same value. | 124 | /// Copies the value of a Const to an existing Mutable so that they both have the same value. |
| 168 | /// Extra memory will be allocated if the receiver does not have enough capacity. | 125 | /// Asserts the value fits in the limbs buffer. |
| 169 | pub fn copy(self: *Int, other: Int) !void { | 126 | pub fn copy(self: *Mutable, other: Const) void { |
| 170 | self.assertWritable(); | 127 | if (self.limbs.ptr != other.limbs.ptr) { |
| 171 | if (self.limbs.ptr == other.limbs.ptr) { | 128 | mem.copy(Limb, self.limbs[0..], other.limbs[0..other.limbs.len]); |
| 172 | return; | | |
| 173 | } | 129 | } |
| 174 | | 130 | self.positive = other.positive; |
| 175 | try self.ensureCapacity(other.len()); | 131 | self.len = other.limbs.len; |
| 176 | mem.copy(Limb, self.limbs[0..], other.limbs[0..other.len()]); | | |
| 177 | self.metadata = other.metadata; | | |
| 178 | } | 132 | } |
| 179 | | 133 | |
| 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 |
| 181 | /// performed. The address of the limbs field will not be the same after this function. | 135 | /// performed. The address of the limbs field will not be the same after this function. |
| 182 | pub fn swap(self: *Int, other: *Int) void { | 136 | pub fn swap(self: *Mutable, other: *Mutable) void { |
| 183 | self.assertWritable(); | 137 | mem.swap(Mutable, self, other); |
| 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; | | |
| 207 | } | 138 | } |
| 208 | | 139 | |
| 209 | /// Returns true if an Int is even. | 140 | pub fn dump(self: Mutable) void { |
| 210 | pub fn isEven(self: Int) bool { | 141 | for (self.limbs[0..self.len]) |limb| { |
| 211 | return !self.isOdd(); | 142 | std.debug.warn("{x} ", .{limb}); |
| 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 | } | | |
| 244 | } | 143 | } |
| 245 | | 144 | std.debug.warn("capacity={} positive={}\n", .{ self.limbs.len, self.positive }); |
| 246 | return bits; | | |
| 247 | } | 145 | } |
| 248 | | 146 | |
| 249 | pub fn fitsInTwosComp(self: Int, is_signed: bool, bit_count: usize) bool { | 147 | /// Clones an Mutable and returns a new Mutable with the same value. The new Mutable is a deep copy and |
| 250 | if (self.eqZero()) { | 148 | /// can be modified separately from the original. |
| 251 | return true; | 149 | /// Asserts that limbs is big enough to store the value. |
| 252 | } | 150 | pub fn clone(other: Mutable, limbs: []Limb) Mutable { |
| 253 | if (!is_signed and !self.isPositive()) { | 151 | mem.copy(Limb, limbs, other.limbs[0..other.len]); |
| 254 | return false; | 152 | return .{ |
| 255 | } | 153 | .limbs = limbs, |
| 256 | | 154 | .len = other.len, |
| 257 | const req_bits = self.bitCountTwosComp() + @boolToInt(self.isPositive() and is_signed); | 155 | .positive = other.positive, |
| 258 | return bit_count >= req_bits; | 156 | }; |
| 259 | } | 157 | } |
| 260 | | 158 | |
| 261 | /// Returns whether self can fit into an integer of the requested type. | 159 | pub fn negate(self: *Mutable) void { |
| 262 | pub fn fits(self: Int, comptime T: type) bool { | 160 | self.positive = !self.positive; |
| 263 | return self.fitsInTwosComp(T.is_signed, T.bit_count); | | |
| 264 | } | 161 | } |
| 265 | | 162 | |
| 266 | /// Returns the approximate size of the integer in the given base. Negative values accommodate for | 163 | /// Modify to become the absolute value |
| 267 | /// the minus sign. This is used for determining the number of characters needed to print the | 164 | pub fn abs(self: *Mutable) void { |
| 268 | /// value. It is inexact and may exceed the given value by ~1-2 bytes. | 165 | self.positive = true; |
| 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; | | |
| 272 | } | 166 | } |
| 273 | | 167 | |
| 274 | /// Sets an Int to value. Value must be an primitive integer type. | 168 | /// Sets the Mutable to value. Value must be an primitive integer type. |
| 275 | pub fn set(self: *Int, value: var) Allocator.Error!void { | 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 { |
| 276 | const T = @TypeOf(value); | 173 | const T = @TypeOf(value); |
| 277 | | 174 | |
| 278 | switch (@typeInfo(T)) { | 175 | switch (@typeInfo(T)) { |
| 279 | .Int => |info| { | 176 | .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; |
| 281 | | 178 | |
| 282 | try self.ensureCapacity(@sizeOf(UT) / @sizeOf(Limb)); | 179 | const needed_limbs = @sizeOf(UT) / @sizeOf(Limb); |
| 283 | self.metadata = 0; | 180 | assert(needed_limbs <= self.limbs.len); // value too big |
| 284 | self.setSign(value >= 0); | 181 | self.len = 0; |
| | 182 | self.positive = value >= 0; |
| 285 | | 183 | |
| 286 | var w_value: UT = if (value < 0) @intCast(UT, -value) else @intCast(UT, value); | 184 | var w_value: UT = if (value < 0) @intCast(UT, -value) else @intCast(UT, value); |
| 287 | | 185 | |
| 288 | if (info.bits <= Limb.bit_count) { | 186 | if (info.bits <= Limb.bit_count) { |
| 289 | self.limbs[0] = @as(Limb, w_value); | 187 | self.limbs[0] = @as(Limb, w_value); |
| 290 | self.metadata += 1; | 188 | self.len += 1; |
| 291 | } else { | 189 | } else { |
| 292 | var i: usize = 0; | 190 | var i: usize = 0; |
| 293 | while (w_value != 0) : (i += 1) { | 191 | while (w_value != 0) : (i += 1) { |
| 294 | self.limbs[i] = @truncate(Limb, w_value); | 192 | self.limbs[i] = @truncate(Limb, w_value); |
| 295 | self.metadata += 1; | 193 | self.len += 1; |
| 296 | | 194 | |
| 297 | // TODO: shift == 64 at compile-time fails. Fails on u128 limbs. | 195 | // TODO: shift == 64 at compile-time fails. Fails on u128 limbs. |
| 298 | w_value >>= Limb.bit_count / 2; | 196 | w_value >>= Limb.bit_count / 2; |
| ... | @@ -304,10 +202,10 @@ pub const Int = struct { | ... | @@ -304,10 +202,10 @@ pub const Int = struct { |
| 304 | comptime var w_value = if (value < 0) -value else value; | 202 | comptime var w_value = if (value < 0) -value else value; |
| 305 | | 203 | |
| 306 | const req_limbs = @divFloor(math.log2(w_value), Limb.bit_count) + 1; | 204 | 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 |
| 308 | | 206 | |
| 309 | self.metadata = req_limbs; | 207 | self.len = req_limbs; |
| 310 | self.setSign(value >= 0); | 208 | self.positive = value >= 0; |
| 311 | | 209 | |
| 312 | if (w_value <= maxInt(Limb)) { | 210 | if (w_value <= maxInt(Limb)) { |
| 313 | self.limbs[0] = w_value; | 211 | self.limbs[0] = w_value; |
| ... | @@ -323,83 +221,8 @@ pub const Int = struct { | ... | @@ -323,83 +221,8 @@ pub const Int = struct { |
| 323 | } | 221 | } |
| 324 | } | 222 | } |
| 325 | }, | 223 | }, |
| 326 | else => { | 224 | else => @compileError("cannot set Mutable using type " ++ @typeName(T)), |
| 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; | | |
| 395 | } | 225 | } |
| 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 | }; | | |
| 403 | } | 226 | } |
| 404 | | 227 | |
| 405 | /// Set self from the string representation `value`. | 228 | /// Set self from the string representation `value`. |
| ... | @@ -408,13 +231,25 @@ pub const Int = struct { | ... | @@ -408,13 +231,25 @@ pub const Int = struct { |
| 408 | /// not allowed (e.g. 0x43 should simply be 43). Underscores in the input string are | 231 | /// not allowed (e.g. 0x43 should simply be 43). Underscores in the input string are |
| 409 | /// ignored and can be used as digit separators. | 232 | /// ignored and can be used as digit separators. |
| 410 | /// | 233 | /// |
| 411 | /// Returns an error if memory could not be allocated or `value` has invalid digits for the | 234 | /// Asserts there is enough memory for the value in `self.limbs`. An upper bound on number of limbs can |
| 412 | /// requested base. | 235 | /// be determined with `calcSetStringLimbCount`. |
| 413 | pub fn setString(self: *Int, base: u8, value: []const u8) !void { | 236 | /// Asserts the base is in the range [2, 16]. |
| 414 | self.assertWritable(); | 237 | /// |
| 415 | if (base < 2 or base > 16) { | 238 | /// Returns an error if the value has invalid digits for the requested base. |
| 416 | return error.InvalidBase; | 239 | /// |
| 417 | } | 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); |
| 418 | | 253 | |
| 419 | var i: usize = 0; | 254 | var i: usize = 0; |
| 420 | var positive = true; | 255 | var positive = true; |
| ... | @@ -423,787 +258,561 @@ pub const Int = struct { | ... | @@ -423,787 +258,561 @@ pub const Int = struct { |
| 423 | i += 1; | 258 | i += 1; |
| 424 | } | 259 | } |
| 425 | | 260 | |
| 426 | const ap_base = Int.initFixed(([_]Limb{base})[0..]); | 261 | const ap_base: Const = .{ .limbs = &[_]Limb{base}, .positive = true }; |
| 427 | try self.set(0); | 262 | self.set(0); |
| 428 | | 263 | |
| 429 | for (value[i..]) |ch| { | 264 | for (value[i..]) |ch| { |
| 430 | if (ch == '_') { | 265 | if (ch == '_') { |
| 431 | continue; | 266 | continue; |
| 432 | } | 267 | } |
| 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 }; |
| 434 | | 270 | |
| 435 | const ap_d = Int.initFixed(([_]Limb{d})[0..]); | 271 | self.mul(self.toConst(), ap_base, limbs_buffer, allocator); |
| 436 | | 272 | self.add(self.toConst(), ap_d); |
| 437 | try self.mul(self.*, ap_base); | | |
| 438 | try self.add(self.*, ap_d); | | |
| 439 | } | 273 | } |
| 440 | self.setSign(positive); | 274 | self.positive = positive; |
| 441 | } | 275 | } |
| 442 | | 276 | |
| 443 | /// Converts self to a string in the requested base. Memory is allocated from the provided | 277 | /// r = a + scalar |
| 444 | /// allocator and not the one present in self. | 278 | /// |
| 445 | /// TODO make this call format instead of the other way around | 279 | /// r and a may be aliases. |
| 446 | pub fn toString(self: Int, allocator: *Allocator, base: u8, uppercase: bool) ![]const u8 { | 280 | /// scalar is a primitive integer type. |
| 447 | if (base < 2 or base > 16) { | 281 | /// |
| 448 | return error.InvalidBase; | 282 | /// Asserts the result fits in `r`. An upper bound on the number of limbs needed by |
| 449 | } | 283 | /// r is `math.max(a.limbs.len, calcLimbLen(scalar)) + 1`. |
| 450 | | 284 | pub fn addScalar(r: *Mutable, a: Const, scalar: var) void { |
| 451 | var digits = ArrayList(u8).init(allocator); | 285 | var limbs: [calcLimbLen(scalar)]Limb = undefined; |
| 452 | try digits.ensureCapacity(self.sizeInBase(base) + 1); | 286 | const operand = init(&limbs, scalar).toConst(); |
| 453 | defer digits.deinit(); | 287 | return add(r, a, operand); |
| | 288 | } |
| 454 | | 289 | |
| 455 | if (self.eqZero()) { | 290 | /// r = a + b |
| 456 | try digits.append('0'); | 291 | /// |
| 457 | return digits.toOwnedSlice(); | 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; |
| 458 | } | 303 | } |
| 459 | | 304 | |
| 460 | // Power of two: can do a single pass and use masks to extract digits. | 305 | if (a.limbs.len == 1 and b.limbs.len == 1 and a.positive == b.positive) { |
| 461 | if (math.isPowerOfTwo(base)) { | 306 | if (!@addWithOverflow(Limb, a.limbs[0], b.limbs[0], &r.limbs[0])) { |
| 462 | const base_shift = math.log2_int(Limb, base); | 307 | r.len = 1; |
| 463 | | 308 | r.positive = a.positive; |
| 464 | for (self.limbs[0..self.len()]) |limb| { | 309 | return; |
| 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 | } | | |
| 471 | } | 310 | } |
| | 311 | } |
| 472 | | 312 | |
| 473 | while (true) { | 313 | if (a.positive != b.positive) { |
| 474 | // always will have a non-zero digit somewhere | 314 | if (a.positive) { |
| 475 | const c = digits.pop(); | 315 | // (a) + (-b) => a - b |
| 476 | if (c != '0') { | 316 | r.sub(a, b.abs()); |
| 477 | digits.append(c) catch unreachable; | 317 | } else { |
| 478 | break; | 318 | // (-a) + (b) => b - a |
| 479 | } | 319 | r.sub(b, a.abs()); |
| 480 | } | 320 | } |
| 481 | } else { | 321 | } else { |
| 482 | // Non power-of-two: batch divisions per word size. | 322 | if (a.limbs.len >= b.limbs.len) { |
| 483 | const digits_per_limb = math.log(Limb, base, maxInt(Limb)); | 323 | lladd(r.limbs[0..], a.limbs[0..a.limbs.len], b.limbs[0..b.limbs.len]); |
| 484 | var limb_base: Limb = 1; | 324 | r.normalize(a.limbs.len + 1); |
| 485 | var j: usize = 0; | 325 | } else { |
| 486 | while (j < digits_per_limb) : (j += 1) { | 326 | lladd(r.limbs[0..], b.limbs[0..b.limbs.len], a.limbs[0..a.limbs.len]); |
| 487 | limb_base *= base; | 327 | r.normalize(b.limbs.len + 1); |
| 488 | } | 328 | } |
| 489 | | 329 | |
| 490 | var q = try self.clone2(allocator); | 330 | r.positive = a.positive; |
| 491 | defer q.deinit(); | 331 | } |
| 492 | q.abs(); | 332 | } |
| 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); | | |
| 500 | | 333 | |
| 501 | var r_word = r.limbs[0]; | 334 | /// r = a - b |
| 502 | var i: usize = 0; | 335 | /// |
| 503 | while (i < digits_per_limb) : (i += 1) { | 336 | /// r, a and b may be aliases. |
| 504 | const ch = try digitToChar(@intCast(u8, r_word % base), base, uppercase); | 337 | /// |
| 505 | r_word /= base; | 338 | /// Asserts the result fits in `r`. An upper bound on the number of limbs needed by |
| 506 | try digits.append(ch); | 339 | /// r is `math.max(a.limbs.len, b.limbs.len) + 1`. The +1 is not needed if both operands are positive. |
| 507 | } | 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; |
| 508 | } | 349 | } |
| 509 | | 350 | } else { |
| 510 | { | 351 | if (a.positive) { |
| 511 | debug.assert(q.len() == 1); | 352 | // (a) - (b) => a - b |
| 512 | | 353 | if (a.order(b) != .lt) { |
| 513 | var r_word = q.limbs[0]; | 354 | llsub(r.limbs[0..], a.limbs[0..a.limbs.len], b.limbs[0..b.limbs.len]); |
| 514 | while (r_word != 0) { | 355 | r.normalize(a.limbs.len); |
| 515 | const ch = try digitToChar(@intCast(u8, r_word % base), base, uppercase); | 356 | r.positive = true; |
| 516 | r_word /= base; | 357 | } else { |
| 517 | try digits.append(ch); | 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; |
| 518 | } | 372 | } |
| 519 | } | 373 | } |
| 520 | } | 374 | } |
| 521 | | | |
| 522 | if (!self.isPositive()) { | | |
| 523 | try digits.append('-'); | | |
| 524 | } | | |
| 525 | | | |
| 526 | var s = digits.toOwnedSlice(); | | |
| 527 | mem.reverse(u8, s); | | |
| 528 | return s; | | |
| 529 | } | 375 | } |
| 530 | | 376 | |
| 531 | /// To allow `std.fmt.printf` to work with Int. | 377 | /// rma = a * b |
| 532 | /// TODO make this non-allocating | 378 | /// |
| 533 | /// TODO support read-only fixed integers | 379 | /// `rma` may alias with `a` or `b`. |
| 534 | pub fn format( | 380 | /// `a` and `b` may alias with each other. |
| 535 | self: Int, | 381 | /// |
| 536 | comptime fmt: []const u8, | 382 | /// Asserts the result fits in `rma`. An upper bound on the number of limbs needed by |
| 537 | options: std.fmt.FormatOptions, | 383 | /// rma is given by `a.limbs.len + b.limbs.len + 1`. |
| 538 | out_stream: var, | 384 | /// |
| 539 | ) !void { | 385 | /// `limbs_buffer` is used for temporary storage. The amount required is given by `calcMulLimbsBufferLen`. |
| 540 | comptime var radix = 10; | 386 | pub fn mul(rma: *Mutable, a: Const, b: Const, limbs_buffer: []Limb, allocator: ?*Allocator) void { |
| 541 | comptime var uppercase = false; | 387 | var buf_index: usize = 0; |
| 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 | } | | |
| 564 | | 388 | |
| 565 | /// Returns math.Order.lt, math.Order.eq, math.Order.gt if |a| < |b|, |a| == | 389 | const a_copy = if (rma.limbs.ptr == a.limbs.ptr) blk: { |
| 566 | /// |b| or |a| > |b| respectively. | 390 | const start = buf_index; |
| 567 | pub fn cmpAbs(a: Int, b: Int) math.Order { | 391 | mem.copy(Limb, limbs_buffer[buf_index..], a.limbs); |
| 568 | if (a.len() < b.len()) { | 392 | buf_index += a.limbs.len; |
| 569 | return .lt; | 393 | break :blk a.toMutable(limbs_buffer[start..buf_index]).toConst(); |
| 570 | } | 394 | } else a; |
| 571 | if (a.len() > b.len()) { | | |
| 572 | return .gt; | | |
| 573 | } | | |
| 574 | | 395 | |
| 575 | var i: usize = a.len() - 1; | 396 | const b_copy = if (rma.limbs.ptr == b.limbs.ptr) blk: { |
| 576 | while (i != 0) : (i -= 1) { | 397 | const start = buf_index; |
| 577 | if (a.limbs[i] != b.limbs[i]) { | 398 | mem.copy(Limb, limbs_buffer[buf_index..], b.limbs); |
| 578 | break; | 399 | buf_index += b.limbs.len; |
| 579 | } | 400 | break :blk b.toMutable(limbs_buffer[start..buf_index]).toConst(); |
| 580 | } | 401 | } else b; |
| 581 | | 402 | |
| 582 | if (a.limbs[i] < b.limbs[i]) { | 403 | return rma.mulNoAlias(a_copy, b_copy, allocator); |
| 583 | return .lt; | | |
| 584 | } else if (a.limbs[i] > b.limbs[i]) { | | |
| 585 | return .gt; | | |
| 586 | } else { | | |
| 587 | return .eq; | | |
| 588 | } | | |
| 589 | } | 404 | } |
| 590 | | 405 | |
| 591 | /// Returns math.Order.lt, math.Order.eq, math.Order.gt if a < b, a == b or a | 406 | /// rma = a * b |
| 592 | /// > b respectively. | 407 | /// |
| 593 | pub fn cmp(a: Int, b: Int) math.Order { | 408 | /// `rma` may not alias with `a` or `b`. |
| 594 | if (a.isPositive() != b.isPositive()) { | 409 | /// `a` and `b` may alias with each other. |
| 595 | return if (a.isPositive()) .gt else .lt; | 410 | /// |
| 596 | } else { | 411 | /// Asserts the result fits in `rma`. An upper bound on the number of limbs needed by |
| 597 | const r = cmpAbs(a, b); | 412 | /// rma is given by `a.limbs.len + b.limbs.len + 1`. |
| 598 | return if (a.isPositive()) r else switch (r) { | 413 | /// |
| 599 | .lt => math.Order.gt, | 414 | /// If `allocator` is provided, it will be used for temporary storage to improve |
| 600 | .eq => math.Order.eq, | 415 | /// multiplication performance. `error.OutOfMemory` is handled with a fallback algorithm. |
| 601 | .gt => math.Order.lt, | 416 | pub fn mulNoAlias(rma: *Mutable, a: Const, b: Const, allocator: ?*Allocator) void { |
| 602 | }; | 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 | } |
| 603 | } | 426 | } |
| 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 | } | | |
| 622 | | 427 | |
| 623 | /// Returns true if a == b. | 428 | mem.set(Limb, rma.limbs[0 .. a.limbs.len + b.limbs.len + 1], 0); |
| 624 | pub fn eq(a: Int, b: Int) bool { | | |
| 625 | return cmp(a, b) == .eq; | | |
| 626 | } | | |
| 627 | | 429 | |
| 628 | // Normalize a possible sequence of leading zeros. | 430 | llmulacc(allocator, rma.limbs, a.limbs, b.limbs); |
| 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 | } | | |
| 643 | | 431 | |
| 644 | // Handle zero | 432 | rma.normalize(a.limbs.len + b.limbs.len); |
| 645 | r.setLen(if (j != 0) j else 1); | 433 | rma.positive = (a.positive == b.positive); |
| 646 | } | 434 | } |
| 647 | | 435 | |
| 648 | // Cannot be used as a result argument to any function. | 436 | /// q = a / b (rem r) |
| 649 | fn readOnlyPositive(a: Int) Int { | 437 | /// |
| 650 | return Int{ | 438 | /// a / b are floored (rounded towards 0). |
| 651 | .allocator = null, | 439 | /// q may alias with a or b. |
| 652 | .metadata = a.len(), | 440 | /// |
| 653 | .limbs = a.limbs, | 441 | /// Asserts there is enough memory to store q and r. |
| 654 | }; | 442 | /// The upper bound for r limb count is a.limbs.len. |
| 655 | } | 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); |
| 656 | | 458 | |
| 657 | /// Returns the number of limbs needed to store `scalar`, which must be a | 459 | // Trunc -> Floor. |
| 658 | /// primitive integer value. | 460 | if (!q.positive) { |
| 659 | pub fn calcLimbLen(scalar: var) usize { | 461 | const one: Const = .{ .limbs = &[_]Limb{1}, .positive = true }; |
| 660 | switch (@typeInfo(@TypeOf(scalar))) { | 462 | q.sub(q.toConst(), one); |
| 661 | .Int => return @sizeOf(scalar) / @sizeOf(Limb), | 463 | r.add(q.toConst(), one); |
| 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"), | | |
| 668 | } | 464 | } |
| | 465 | r.positive = b.positive; |
| 669 | } | 466 | } |
| 670 | | 467 | |
| 671 | /// r = a + scalar | 468 | /// q = a / b (rem r) |
| 672 | /// | 469 | /// |
| 673 | /// r and a may be aliases. | 470 | /// a / b are truncated (rounded towards -inf). |
| 674 | /// scalar is a primitive integer type. | 471 | /// q may alias with a or b. |
| 675 | /// | 472 | /// |
| 676 | /// Returns an error if memory could not be allocated. | 473 | /// Asserts there is enough memory to store q and r. |
| 677 | pub fn addScalar(r: *Int, a: Int, scalar: var) Allocator.Error!void { | 474 | /// The upper bound for r limb count is a.limbs.len. |
| 678 | var limbs: [calcLimbLen(scalar)]Limb = undefined; | 475 | /// The upper bound for q limb count is given by `calcQuotientLimbLen`. This accounts |
| 679 | var operand = initFixed(&limbs); | 476 | /// for temporary space used by the division algorithm. |
| 680 | operand.set(scalar) catch unreachable; | 477 | /// |
| 681 | return add(r, a, operand); | 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; |
| 682 | } | 492 | } |
| 683 | | 493 | |
| 684 | /// r = a + b | 494 | /// r = a << shift, in other words, r = a * 2^shift |
| 685 | /// | 495 | /// |
| 686 | /// r, a and b may be aliases. | 496 | /// r and a may alias. |
| 687 | /// | 497 | /// |
| 688 | /// Returns an error if memory could not be allocated. | 498 | /// Asserts there is enough memory to fit the result. The upper bound Limb count is |
| 689 | pub fn add(r: *Int, a: Int, b: Int) Allocator.Error!void { | 499 | /// `a.limbs.len + (shift / (@sizeOf(Limb) * 8))`. |
| 690 | r.assertWritable(); | 500 | pub fn shiftLeft(r: *Mutable, a: Const, shift: usize) void { |
| 691 | if (a.eqZero()) { | 501 | llshl(r.limbs[0..], a.limbs[0..a.limbs.len], shift); |
| 692 | try r.copy(b); | 502 | r.normalize(a.limbs.len + (shift / Limb.bit_count) + 1); |
| 693 | return; | 503 | r.positive = a.positive; |
| 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 | } | | |
| 720 | } | 504 | } |
| 721 | | 505 | |
| 722 | // Knuth 4.3.1, Algorithm A. | 506 | /// r = a >> shift |
| 723 | fn lladd(r: []Limb, a: []const Limb, b: []const Limb) void { | 507 | /// r and a may alias. |
| 724 | @setRuntimeSafety(false); | 508 | /// |
| 725 | debug.assert(a.len != 0 and b.len != 0); | 509 | /// Asserts there is enough memory to fit the result. The upper bound Limb count is |
| 726 | debug.assert(a.len >= b.len); | 510 | /// `a.limbs.len - (shift / (@sizeOf(Limb) * 8))`. |
| 727 | debug.assert(r.len >= a.len + 1); | 511 | pub fn shiftRight(r: *Mutable, a: Const, shift: usize) void { |
| 728 | | 512 | if (a.limbs.len <= shift / Limb.bit_count) { |
| 729 | var i: usize = 0; | 513 | r.len = 1; |
| 730 | var carry: Limb = 0; | 514 | r.positive = true; |
| 731 | | 515 | r.limbs[0] = 0; |
| 732 | while (i < b.len) : (i += 1) { | 516 | return; |
| 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])); | | |
| 741 | } | 517 | } |
| 742 | | 518 | |
| 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; |
| 744 | } | 522 | } |
| 745 | | 523 | |
| 746 | /// r = a - b | 524 | /// r = a | b |
| | 525 | /// r may alias with a or b. |
| 747 | /// | 526 | /// |
| 748 | /// r, a and b may be aliases. | 527 | /// a and b are zero-extended to the longer of a or b. |
| 749 | /// | 528 | /// |
| 750 | /// Returns an error if memory could not be allocated. | 529 | /// Asserts that r has enough limbs to store the result. Upper bound is `math.max(a.limbs.len, b.limbs.len)`. |
| 751 | pub fn sub(r: *Int, a: Int, b: Int) !void { | 530 | pub fn bitOr(r: *Mutable, a: Const, b: Const) void { |
| 752 | r.assertWritable(); | 531 | if (a.limbs.len > b.limbs.len) { |
| 753 | if (a.isPositive() != b.isPositive()) { | 532 | llor(r.limbs[0..], a.limbs[0..a.limbs.len], b.limbs[0..b.limbs.len]); |
| 754 | if (a.isPositive()) { | 533 | r.len = a.limbs.len; |
| 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 | } | | |
| 762 | } else { | 534 | } else { |
| 763 | if (a.isPositive()) { | 535 | llor(r.limbs[0..], b.limbs[0..b.limbs.len], a.limbs[0..a.limbs.len]); |
| 764 | // (a) - (b) => a - b | 536 | r.len = b.limbs.len; |
| 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 | } | | |
| 790 | } | 537 | } |
| 791 | } | 538 | } |
| 792 | | 539 | |
| 793 | // Knuth 4.3.1, Algorithm S. | 540 | /// r = a & b |
| 794 | fn llsub(r: []Limb, a: []const Limb, b: []const Limb) void { | 541 | /// r may alias with a or b. |
| 795 | @setRuntimeSafety(false); | 542 | /// |
| 796 | debug.assert(a.len != 0 and b.len != 0); | 543 | /// Asserts that r has enough limbs to store the result. Upper bound is `math.min(a.limbs.len, b.limbs.len)`. |
| 797 | debug.assert(a.len > b.len or (a.len == b.len and a[a.len - 1] >= b[b.len - 1])); | 544 | pub fn bitAnd(r: *Mutable, a: Const, b: Const) void { |
| 798 | debug.assert(r.len >= a.len); | 545 | if (a.limbs.len > b.limbs.len) { |
| 799 | | 546 | lland(r.limbs[0..], a.limbs[0..a.limbs.len], b.limbs[0..b.limbs.len]); |
| 800 | var i: usize = 0; | 547 | r.normalize(b.limbs.len); |
| 801 | var borrow: Limb = 0; | 548 | } else { |
| 802 | | 549 | lland(r.limbs[0..], b.limbs[0..b.limbs.len], a.limbs[0..a.limbs.len]); |
| 803 | while (i < b.len) : (i += 1) { | 550 | r.normalize(a.limbs.len); |
| 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; | | |
| 808 | } | 551 | } |
| | 552 | } |
| 809 | | 553 | |
| 810 | while (i < a.len) : (i += 1) { | 554 | /// r = a ^ b |
| 811 | borrow = @boolToInt(@subWithOverflow(Limb, a[i], borrow, &r[i])); | 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); |
| 812 | } | 565 | } |
| 813 | | | |
| 814 | debug.assert(borrow == 0); | | |
| 815 | } | 566 | } |
| 816 | | 567 | |
| 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)`. |
| 818 | /// | 572 | /// |
| 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`. |
| 820 | /// | 595 | /// |
| 821 | /// Returns an error if memory could not be allocated. | 596 | /// `limbs_buffer` is used for temporary storage during the operation. |
| 822 | pub fn mul(rma: *Int, a: Int, b: Int) !void { | 597 | pub fn gcdNoAlias(rma: *Mutable, x: Const, y: Const, limbs_buffer: *std.ArrayList(Limb)) !void { |
| 823 | rma.assertWritable(); | 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(); |
| 824 | | 607 | |
| 825 | var r = rma; | 608 | var y = try ya.toManaged(limbs_buffer.allocator); |
| 826 | var aliased = rma.limbs.ptr == a.limbs.ptr or rma.limbs.ptr == b.limbs.ptr; | 609 | defer y.deinit(); |
| | 610 | y.abs(); |
| 827 | | 611 | |
| 828 | var sr: Int = undefined; | 612 | if (x.toConst().order(y.toConst()) == .lt) { |
| 829 | if (aliased) { | 613 | x.swap(&y); |
| 830 | sr = try Int.initCapacity(rma.allocator.?, a.len() + b.len()); | | |
| 831 | r = &sr; | | |
| 832 | aliased = true; | | |
| 833 | } | 614 | } |
| 834 | defer if (aliased) { | | |
| 835 | rma.swap(r); | | |
| 836 | r.deinit(); | | |
| 837 | }; | | |
| 838 | | 615 | |
| 839 | try r.ensureCapacity(a.len() + b.len() + 1); | 616 | var t_big = try Managed.init(limbs_buffer.allocator); |
| | 617 | defer t_big.deinit(); |
| 840 | | 618 | |
| 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(); |
| 842 | | 621 | |
| 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()); |
| 844 | | 625 | |
| 845 | r.normalize(a.len() + b.len()); | 626 | var xh: SignedDoubleLimb = x.limbs[x.len() - 1]; |
| 846 | r.setSign(a.isPositive() == b.isPositive()); | 627 | var yh: SignedDoubleLimb = if (x.len() > y.len()) 0 else y.limbs[x.len() - 1]; |
| 847 | } | 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 | } |
| 848 | | 640 | |
| 849 | // a + b * c + *carry, sets carry to the overflow bits | 641 | var t = A - q * C; |
| 850 | pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb { | 642 | A = C; |
| 851 | @setRuntimeSafety(false); | 643 | C = t; |
| 852 | var r1: Limb = undefined; | 644 | t = B - q * D; |
| | 645 | B = D; |
| | 646 | D = t; |
| 853 | | 647 | |
| 854 | // r1 = a + *carry | 648 | t = xh - q * yh; |
| 855 | const c1: Limb = @boolToInt(@addWithOverflow(Limb, a, carry.*, &r1)); | 649 | xh = yh; |
| | 650 | yh = t; |
| | 651 | } |
| 856 | | 652 | |
| 857 | // r2 = b * c | 653 | if (B == 0) { |
| 858 | const bc = @as(DoubleLimb, math.mulWide(Limb, b, c)); | 654 | // t_big = x % y, r is unused |
| 859 | const r2 = @truncate(Limb, bc); | 655 | try r.divTrunc(&t_big, x.toConst(), y.toConst()); |
| 860 | const c2 = @truncate(Limb, bc >> Limb.bit_count); | 656 | assert(t_big.isPositive()); |
| 861 | | 657 | |
| 862 | // r1 = r1 + r2 | 658 | x.swap(&y); |
| 863 | const c3: Limb = @boolToInt(@addWithOverflow(Limb, r1, r2, &r1)); | 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(); |
| 864 | | 666 | |
| 865 | // This never overflows, c1, c3 are either 0 or 1 and if both are 1 then | 667 | // t_big = Ax + By |
| 866 | // c2 is at least <= maxInt(Limb) - 2. | 668 | try r.mul(x.toConst(), Ap); |
| 867 | carry.* = c1 + c2 + c3; | 669 | try t_big.mul(y.toConst(), Bp); |
| | 670 | try t_big.add(r.toConst(), t_big.toConst()); |
| 868 | | 671 | |
| 869 | return r1; | 672 | // u = Cx + Dy, r as u |
| 870 | } | 673 | try x.mul(x.toConst(), Cp); |
| | 674 | try r.mul(y.toConst(), Dp); |
| | 675 | try r.add(x.toConst(), r.toConst()); |
| 871 | | 676 | |
| 872 | fn llmulDigit(acc: []Limb, y: []const Limb, xi: Limb) void { | 677 | x.swap(&t_big); |
| 873 | @setRuntimeSafety(false); | 678 | y.swap(&r); |
| 874 | if (xi == 0) { | 679 | } |
| 875 | return; | | |
| 876 | } | 680 | } |
| 877 | | 681 | |
| 878 | var carry: usize = 0; | 682 | // euclidean algorithm |
| 879 | var a_lo = acc[0..y.len]; | 683 | assert(x.toConst().order(y.toConst()) != .lt); |
| 880 | var a_hi = acc[y.len..]; | | |
| 881 | | 684 | |
| 882 | var j: usize = 0; | 685 | while (!y.toConst().eqZero()) { |
| 883 | while (j < a_lo.len) : (j += 1) { | 686 | try t_big.divTrunc(&r, x.toConst(), y.toConst()); |
| 884 | a_lo[j] = @call(.{ .modifier = .always_inline }, addMulLimbWithCarry, .{ a_lo[j], y[j], xi, &carry }); | 687 | x.swap(&y); |
| | 688 | y.swap(&r); |
| 885 | } | 689 | } |
| 886 | | 690 | |
| 887 | j = 0; | 691 | result.copy(x.toConst()); |
| 888 | while ((carry != 0) and (j < a_hi.len)) : (j += 1) { | | |
| 889 | carry = @boolToInt(@addWithOverflow(Limb, a_hi[j], carry, &a_hi[j])); | | |
| 890 | } | | |
| 891 | } | 692 | } |
| 892 | | 693 | |
| 893 | // Knuth 4.3.1, Algorithm M. | 694 | /// Truncates by default. |
| 894 | // | 695 | fn div(quo: *Mutable, rem: *Mutable, a: Const, b: Const, limbs_buffer: []Limb, allocator: ?*Allocator) void { |
| 895 | // r MUST NOT alias any of a or b. | 696 | assert(!b.eqZero()); // division by zero |
| 896 | fn llmulacc(allocator: *Allocator, r: []Limb, a: []const Limb, b: []const Limb) error{OutOfMemory}!void { | 697 | assert(quo != rem); // illegal aliasing |
| 897 | @setRuntimeSafety(false); | | |
| 898 | | 698 | |
| 899 | const a_norm = a[0..llnormalize(a)]; | 699 | if (a.orderAbs(b) == .lt) { |
| 900 | const b_norm = b[0..llnormalize(b)]; | 700 | // quo may alias a so handle rem first |
| 901 | var x = a_norm; | 701 | rem.copy(a); |
| 902 | var y = b_norm; | 702 | rem.positive = a.positive == b.positive; |
| 903 | if (a_norm.len > b_norm.len) { | | |
| 904 | x = b_norm; | | |
| 905 | y = a_norm; | | |
| 906 | } | | |
| 907 | | 703 | |
| 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 | } |
| 909 | | 709 | |
| 910 | // 48 is a pretty abitrary size chosen based on performance of a factorial program. | 710 | // Handle trailing zero-words of divisor/dividend. These are not handled in the following |
| 911 | if (x.len <= 48) { | 711 | // algorithms. |
| 912 | // Basecase multiplication | 712 | const a_zero_limb_count = blk: { |
| 913 | var i: usize = 0; | 713 | var i: usize = 0; |
| 914 | while (i < x.len) : (i += 1) { | 714 | while (i < a.limbs.len) : (i += 1) { |
| 915 | llmulDigit(r[i..], y, x[i]); | 715 | if (a.limbs[i] != 0) break; |
| 916 | } | 716 | } |
| 917 | } else { | 717 | break :blk i; |
| 918 | // Karatsuba multiplication | 718 | }; |
| 919 | const split = @divFloor(x.len, 2); | 719 | const b_zero_limb_count = blk: { |
| 920 | var x0 = x[0..split]; | 720 | var i: usize = 0; |
| 921 | var x1 = x[split..x.len]; | 721 | while (i < b.limbs.len) : (i += 1) { |
| 922 | var y0 = y[0..split]; | 722 | if (b.limbs[i] != 0) break; |
| 923 | var y1 = y[split..y.len]; | 723 | } |
| 924 | | 724 | break :blk i; |
| 925 | var tmp = try allocator.alloc(Limb, x1.len + y1.len + 1); | 725 | }; |
| 926 | defer allocator.free(tmp); | | |
| 927 | mem.set(Limb, tmp, 0); | | |
| 928 | | | |
| 929 | try llmulacc(allocator, tmp, x1, y1); | | |
| 930 | | 726 | |
| 931 | var length = llnormalize(tmp); | 727 | const ab_zero_limb_count = math.min(a_zero_limb_count, b_zero_limb_count); |
| 932 | _ = llaccum(r[split..], tmp[0..length]); | | |
| 933 | _ = llaccum(r[split * 2 ..], tmp[0..length]); | | |
| 934 | | 728 | |
| 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); |
| 936 | | 733 | |
| 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 | }; |
| 938 | | 754 | |
| 939 | length = llnormalize(tmp); | 755 | // Shrink x, y such that the trailing zero limbs shared between are removed. |
| 940 | _ = llaccum(r[0..], tmp[0..length]); | 756 | mem.copy(Limb, x.limbs, a.limbs[ab_zero_limb_count..a.limbs.len]); |
| 941 | _ = llaccum(r[split..], tmp[0..length]); | 757 | mem.copy(Limb, y.limbs, b.limbs[ab_zero_limb_count..b.limbs.len]); |
| 942 | | 758 | |
| 943 | const x_cmp = llcmp(x1, x0); | 759 | divN(quo, rem, &x, &y, t_limbs, mul_limbs_buf, allocator); |
| 944 | const y_cmp = llcmp(y1, y0); | 760 | quo.positive = (a.positive == b.positive); |
| 945 | if (x_cmp * y_cmp == 0) { | 761 | } |
| 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 | } | | |
| 957 | | 762 | |
| 958 | const y0_len = llnormalize(y0); | 763 | if (ab_zero_limb_count != 0) { |
| 959 | const y1_len = llnormalize(y1); | 764 | rem.shiftLeft(rem.toConst(), ab_zero_limb_count * Limb.bit_count); |
| 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 | } | | |
| 978 | } | 765 | } |
| 979 | } | 766 | } |
| 980 | | 767 | |
| 981 | // r = r + a | 768 | /// Handbook of Applied Cryptography, 14.20 |
| 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) | | |
| 1047 | /// | 769 | /// |
| 1048 | /// a / b are floored (rounded towards 0). | 770 | /// x = qy + r where 0 <= r < y |
| 1049 | pub fn divFloor(q: *Int, r: *Int, a: Int, b: Int) !void { | 771 | fn divN( |
| 1050 | try div(q, r, a, b); | 772 | q: *Mutable, |
| 1051 | | 773 | r: *Mutable, |
| 1052 | // Trunc -> Floor. | 774 | x: *Mutable, |
| 1053 | if (!q.isPositive()) { | 775 | y: *Mutable, |
| 1054 | const one = Int.initFixed(([_]Limb{1})[0..]); | 776 | tmp_limbs: []Limb, |
| 1055 | try q.sub(q.*, one); | 777 | mul_limb_buf: []Limb, |
| 1056 | try r.add(q.*, one); | 778 | allocator: ?*Allocator, |
| 1057 | } | 779 | ) void { |
| 1058 | r.setSign(b.isPositive()); | 780 | assert(y.len >= 2); |
| 1059 | } | 781 | assert(x.len >= y.len); |
| 1060 | | 782 | assert(q.limbs.len >= x.len + y.len - 1); |
| 1061 | /// q = a / b (rem r) | 783 | |
| 1062 | /// | 784 | // See 3.2 |
| 1063 | /// a / b are truncated (rounded towards -inf). | 785 | var backup_tmp_limbs: [3]Limb = undefined; |
| 1064 | pub fn divTrunc(q: *Int, r: *Int, a: Int, b: Int) !void { | 786 | const t_limbs = if (tmp_limbs.len < 3) &backup_tmp_limbs else tmp_limbs; |
| 1065 | try div(q, r, a, b); | 787 | |
| 1066 | r.setSign(a.isPositive()); | 788 | var tmp: Mutable = .{ |
| 1067 | } | 789 | .limbs = t_limbs, |
| 1068 | | 790 | .len = 1, |
| 1069 | // Truncates by default. | 791 | .positive = true, |
| 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; | | |
| 1106 | }; | 792 | }; |
| 1107 | | 793 | tmp.limbs[0] = 0; |
| 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(); | | |
| 1186 | | 794 | |
| 1187 | // Normalize so y > Limb.bit_count / 2 (i.e. leading bit is set) and even | 795 | // 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]); | 796 | var norm_shift = @clz(Limb, y.limbs[y.len - 1]); |
| 1189 | if (norm_shift == 0 and y.isOdd()) { | 797 | if (norm_shift == 0 and y.toConst().isOdd()) { |
| 1190 | norm_shift = Limb.bit_count; | 798 | norm_shift = Limb.bit_count; |
| 1191 | } | 799 | } |
| 1192 | try x.shiftLeft(x.*, norm_shift); | 800 | x.shiftLeft(x.toConst(), norm_shift); |
| 1193 | try y.shiftLeft(y.*, norm_shift); | 801 | y.shiftLeft(y.toConst(), norm_shift); |
| 1194 | | 802 | |
| 1195 | const n = x.len() - 1; | 803 | const n = x.len - 1; |
| 1196 | const t = y.len() - 1; | 804 | const t = y.len - 1; |
| 1197 | | 805 | |
| 1198 | // 1. | 806 | // 1. |
| 1199 | q.metadata = n - t + 1; | 807 | q.len = n - t + 1; |
| 1200 | mem.set(Limb, q.limbs[0..q.len()], 0); | 808 | q.positive = true; |
| | 809 | mem.set(Limb, q.limbs[0..q.len], 0); |
| 1201 | | 810 | |
| 1202 | // 2. | 811 | // 2. |
| 1203 | try tmp.shiftLeft(y.*, Limb.bit_count * (n - t)); | 812 | tmp.shiftLeft(y.toConst(), Limb.bit_count * (n - t)); |
| 1204 | while (x.cmp(tmp) != .lt) { | 813 | while (x.toConst().order(tmp.toConst()) != .lt) { |
| 1205 | q.limbs[n - t] += 1; | 814 | q.limbs[n - t] += 1; |
| 1206 | try x.sub(x.*, tmp); | 815 | x.sub(x.toConst(), tmp.toConst()); |
| 1207 | } | 816 | } |
| 1208 | | 817 | |
| 1209 | // 3. | 818 | // 3. |
| ... | @@ -1232,7 +841,7 @@ pub const Int = struct { | ... | @@ -1232,7 +841,7 @@ pub const Int = struct { |
| 1232 | r.limbs[2] = carry; | 841 | r.limbs[2] = carry; |
| 1233 | r.normalize(3); | 842 | r.normalize(3); |
| 1234 | | 843 | |
| 1235 | if (r.cmpAbs(tmp) != .gt) { | 844 | if (r.toConst().orderAbs(tmp.toConst()) != .gt) { |
| 1236 | break; | 845 | break; |
| 1237 | } | 846 | } |
| 1238 | | 847 | |
| ... | @@ -1240,1748 +849,1284 @@ pub const Int = struct { | ... | @@ -1240,1748 +849,1284 @@ pub const Int = struct { |
| 1240 | } | 849 | } |
| 1241 | | 850 | |
| 1242 | // 3.3 | 851 | // 3.3 |
| 1243 | try tmp.set(q.limbs[i - t - 1]); | 852 | tmp.set(q.limbs[i - t - 1]); |
| 1244 | try tmp.mul(tmp, y.*); | 853 | tmp.mul(tmp.toConst(), y.toConst(), mul_limb_buf, allocator); |
| 1245 | try tmp.shiftLeft(tmp, Limb.bit_count * (i - t - 1)); | 854 | tmp.shiftLeft(tmp.toConst(), Limb.bit_count * (i - t - 1)); |
| 1246 | try x.sub(x.*, tmp); | 855 | x.sub(x.toConst(), tmp.toConst()); |
| 1247 | | 856 | |
| 1248 | if (!x.isPositive()) { | 857 | if (!x.positive) { |
| 1249 | try tmp.shiftLeft(y.*, Limb.bit_count * (i - t - 1)); | 858 | tmp.shiftLeft(y.toConst(), Limb.bit_count * (i - t - 1)); |
| 1250 | try x.add(x.*, tmp); | 859 | x.add(x.toConst(), tmp.toConst()); |
| 1251 | q.limbs[i - t - 1] -= 1; | 860 | q.limbs[i - t - 1] -= 1; |
| 1252 | } | 861 | } |
| 1253 | } | 862 | } |
| 1254 | | 863 | |
| 1255 | // Denormalize | 864 | // Denormalize |
| 1256 | q.normalize(q.len()); | 865 | q.normalize(q.len); |
| 1257 | | 866 | |
| 1258 | try r.shiftRight(x.*, norm_shift); | 867 | r.shiftRight(x.toConst(), norm_shift); |
| 1259 | r.normalize(r.len()); | 868 | r.normalize(r.len); |
| 1260 | } | 869 | } |
| 1261 | | 870 | |
| 1262 | /// r = a << shift, in other words, r = a * 2^shift | 871 | /// Normalize a possible sequence of leading zeros. |
| 1263 | pub fn shiftLeft(r: *Int, a: Int, shift: usize) !void { | 872 | /// |
| 1264 | r.assertWritable(); | 873 | /// [1, 2, 3, 4, 0] -> [1, 2, 3, 4] |
| 1265 | | 874 | /// [1, 2, 0, 0, 0] -> [1, 2] |
| 1266 | try r.ensureCapacity(a.len() + (shift / Limb.bit_count) + 1); | 875 | /// [0, 0, 0, 0, 0] -> [0] |
| 1267 | llshl(r.limbs[0..], a.limbs[0..a.len()], shift); | 876 | fn normalize(r: *Mutable, length: usize) void { |
| 1268 | r.normalize(a.len() + (shift / Limb.bit_count) + 1); | 877 | r.len = llnormalize(r.limbs[0..length]); |
| 1269 | r.setSign(a.isPositive()); | | |
| 1270 | } | 878 | } |
| | 879 | }; |
| 1271 | | 880 | |
| 1272 | fn llshl(r: []Limb, a: []const Limb, shift: usize) void { | 881 | /// A arbitrary-precision big integer, with a fixed set of immutable limbs. |
| 1273 | @setRuntimeSafety(false); | 882 | pub const Const = struct { |
| 1274 | debug.assert(a.len >= 1); | 883 | /// Raw digits. These are: |
| 1275 | debug.assert(r.len >= a.len + (shift / Limb.bit_count) + 1); | 884 | /// |
| 1276 | | 885 | /// * Little-endian ordered |
| 1277 | const limb_shift = shift / Limb.bit_count + 1; | 886 | /// * limbs.len >= 1 |
| 1278 | const interior_limb_shift = @intCast(Log2Limb, shift % Limb.bit_count); | 887 | /// * Zero is represented as limbs.len == 1 with limbs[0] == 0. |
| 1279 | | 888 | /// |
| 1280 | var carry: Limb = 0; | 889 | /// Accessing limbs directly should be avoided. |
| 1281 | var i: usize = 0; | 890 | limbs: []const Limb, |
| 1282 | while (i < a.len) : (i += 1) { | 891 | positive: bool, |
| 1283 | const src_i = a.len - i - 1; | 892 | |
| 1284 | const dst_i = src_i + limb_shift; | 893 | /// The result is an independent resource which is managed by the caller. |
| 1285 | | 894 | pub fn toManaged(self: Const, allocator: *Allocator) Allocator.Error!Managed { |
| 1286 | const src_digit = a[src_i]; | 895 | const limbs = try allocator.alloc(Limb, math.max(Managed.default_capacity, self.limbs.len)); |
| 1287 | r[dst_i] = carry | @call(.{ .modifier = .always_inline }, math.shr, .{ | 896 | mem.copy(Limb, limbs, self.limbs); |
| 1288 | Limb, | 897 | return Managed{ |
| 1289 | src_digit, | 898 | .allocator = allocator, |
| 1290 | Limb.bit_count - @intCast(Limb, interior_limb_shift), | 899 | .limbs = limbs, |
| 1291 | }); | 900 | .metadata = if (self.positive) |
| 1292 | carry = (src_digit << interior_limb_shift); | 901 | self.limbs.len & ~Managed.sign_bit |
| 1293 | } | 902 | else |
| 1294 | | 903 | self.limbs.len | Managed.sign_bit, |
| 1295 | r[limb_shift - 1] = carry; | 904 | }; |
| 1296 | mem.set(Limb, r[0 .. limb_shift - 1], 0); | | |
| 1297 | } | 905 | } |
| 1298 | | 906 | |
| 1299 | /// r = a >> shift | 907 | /// Asserts `limbs` is big enough to store the value. |
| 1300 | pub fn shiftRight(r: *Int, a: Int, shift: usize) !void { | 908 | pub fn toMutable(self: Const, limbs: []Limb) Mutable { |
| 1301 | r.assertWritable(); | 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 | } |
| 1302 | | 916 | |
| 1303 | if (a.len() <= shift / Limb.bit_count) { | 917 | pub fn dump(self: Const) void { |
| 1304 | r.metadata = 1; | 918 | for (self.limbs[0..self.limbs.len]) |limb| { |
| 1305 | r.limbs[0] = 0; | 919 | std.debug.warn("{x} ", .{limb}); |
| 1306 | return; | | |
| 1307 | } | 920 | } |
| | 921 | std.debug.warn("positive={}\n", .{self.positive}); |
| | 922 | } |
| 1308 | | 923 | |
| 1309 | try r.ensureCapacity(a.len() - (shift / Limb.bit_count)); | 924 | pub fn abs(self: Const) Const { |
| 1310 | const r_len = llshr(r.limbs[0..], a.limbs[0..a.len()], shift); | 925 | return .{ |
| 1311 | r.metadata = a.len() - (shift / Limb.bit_count); | 926 | .limbs = self.limbs, |
| 1312 | r.setSign(a.isPositive()); | 927 | .positive = true, |
| | 928 | }; |
| 1313 | } | 929 | } |
| 1314 | | 930 | |
| 1315 | fn llshr(r: []Limb, a: []const Limb, shift: usize) void { | 931 | pub fn isOdd(self: Const) bool { |
| 1316 | @setRuntimeSafety(false); | 932 | return self.limbs[0] & 1 != 0; |
| 1317 | debug.assert(a.len >= 1); | 933 | } |
| 1318 | debug.assert(r.len >= a.len - (shift / Limb.bit_count)); | | |
| 1319 | | 934 | |
| 1320 | const limb_shift = shift / Limb.bit_count; | 935 | pub fn isEven(self: Const) bool { |
| 1321 | const interior_limb_shift = @intCast(Log2Limb, shift % Limb.bit_count); | 936 | return !self.isOdd(); |
| | 937 | } |
| 1322 | | 938 | |
| 1323 | var carry: Limb = 0; | 939 | /// Returns the number of bits required to represent the absolute value of an integer. |
| 1324 | var i: usize = 0; | 940 | pub fn bitCountAbs(self: Const) usize { |
| 1325 | while (i < a.len - limb_shift) : (i += 1) { | 941 | return (self.limbs.len - 1) * Limb.bit_count + (Limb.bit_count - @clz(Limb, self.limbs[self.limbs.len - 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 | } | | |
| 1337 | } | 942 | } |
| 1338 | | 943 | |
| 1339 | /// r = a | b | 944 | /// Returns the number of bits required to represent the integer in twos-complement form. |
| 1340 | /// | 945 | /// |
| 1341 | /// a and b are zero-extended to the longer of a or b. | 946 | /// If the integer is negative the value returned is the number of bits needed by a signed |
| 1342 | pub fn bitOr(r: *Int, a: Int, b: Int) !void { | 947 | /// integer to represent the value. If positive the value is the number of bits for an |
| 1343 | r.assertWritable(); | 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(); |
| 1344 | | 954 | |
| 1345 | if (a.len() > b.len()) { | 955 | // If the entire value has only one bit set (e.g. 0b100000000) then the negation in twos |
| 1346 | try r.ensureCapacity(a.len()); | 956 | // complement requires one less bit. |
| 1347 | llor(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]); | 957 | if (!self.positive) block: { |
| 1348 | r.setLen(a.len()); | 958 | bits += 1; |
| 1349 | } else { | 959 | |
| 1350 | try r.ensureCapacity(b.len()); | 960 | if (@popCount(Limb, self.limbs[self.limbs.len - 1]) == 1) { |
| 1351 | llor(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]); | 961 | for (self.limbs[0 .. self.limbs.len - 1]) |limb| { |
| 1352 | r.setLen(b.len()); | 962 | if (@popCount(Limb, limb) != 0) { |
| | 963 | break :block; |
| | 964 | } |
| | 965 | } |
| | 966 | |
| | 967 | bits -= 1; |
| | 968 | } |
| 1353 | } | 969 | } |
| 1354 | } | | |
| 1355 | | 970 | |
| 1356 | fn llor(r: []Limb, a: []const Limb, b: []const Limb) void { | 971 | return bits; |
| 1357 | @setRuntimeSafety(false); | 972 | } |
| 1358 | debug.assert(r.len >= a.len); | | |
| 1359 | debug.assert(a.len >= b.len); | | |
| 1360 | | 973 | |
| 1361 | var i: usize = 0; | 974 | pub fn fitsInTwosComp(self: Const, is_signed: bool, bit_count: usize) bool { |
| 1362 | while (i < b.len) : (i += 1) { | 975 | if (self.eqZero()) { |
| 1363 | r[i] = a[i] | b[i]; | 976 | return true; |
| 1364 | } | 977 | } |
| 1365 | while (i < a.len) : (i += 1) { | 978 | if (!is_signed and !self.positive) { |
| 1366 | r[i] = a[i]; | 979 | return false; |
| 1367 | } | 980 | } |
| | 981 | |
| | 982 | const req_bits = self.bitCountTwosComp() + @boolToInt(self.positive and is_signed); |
| | 983 | return bit_count >= req_bits; |
| 1368 | } | 984 | } |
| 1369 | | 985 | |
| 1370 | /// r = a & b | 986 | /// Returns whether self can fit into an integer of the requested type. |
| 1371 | pub fn bitAnd(r: *Int, a: Int, b: Int) !void { | 987 | pub fn fits(self: Const, comptime T: type) bool { |
| 1372 | r.assertWritable(); | 988 | const info = @typeInfo(T).Int; |
| | 989 | return self.fitsInTwosComp(info.is_signed, info.bits); |
| | 990 | } |
| 1373 | | 991 | |
| 1374 | if (a.len() > b.len()) { | 992 | /// Returns the approximate size of the integer in the given base. Negative values accommodate for |
| 1375 | try r.ensureCapacity(b.len()); | 993 | /// the minus sign. This is used for determining the number of characters needed to print the |
| 1376 | lland(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]); | 994 | /// value. It is inexact and may exceed the given value by ~1-2 bytes. |
| 1377 | r.normalize(b.len()); | 995 | /// TODO See if we can make this exact. |
| 1378 | } else { | 996 | pub fn sizeInBaseUpperBound(self: Const, base: usize) usize { |
| 1379 | try r.ensureCapacity(a.len()); | 997 | const bit_count = @as(usize, @boolToInt(!self.positive)) + self.bitCountAbs(); |
| 1380 | lland(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]); | 998 | return (bit_count / math.log2(base)) + 1; |
| 1381 | r.normalize(a.len()); | | |
| 1382 | } | | |
| 1383 | } | 999 | } |
| 1384 | | 1000 | |
| 1385 | fn lland(r: []Limb, a: []const Limb, b: []const Limb) void { | 1001 | pub const ConvertError = error{ |
| 1386 | @setRuntimeSafety(false); | 1002 | NegativeIntoUnsigned, |
| 1387 | debug.assert(r.len >= b.len); | 1003 | TargetTooSmall, |
| 1388 | debug.assert(a.len >= b.len); | 1004 | }; |
| 1389 | | 1005 | |
| 1390 | var i: usize = 0; | 1006 | /// Convert self to type T. |
| 1391 | while (i < b.len) : (i += 1) { | 1007 | /// |
| 1392 | r[i] = a[i] & b[i]; | 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)), |
| 1393 | } | 1045 | } |
| 1394 | } | 1046 | } |
| 1395 | | 1047 | |
| 1396 | /// r = a ^ b | 1048 | /// To allow `std.fmt.format` to work with this type. |
| 1397 | pub fn bitXor(r: *Int, a: Int, b: Int) !void { | 1049 | /// If the integer is larger than `pow(2, 64 * @sizeOf(usize) * 8), this function will fail |
| 1398 | r.assertWritable(); | 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; |
| 1399 | | 1061 | |
| 1400 | if (a.len() > b.len()) { | 1062 | if (fmt.len == 0 or comptime mem.eql(u8, fmt, "d")) { |
| 1401 | try r.ensureCapacity(a.len()); | 1063 | radix = 10; |
| 1402 | llxor(r.limbs[0..], a.limbs[0..a.len()], b.limbs[0..b.len()]); | 1064 | uppercase = false; |
| 1403 | r.normalize(a.len()); | 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; |
| 1404 | } else { | 1074 | } else { |
| 1405 | try r.ensureCapacity(b.len()); | 1075 | @compileError("Unknown format string: '" ++ fmt ++ "'"); |
| 1406 | llxor(r.limbs[0..], b.limbs[0..b.len()], a.limbs[0..a.len()]); | | |
| 1407 | r.normalize(b.len()); | | |
| 1408 | } | 1076 | } |
| 1409 | } | | |
| 1410 | | 1077 | |
| 1411 | fn llxor(r: []Limb, a: []const Limb, b: []const Limb) void { | 1078 | var limbs: [128]Limb = undefined; |
| 1412 | @setRuntimeSafety(false); | 1079 | const needed_limbs = calcDivLimbsBufferLen(self.limbs.len, 1); |
| 1413 | debug.assert(r.len >= a.len); | 1080 | if (needed_limbs > limbs.len) |
| 1414 | debug.assert(a.len >= b.len); | 1081 | return out_stream.writeAll("(BigInt)"); |
| 1415 | | 1082 | |
| 1416 | var i: usize = 0; | 1083 | // This is the inverse of calcDivLimbsBufferLen |
| 1417 | while (i < b.len) : (i += 1) { | 1084 | const available_len = (limbs.len / 3) - 2; |
| 1418 | r[i] = a[i] ^ b[i]; | 1085 | |
| 1419 | } | 1086 | const biggest: Const = .{ |
| 1420 | while (i < a.len) : (i += 1) { | 1087 | .limbs = &([1]Limb{math.maxInt(Limb)} ** available_len), |
| 1421 | r[i] = a[i]; | 1088 | .positive = false, |
| 1422 | } | 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]); |
| 1423 | } | 1093 | } |
| 1424 | | 1094 | |
| 1425 | pub fn gcd(rma: *Int, x: Int, y: Int) !void { | 1095 | /// Converts self to a string in the requested base. |
| 1426 | rma.assertWritable(); | 1096 | /// Caller owns returned memory. |
| 1427 | var r = rma; | 1097 | /// Asserts that `base` is in the range [2, 16]. |
| 1428 | var aliased = rma.limbs.ptr == x.limbs.ptr or rma.limbs.ptr == y.limbs.ptr; | 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); |
| 1429 | | 1102 | |
| 1430 | var sr: Int = undefined; | 1103 | if (self.eqZero()) { |
| 1431 | if (aliased) { | 1104 | return mem.dupe(allocator, u8, "0"); |
| 1432 | sr = try Int.initCapacity(rma.allocator.?, math.max(x.len(), y.len())); | | |
| 1433 | r = &sr; | | |
| 1434 | aliased = true; | | |
| 1435 | } | 1105 | } |
| 1436 | defer if (aliased) { | 1106 | const string = try allocator.alloc(u8, self.sizeInBaseUpperBound(base)); |
| 1437 | rma.swap(r); | 1107 | errdefer allocator.free(string); |
| 1438 | r.deinit(); | | |
| 1439 | }; | | |
| 1440 | | 1108 | |
| 1441 | try gcdLehmer(r, x, y); | 1109 | const limbs = try allocator.alloc(Limb, calcToStringLimbsBufferLen(self.limbs.len, base)); |
| 1442 | } | 1110 | defer allocator.free(limbs); |
| 1443 | | 1111 | |
| 1444 | fn gcdLehmer(r: *Int, xa: Int, ya: Int) !void { | 1112 | return allocator.shrink(string, self.toString(string, base, uppercase, limbs)); |
| 1445 | var x = try xa.clone(); | 1113 | } |
| 1446 | x.abs(); | | |
| 1447 | defer x.deinit(); | | |
| 1448 | | 1114 | |
| 1449 | var y = try ya.clone(); | 1115 | /// Converts self to a string in the requested base. |
| 1450 | y.abs(); | 1116 | /// Asserts that `base` is in the range [2, 16]. |
| 1451 | defer y.deinit(); | 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); |
| 1452 | | 1127 | |
| 1453 | if (x.cmp(y) == .lt) { | 1128 | if (self.eqZero()) { |
| 1454 | x.swap(&y); | 1129 | string[0] = '0'; |
| | 1130 | return 1; |
| 1455 | } | 1131 | } |
| 1456 | | 1132 | |
| 1457 | var T = try Int.init(r.allocator.?); | 1133 | var digits_len: usize = 0; |
| 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()); | | |
| 1463 | | 1134 | |
| 1464 | var xh: SignedDoubleLimb = x.limbs[x.len() - 1]; | 1135 | // Power of two: can do a single pass and use masks to extract digits. |
| 1465 | var yh: SignedDoubleLimb = if (x.len() > y.len()) 0 else y.limbs[x.len() - 1]; | 1136 | if (math.isPowerOfTwo(base)) { |
| | 1137 | const base_shift = math.log2_int(Limb, base); |
| 1466 | | 1138 | |
| 1467 | var A: SignedDoubleLimb = 1; | 1139 | outer: for (self.limbs[0..self.limbs.len]) |limb| { |
| 1468 | var B: SignedDoubleLimb = 0; | 1140 | var shift: usize = 0; |
| 1469 | var C: SignedDoubleLimb = 0; | 1141 | while (shift < Limb.bit_count) : (shift += base_shift) { |
| 1470 | var D: SignedDoubleLimb = 1; | 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 | } |
| 1471 | | 1150 | |
| 1472 | while (yh + C != 0 and yh + D != 0) { | 1151 | // Always will have a non-zero digit somewhere. |
| 1473 | const q = @divFloor(xh + A, yh + C); | 1152 | while (string[digits_len - 1] == '0') { |
| 1474 | const qp = @divFloor(xh + B, yh + D); | 1153 | digits_len -= 1; |
| 1475 | if (q != qp) { | 1154 | } |
| 1476 | break; | 1155 | } else { |
| 1477 | } | 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 }; |
| 1478 | | 1164 | |
| 1479 | var t = A - q * C; | 1165 | var q: Mutable = .{ |
| 1480 | A = C; | 1166 | .limbs = limbs_buffer[0 .. self.limbs.len + 2], |
| 1481 | C = t; | 1167 | .positive = true, // Make absolute by ignoring self.positive. |
| 1482 | t = B - q * D; | 1168 | .len = self.limbs.len, |
| 1483 | B = D; | 1169 | }; |
| 1484 | D = t; | 1170 | mem.copy(Limb, q.limbs, self.limbs); |
| 1485 | | 1171 | |
| 1486 | t = xh - q * yh; | 1172 | var r: Mutable = .{ |
| 1487 | xh = yh; | 1173 | .limbs = limbs_buffer[q.limbs.len..][0..self.limbs.len], |
| 1488 | yh = t; | 1174 | .positive = true, |
| 1489 | } | 1175 | .len = 1, |
| | 1176 | }; |
| | 1177 | r.limbs[0] = 0; |
| 1490 | | 1178 | |
| 1491 | if (B == 0) { | 1179 | const rest_of_the_limbs_buf = limbs_buffer[q.limbs.len + r.limbs.len ..]; |
| 1492 | // T = x % y, r is unused | | |
| 1493 | try Int.divTrunc(r, &T, x, y); | | |
| 1494 | debug.assert(T.isPositive()); | | |
| 1495 | | 1180 | |
| 1496 | x.swap(&y); | 1181 | while (q.len >= 2) { |
| 1497 | y.swap(&T); | 1182 | // Passing an allocator here would not be helpful since this division is destroying |
| 1498 | } else { | 1183 | // information, not creating it. [TODO citation needed] |
| 1499 | var storage: [8]Limb = undefined; | 1184 | q.divTrunc(&r, q.toConst(), b, rest_of_the_limbs_buf, null); |
| 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]); | | |
| 1504 | | 1185 | |
| 1505 | // T = Ax + By | 1186 | var r_word = r.limbs[0]; |
| 1506 | try r.mul(x, Ap); | 1187 | var i: usize = 0; |
| 1507 | try T.mul(y, Bp); | 1188 | while (i < digits_per_limb) : (i += 1) { |
| 1508 | try T.add(r.*, T); | 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 | } |
| 1509 | | 1195 | |
| 1510 | // u = Cx + Dy, r as u | 1196 | { |
| 1511 | try x.mul(x, Cp); | 1197 | assert(q.len == 1); |
| 1512 | try r.mul(y, Dp); | | |
| 1513 | try r.add(x, r.*); | | |
| 1514 | | 1198 | |
| 1515 | x.swap(&T); | 1199 | var r_word = q.limbs[0]; |
| 1516 | y.swap(r); | 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 | } |
| 1517 | } | 1206 | } |
| 1518 | } | 1207 | } |
| 1519 | | 1208 | |
| 1520 | // euclidean algorithm | 1209 | if (!self.positive) { |
| 1521 | debug.assert(x.cmp(y) != .lt); | 1210 | string[digits_len] = '-'; |
| 1522 | | 1211 | digits_len += 1; |
| 1523 | while (!y.eqZero()) { | | |
| 1524 | try Int.divTrunc(&T, r, x, y); | | |
| 1525 | x.swap(&y); | | |
| 1526 | y.swap(r); | | |
| 1527 | } | 1212 | } |
| 1528 | | 1213 | |
| 1529 | r.swap(&x); | 1214 | const s = string[0..digits_len]; |
| | 1215 | mem.reverse(u8, s); |
| | 1216 | return s.len; |
| 1530 | } | 1217 | } |
| 1531 | }; | | |
| 1532 | | 1218 | |
| 1533 | // Storage must live for the lifetime of the returned value | 1219 | /// Returns `math.Order.lt`, `math.Order.eq`, `math.Order.gt` if |
| 1534 | fn FixedIntFromSignedDoubleLimb(A: SignedDoubleLimb, storage: []Limb) Int { | 1220 | /// `|a| < |b|`, `|a| == |b|`, or `|a| > |b|` respectively. |
| 1535 | std.debug.assert(storage.len >= 2); | 1221 | pub fn orderAbs(a: Const, b: Const) math.Order { |
| 1536 | | 1222 | if (a.limbs.len < b.limbs.len) { |
| 1537 | var A_is_positive = A >= 0; | 1223 | return .lt; |
| 1538 | const Au = @intCast(DoubleLimb, if (A < 0) -A else A); | 1224 | } |
| 1539 | storage[0] = @truncate(Limb, Au); | 1225 | if (a.limbs.len > b.limbs.len) { |
| 1540 | storage[1] = @truncate(Limb, Au >> Limb.bit_count); | 1226 | return .gt; |
| 1541 | var Ap = Int.initFixed(storage[0..2]); | 1227 | } |
| 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 | | | |
| 1551 | test "big.int comptime_int set" { | | |
| 1552 | comptime var s = 0xefffffff00000001eeeeeeefaaaaaaab; | | |
| 1553 | var a = try Int.initSet(testing.allocator, s); | | |
| 1554 | defer a.deinit(); | | |
| 1555 | | 1228 | |
| 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 | } |
| 1557 | | 1235 | |
| 1558 | comptime var i: usize = 0; | 1236 | if (a.limbs[i] < b.limbs[i]) { |
| 1559 | inline while (i < s_limb_count) : (i += 1) { | 1237 | return .lt; |
| 1560 | const result = @as(Limb, s & maxInt(Limb)); | 1238 | } else if (a.limbs[i] > b.limbs[i]) { |
| 1561 | s >>= Limb.bit_count / 2; | 1239 | return .gt; |
| 1562 | s >>= Limb.bit_count / 2; | 1240 | } else { |
| 1563 | testing.expect(a.limbs[i] == result); | 1241 | return .eq; |
| | 1242 | } |
| 1564 | } | 1243 | } |
| 1565 | } | | |
| 1566 | | | |
| 1567 | test "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 | | | |
| 1575 | test "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 | | | |
| 1583 | test "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 | | | |
| 1590 | test "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 | | | |
| 1597 | test "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 | | | |
| 1604 | test "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 | | | |
| 1632 | test "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 | | | |
| 1662 | test "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 | | | |
| 1675 | test "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 | | | |
| 1703 | test "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 | | | |
| 1734 | test "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 | | | |
| 1762 | test "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 | | | |
| 1770 | test "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 | | | |
| 1778 | test "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 | | | |
| 1786 | test "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 | | | |
| 1794 | test "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 | | | |
| 1800 | test "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 | | | |
| 1806 | test "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 | | | |
| 1817 | test "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 | | | |
| 1824 | test "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 | | | |
| 1835 | test "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 | | | |
| 1846 | test "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 | | | |
| 1857 | test "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 | | | |
| 1868 | test "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 | | | |
| 1882 | test "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 | | | |
| 1897 | test "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 | | | |
| 1904 | test "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(); | | |
| 1909 | | 1244 | |
| 1910 | testing.expect(a.cmpAbs(b) == .gt); | 1245 | /// Returns `math.Order.lt`, `math.Order.eq`, `math.Order.gt` if `a < b`, `a == b` or `a > b` respectively. |
| 1911 | testing.expect(a.cmp(b) == .lt); | 1246 | pub fn order(a: Const, b: Const) math.Order { |
| 1912 | } | 1247 | if (a.positive != b.positive) { |
| 1913 | | 1248 | return if (a.positive) .gt else .lt; |
| 1914 | test "big.int compare similar" { | 1249 | } else { |
| 1915 | var a = try Int.initSet(testing.allocator, 0xffffffffeeeeeeeeffffffffeeeeeeee); | 1250 | const r = orderAbs(a, b); |
| 1916 | defer a.deinit(); | 1251 | return if (a.positive) r else switch (r) { |
| 1917 | var b = try Int.initSet(testing.allocator, 0xffffffffeeeeeeeeffffffffeeeeeeef); | 1252 | .lt => math.Order.gt, |
| 1918 | defer b.deinit(); | 1253 | .eq => math.Order.eq, |
| 1919 | | 1254 | .gt => math.Order.lt, |
| 1920 | testing.expect(a.cmpAbs(b) == .lt); | 1255 | }; |
| 1921 | testing.expect(b.cmpAbs(a) == .gt); | 1256 | } |
| 1922 | } | 1257 | } |
| 1923 | | | |
| 1924 | test "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 | | | |
| 1934 | test "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 | | | |
| 1944 | test "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 | | | |
| 1954 | test "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 | | | |
| 1965 | test "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 | | | |
| 1976 | test "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 | | | |
| 1989 | test "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 | | | |
| 2005 | test "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 | | | |
| 2020 | test "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 | | | |
| 2033 | test "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 | | | |
| 2045 | test "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 | | | |
| 2071 | test "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 | | | |
| 2084 | test "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 | | | |
| 2097 | test "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 | | | |
| 2113 | test "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 | | | |
| 2126 | test "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 | | | |
| 2155 | test "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 | | | |
| 2168 | test "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 | | | |
| 2181 | test "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 | | | |
| 2196 | test "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 | | | |
| 2207 | test "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 | | | |
| 2218 | test "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 | | | |
| 2227 | test "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 | | | |
| 2240 | test "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 | | | |
| 2253 | test "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 | | | |
| 2269 | test "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 | | | |
| 2285 | test "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 | | | |
| 2304 | test "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 | | | |
| 2323 | test "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(); | | |
| 2331 | | 1258 | |
| 2332 | var q = try Int.init(testing.allocator); | 1259 | /// Same as `order` but the right-hand operand is a primitive integer. |
| 2333 | defer q.deinit(); | 1260 | pub fn orderAgainstScalar(lhs: Const, scalar: var) math.Order { |
| 2334 | var r = try Int.init(testing.allocator); | 1261 | var limbs: [calcLimbLen(scalar)]Limb = undefined; |
| 2335 | defer r.deinit(); | 1262 | const rhs = Mutable.init(&limbs, scalar); |
| 2336 | try Int.divTrunc(&q, &r, a, b); | 1263 | return order(lhs, rhs.toConst()); |
| | 1264 | } |
| 2337 | | 1265 | |
| 2338 | testing.expect((try q.to(u128)) == op1 / op2); | 1266 | /// Returns true if `a == 0`. |
| 2339 | testing.expect((try r.to(u32)) == 0x3e4e); | 1267 | pub fn eqZero(a: Const) bool { |
| 2340 | } | 1268 | return a.limbs.len == 1 and a.limbs[0] == 0; |
| | 1269 | } |
| 2341 | | 1270 | |
| 2342 | test "big.int div single-single q < r" { | 1271 | /// Returns true if `|a| == |b|`. |
| 2343 | var a = try Int.initSet(testing.allocator, 0x0078f432); | 1272 | pub fn eqAbs(a: Const, b: Const) bool { |
| 2344 | defer a.deinit(); | 1273 | return orderAbs(a, b) == .eq; |
| 2345 | var b = try Int.initSet(testing.allocator, 0x01000000); | 1274 | } |
| 2346 | defer b.deinit(); | | |
| 2347 | | 1275 | |
| 2348 | var q = try Int.init(testing.allocator); | 1276 | /// Returns true if `a == b`. |
| 2349 | defer q.deinit(); | 1277 | pub fn eq(a: Const, b: Const) bool { |
| 2350 | var r = try Int.init(testing.allocator); | 1278 | return order(a, b) == .eq; |
| 2351 | defer r.deinit(); | 1279 | } |
| 2352 | try Int.divTrunc(&q, &r, a, b); | 1280 | }; |
| 2353 | | 1281 | |
| 2354 | testing.expect((try q.to(u64)) == 0); | 1282 | /// An arbitrary-precision big integer along with an allocator which manages the memory. |
| 2355 | testing.expect((try r.to(u64)) == 0x0078f432); | 1283 | /// |
| 2356 | } | 1284 | /// Memory is allocated as needed to ensure operations never overflow. The range |
| | 1285 | /// is bounded only by available memory. |
| | 1286 | pub const Managed = struct { |
| | 1287 | pub const sign_bit: usize = 1 << (usize.bit_count - 1); |
| 2357 | | 1288 | |
| 2358 | test "big.int div single-single q == r" { | 1289 | /// Default number of limbs to allocate on creation of a `Managed`. |
| 2359 | var a = try Int.initSet(testing.allocator, 10); | 1290 | pub const default_capacity = 4; |
| 2360 | defer a.deinit(); | | |
| 2361 | var b = try Int.initSet(testing.allocator, 10); | | |
| 2362 | defer b.deinit(); | | |
| 2363 | | 1291 | |
| 2364 | var q = try Int.init(testing.allocator); | 1292 | /// Allocator used by the Managed when requesting memory. |
| 2365 | defer q.deinit(); | 1293 | allocator: *Allocator, |
| 2366 | var r = try Int.init(testing.allocator); | | |
| 2367 | defer r.deinit(); | | |
| 2368 | try Int.divTrunc(&q, &r, a, b); | | |
| 2369 | | 1294 | |
| 2370 | testing.expect((try q.to(u64)) == 1); | 1295 | /// Raw digits. These are: |
| 2371 | testing.expect((try r.to(u64)) == 0); | 1296 | /// |
| 2372 | } | 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, |
| 2373 | | 1303 | |
| 2374 | test "big.int div q=0 alias" { | 1304 | /// High bit is the sign bit. If set, Managed is negative, else Managed is positive. |
| 2375 | var a = try Int.initSet(testing.allocator, 3); | 1305 | /// The remaining bits represent the number of limbs used by Managed. |
| 2376 | defer a.deinit(); | 1306 | metadata: usize, |
| 2377 | var b = try Int.initSet(testing.allocator, 10); | | |
| 2378 | defer b.deinit(); | | |
| 2379 | | 1307 | |
| 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 | } |
| 2381 | | 1313 | |
| 2382 | testing.expect((try a.to(u64)) == 0); | 1314 | pub fn toMutable(self: Managed) Mutable { |
| 2383 | testing.expect((try b.to(u64)) == 3); | 1315 | return .{ |
| 2384 | } | 1316 | .limbs = self.limbs, |
| | 1317 | .positive = self.isPositive(), |
| | 1318 | .len = self.len(), |
| | 1319 | }; |
| | 1320 | } |
| 2385 | | 1321 | |
| 2386 | test "big.int div multi-multi q < r" { | 1322 | pub fn toConst(self: Managed) Const { |
| 2387 | const op1 = 0x1ffffffff0078f432; | 1323 | return .{ |
| 2388 | const op2 = 0x1ffffffff01000000; | 1324 | .limbs = self.limbs[0..self.len()], |
| 2389 | var a = try Int.initSet(testing.allocator, op1); | 1325 | .positive = self.isPositive(), |
| 2390 | defer a.deinit(); | 1326 | }; |
| 2391 | var b = try Int.initSet(testing.allocator, op2); | 1327 | } |
| 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 | } | | |
| 2403 | | 1328 | |
| 2404 | test "big.int div trunc single-single +/+" { | 1329 | /// Creates a new `Managed` with value `value`. |
| 2405 | const u: i32 = 5; | 1330 | /// |
| 2406 | const v: i32 = 3; | 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 | } |
| 2407 | | 1337 | |
| 2408 | var a = try Int.initSet(testing.allocator, u); | 1338 | /// Creates a new Managed with a specific capacity. If capacity < default_capacity then the |
| 2409 | defer a.deinit(); | 1339 | /// default capacity will be used instead. |
| 2410 | var b = try Int.initSet(testing.allocator, v); | 1340 | /// The integer value after initializing is `0`. |
| 2411 | defer b.deinit(); | 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 | } |
| 2412 | | 1352 | |
| 2413 | var q = try Int.init(testing.allocator); | 1353 | /// Returns the number of limbs currently in use. |
| 2414 | defer q.deinit(); | 1354 | pub fn len(self: Managed) usize { |
| 2415 | var r = try Int.init(testing.allocator); | 1355 | return self.metadata & ~sign_bit; |
| 2416 | defer r.deinit(); | 1356 | } |
| 2417 | try Int.divTrunc(&q, &r, a, b); | | |
| 2418 | | 1357 | |
| 2419 | // n = q * d + r | 1358 | /// Returns whether an Managed is positive. |
| 2420 | // 5 = 1 * 3 + 2 | 1359 | pub fn isPositive(self: Managed) bool { |
| 2421 | const eq = @divTrunc(u, v); | 1360 | return self.metadata & sign_bit == 0; |
| 2422 | const er = @mod(u, v); | 1361 | } |
| 2423 | | 1362 | |
| 2424 | testing.expect((try q.to(i32)) == eq); | 1363 | /// Sets the sign of an Managed. |
| 2425 | testing.expect((try r.to(i32)) == er); | 1364 | pub fn setSign(self: *Managed, positive: bool) void { |
| 2426 | } | 1365 | if (positive) { |
| | 1366 | self.metadata &= ~sign_bit; |
| | 1367 | } else { |
| | 1368 | self.metadata |= sign_bit; |
| | 1369 | } |
| | 1370 | } |
| 2427 | | 1371 | |
| 2428 | test "big.int div trunc single-single -/+" { | 1372 | /// Sets the length of an Managed. |
| 2429 | const u: i32 = -5; | 1373 | /// |
| 2430 | const v: i32 = 3; | 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 | } |
| 2431 | | 1379 | |
| 2432 | var a = try Int.initSet(testing.allocator, u); | 1380 | pub fn setMetadata(self: *Managed, positive: bool, length: usize) void { |
| 2433 | defer a.deinit(); | 1381 | self.metadata = if (positive) length & ~sign_bit else length | sign_bit; |
| 2434 | var b = try Int.initSet(testing.allocator, v); | 1382 | } |
| 2435 | defer b.deinit(); | | |
| 2436 | | 1383 | |
| 2437 | var q = try Int.init(testing.allocator); | 1384 | /// Ensures an Managed has enough space allocated for capacity limbs. If the Managed does not have |
| 2438 | defer q.deinit(); | 1385 | /// sufficient capacity, the exact amount will be allocated. This occurs even if the requested |
| 2439 | var r = try Int.init(testing.allocator); | 1386 | /// capacity is only greater than the current capacity by one limb. |
| 2440 | defer r.deinit(); | 1387 | pub fn ensureCapacity(self: *Managed, capacity: usize) !void { |
| 2441 | try Int.divTrunc(&q, &r, a, b); | 1388 | if (capacity <= self.limbs.len) { |
| | 1389 | return; |
| | 1390 | } |
| | 1391 | self.limbs = try self.allocator.realloc(self.limbs, capacity); |
| | 1392 | } |
| 2442 | | 1393 | |
| 2443 | // n = q * d + r | 1394 | /// Frees all associated memory. |
| 2444 | // -5 = 1 * -3 - 2 | 1395 | pub fn deinit(self: *Managed) void { |
| 2445 | const eq = -1; | 1396 | self.allocator.free(self.limbs); |
| 2446 | const er = -2; | 1397 | self.* = undefined; |
| | 1398 | } |
| 2447 | | 1399 | |
| 2448 | testing.expect((try q.to(i32)) == eq); | 1400 | /// Returns a `Managed` with the same value. The returned `Managed` is a deep copy and |
| 2449 | testing.expect((try r.to(i32)) == er); | 1401 | /// can be modified separately from the original, and its resources are managed |
| 2450 | } | 1402 | /// separately from the original. |
| | 1403 | pub fn clone(other: Managed) !Managed { |
| | 1404 | return other.cloneWithDifferentAllocator(other.allocator); |
| | 1405 | } |
| 2451 | | 1406 | |
| 2452 | test "big.int div trunc single-single +/-" { | 1407 | pub fn cloneWithDifferentAllocator(other: Managed, allocator: *Allocator) !Managed { |
| 2453 | const u: i32 = 5; | 1408 | return Managed{ |
| 2454 | const v: i32 = -3; | 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 | } |
| 2455 | | 1418 | |
| 2456 | var a = try Int.initSet(testing.allocator, u); | 1419 | /// Copies the value of the integer to an existing `Managed` so that they both have the same value. |
| 2457 | defer a.deinit(); | 1420 | /// Extra memory will be allocated if the receiver does not have enough capacity. |
| 2458 | var b = try Int.initSet(testing.allocator, v); | 1421 | pub fn copy(self: *Managed, other: Const) !void { |
| 2459 | defer b.deinit(); | 1422 | if (self.limbs.ptr == other.limbs.ptr) return; |
| 2460 | | 1423 | |
| 2461 | var q = try Int.init(testing.allocator); | 1424 | try self.ensureCapacity(other.limbs.len); |
| 2462 | defer q.deinit(); | 1425 | mem.copy(Limb, self.limbs[0..], other.limbs[0..other.limbs.len]); |
| 2463 | var r = try Int.init(testing.allocator); | 1426 | self.setMetadata(other.positive, other.limbs.len); |
| 2464 | defer r.deinit(); | 1427 | } |
| 2465 | try Int.divTrunc(&q, &r, a, b); | | |
| 2466 | | 1428 | |
| 2467 | // n = q * d + r | 1429 | /// Efficiently swap a `Managed` with another. This swaps the limb pointers and a full copy is not |
| 2468 | // 5 = -1 * -3 + 2 | 1430 | /// performed. The address of the limbs field will not be the same after this function. |
| 2469 | const eq = -1; | 1431 | pub fn swap(self: *Managed, other: *Managed) void { |
| 2470 | const er = 2; | 1432 | mem.swap(Managed, self, other); |
| | 1433 | } |
| 2471 | | 1434 | |
| 2472 | testing.expect((try q.to(i32)) == eq); | 1435 | /// Debugging tool: prints the state to stderr. |
| 2473 | testing.expect((try r.to(i32)) == er); | 1436 | pub fn dump(self: Managed) void { |
| 2474 | } | 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 | } |
| 2475 | | 1442 | |
| 2476 | test "big.int div trunc single-single -/-" { | 1443 | /// Negate the sign. |
| 2477 | const u: i32 = -5; | 1444 | pub fn negate(self: *Managed) void { |
| 2478 | const v: i32 = -3; | 1445 | self.metadata ^= sign_bit; |
| | 1446 | } |
| 2479 | | 1447 | |
| 2480 | var a = try Int.initSet(testing.allocator, u); | 1448 | /// Make positive. |
| 2481 | defer a.deinit(); | 1449 | pub fn abs(self: *Managed) void { |
| 2482 | var b = try Int.initSet(testing.allocator, v); | 1450 | self.metadata &= ~sign_bit; |
| 2483 | defer b.deinit(); | 1451 | } |
| 2484 | | 1452 | |
| 2485 | var q = try Int.init(testing.allocator); | 1453 | pub fn isOdd(self: Managed) bool { |
| 2486 | defer q.deinit(); | 1454 | return self.limbs[0] & 1 != 0; |
| 2487 | var r = try Int.init(testing.allocator); | 1455 | } |
| 2488 | defer r.deinit(); | | |
| 2489 | try Int.divTrunc(&q, &r, a, b); | | |
| 2490 | | 1456 | |
| 2491 | // n = q * d + r | 1457 | pub fn isEven(self: Managed) bool { |
| 2492 | // -5 = 1 * -3 - 2 | 1458 | return !self.isOdd(); |
| 2493 | const eq = 1; | 1459 | } |
| 2494 | const er = -2; | | |
| 2495 | | 1460 | |
| 2496 | testing.expect((try q.to(i32)) == eq); | 1461 | /// Returns the number of bits required to represent the absolute value of an integer. |
| 2497 | testing.expect((try r.to(i32)) == er); | 1462 | pub fn bitCountAbs(self: Managed) usize { |
| 2498 | } | 1463 | return self.toConst().bitCountAbs(); |
| | 1464 | } |
| 2499 | | 1465 | |
| 2500 | test "big.int div floor single-single +/+" { | 1466 | /// Returns the number of bits required to represent the integer in twos-complement form. |
| 2501 | const u: i32 = 5; | 1467 | /// |
| 2502 | const v: i32 = 3; | 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 | } |
| 2503 | | 1477 | |
| 2504 | var a = try Int.initSet(testing.allocator, u); | 1478 | pub fn fitsInTwosComp(self: Managed, is_signed: bool, bit_count: usize) bool { |
| 2505 | defer a.deinit(); | 1479 | return self.toConst().fitsInTwosComp(is_signed, bit_count); |
| 2506 | var b = try Int.initSet(testing.allocator, v); | 1480 | } |
| 2507 | defer b.deinit(); | | |
| 2508 | | 1481 | |
| 2509 | var q = try Int.init(testing.allocator); | 1482 | /// Returns whether self can fit into an integer of the requested type. |
| 2510 | defer q.deinit(); | 1483 | pub fn fits(self: Managed, comptime T: type) bool { |
| 2511 | var r = try Int.init(testing.allocator); | 1484 | return self.toConst().fits(T); |
| 2512 | defer r.deinit(); | 1485 | } |
| 2513 | try Int.divFloor(&q, &r, a, b); | | |
| 2514 | | 1486 | |
| 2515 | // n = q * d + r | 1487 | /// Returns the approximate size of the integer in the given base. Negative values accommodate for |
| 2516 | // 5 = 1 * 3 + 2 | 1488 | /// the minus sign. This is used for determining the number of characters needed to print the |
| 2517 | const eq = 1; | 1489 | /// value. It is inexact and may exceed the given value by ~1-2 bytes. |
| 2518 | const er = 2; | 1490 | pub fn sizeInBaseUpperBound(self: Managed, base: usize) usize { |
| | 1491 | return self.toConst().sizeInBaseUpperBound(base); |
| | 1492 | } |
| 2519 | | 1493 | |
| 2520 | testing.expect((try q.to(i32)) == eq); | 1494 | /// Sets an Managed to value. Value must be an primitive integer type. |
| 2521 | testing.expect((try r.to(i32)) == er); | 1495 | pub fn set(self: *Managed, value: var) Allocator.Error!void { |
| 2522 | } | 1496 | try self.ensureCapacity(calcLimbLen(value)); |
| | 1497 | var m = self.toMutable(); |
| | 1498 | m.set(value); |
| | 1499 | self.setMetadata(m.positive, m.len); |
| | 1500 | } |
| 2523 | | 1501 | |
| 2524 | test "big.int div floor single-single -/+" { | 1502 | pub const ConvertError = Const.ConvertError; |
| 2525 | const u: i32 = -5; | | |
| 2526 | const v: i32 = 3; | | |
| 2527 | | 1503 | |
| 2528 | var a = try Int.initSet(testing.allocator, u); | 1504 | /// Convert self to type T. |
| 2529 | defer a.deinit(); | 1505 | /// |
| 2530 | var b = try Int.initSet(testing.allocator, v); | 1506 | /// Returns an error if self cannot be narrowed into the requested type without truncation. |
| 2531 | defer b.deinit(); | 1507 | pub fn to(self: Managed, comptime T: type) ConvertError!T { |
| | 1508 | return self.toConst().to(T); |
| | 1509 | } |
| 2532 | | 1510 | |
| 2533 | var q = try Int.init(testing.allocator); | 1511 | /// Set self from the string representation `value`. |
| 2534 | defer q.deinit(); | 1512 | /// |
| 2535 | var r = try Int.init(testing.allocator); | 1513 | /// `value` must contain only digits <= `base` and is case insensitive. Base prefixes are |
| 2536 | defer r.deinit(); | 1514 | /// not allowed (e.g. 0x43 should simply be 43). Underscores in the input string are |
| 2537 | try Int.divFloor(&q, &r, a, b); | 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 | } |
| 2538 | | 1531 | |
| 2539 | // n = q * d + r | 1532 | /// Converts self to a string in the requested base. Memory is allocated from the provided |
| 2540 | // -5 = -2 * 3 + 1 | 1533 | /// allocator and not the one present in self. |
| 2541 | const eq = -2; | 1534 | pub fn toString(self: Managed, allocator: *Allocator, base: u8, uppercase: bool) ![]u8 { |
| 2542 | const er = 1; | 1535 | if (base < 2 or base > 16) return error.InvalidBase; |
| | 1536 | return self.toConst().toStringAlloc(self.allocator, base, uppercase); |
| | 1537 | } |
| 2543 | | 1538 | |
| 2544 | testing.expect((try q.to(i32)) == eq); | 1539 | /// To allow `std.fmt.format` to work with `Managed`. |
| 2545 | testing.expect((try r.to(i32)) == er); | 1540 | /// If the integer is larger than `pow(2, 64 * @sizeOf(usize) * 8), this function will fail |
| 2546 | } | 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 | } |
| 2547 | | 1552 | |
| 2548 | test "big.int div floor single-single +/-" { | 1553 | /// Returns math.Order.lt, math.Order.eq, math.Order.gt if |a| < |b|, |a| == |
| 2549 | const u: i32 = 5; | 1554 | /// |b| or |a| > |b| respectively. |
| 2550 | const v: i32 = -3; | 1555 | pub fn orderAbs(a: Managed, b: Managed) math.Order { |
| | 1556 | return a.toConst().orderAbs(b.toConst()); |
| | 1557 | } |
| 2551 | | 1558 | |
| 2552 | var a = try Int.initSet(testing.allocator, u); | 1559 | /// Returns math.Order.lt, math.Order.eq, math.Order.gt if a < b, a == b or a |
| 2553 | defer a.deinit(); | 1560 | /// > b respectively. |
| 2554 | var b = try Int.initSet(testing.allocator, v); | 1561 | pub fn order(a: Managed, b: Managed) math.Order { |
| 2555 | defer b.deinit(); | 1562 | return a.toConst().order(b.toConst()); |
| | 1563 | } |
| 2556 | | 1564 | |
| 2557 | var q = try Int.init(testing.allocator); | 1565 | /// Returns true if a == 0. |
| 2558 | defer q.deinit(); | 1566 | pub fn eqZero(a: Managed) bool { |
| 2559 | var r = try Int.init(testing.allocator); | 1567 | return a.toConst().eqZero(); |
| 2560 | defer r.deinit(); | 1568 | } |
| 2561 | try Int.divFloor(&q, &r, a, b); | | |
| 2562 | | 1569 | |
| 2563 | // n = q * d + r | 1570 | /// Returns true if |a| == |b|. |
| 2564 | // 5 = -2 * -3 - 1 | 1571 | pub fn eqAbs(a: Managed, b: Managed) bool { |
| 2565 | const eq = -2; | 1572 | return a.toConst().eqAbs(b.toConst()); |
| 2566 | const er = -1; | 1573 | } |
| 2567 | | 1574 | |
| 2568 | testing.expect((try q.to(i32)) == eq); | 1575 | /// Returns true if a == b. |
| 2569 | testing.expect((try r.to(i32)) == er); | 1576 | pub fn eq(a: Managed, b: Managed) bool { |
| 2570 | } | 1577 | return a.toConst().eq(b.toConst()); |
| | 1578 | } |
| 2571 | | 1579 | |
| 2572 | test "big.int div floor single-single -/-" { | 1580 | /// Normalize a possible sequence of leading zeros. |
| 2573 | const u: i32 = -5; | 1581 | /// |
| 2574 | const v: i32 = -3; | 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); |
| 2575 | | 1588 | |
| 2576 | var a = try Int.initSet(testing.allocator, u); | 1589 | var j = length; |
| 2577 | defer a.deinit(); | 1590 | while (j > 0) : (j -= 1) { |
| 2578 | var b = try Int.initSet(testing.allocator, v); | 1591 | if (r.limbs[j - 1] != 0) { |
| 2579 | defer b.deinit(); | 1592 | break; |
| | 1593 | } |
| | 1594 | } |
| 2580 | | 1595 | |
| 2581 | var q = try Int.init(testing.allocator); | 1596 | // Handle zero |
| 2582 | defer q.deinit(); | 1597 | r.setLen(if (j != 0) j else 1); |
| 2583 | var r = try Int.init(testing.allocator); | 1598 | } |
| 2584 | defer r.deinit(); | | |
| 2585 | try Int.divFloor(&q, &r, a, b); | | |
| 2586 | | 1599 | |
| 2587 | // n = q * d + r | 1600 | /// r = a + scalar |
| 2588 | // -5 = 2 * -3 + 1 | 1601 | /// |
| 2589 | const eq = 1; | 1602 | /// r and a may be aliases. |
| 2590 | const er = -2; | 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 | } |
| 2591 | | 1612 | |
| 2592 | testing.expect((try q.to(i32)) == eq); | 1613 | /// r = a + b |
| 2593 | testing.expect((try r.to(i32)) == er); | 1614 | /// |
| 2594 | } | 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 | } |
| 2595 | | 1624 | |
| 2596 | test "big.int div multi-multi with rem" { | 1625 | /// r = a - b |
| 2597 | var a = try Int.initSet(testing.allocator, 0x8888999911110000ffffeeeeddddccccbbbbaaaa9999); | 1626 | /// |
| 2598 | defer a.deinit(); | 1627 | /// r, a and b may be aliases. |
| 2599 | var b = try Int.initSet(testing.allocator, 0x99990000111122223333); | 1628 | /// |
| 2600 | defer b.deinit(); | 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 | } |
| 2601 | | 1636 | |
| 2602 | var q = try Int.init(testing.allocator); | 1637 | /// rma = a * b |
| 2603 | defer q.deinit(); | 1638 | /// |
| 2604 | var r = try Int.init(testing.allocator); | 1639 | /// rma, a and b may be aliases. However, it is more efficient if rma does not alias a or b. |
| 2605 | defer r.deinit(); | 1640 | /// |
| 2606 | try Int.divTrunc(&q, &r, a, b); | 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 | } |
| 2607 | | 1662 | |
| 2608 | testing.expect((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b); | 1663 | /// q = a / b (rem r) |
| 2609 | testing.expect((try r.to(u128)) == 0x28de0acacd806823638); | 1664 | /// |
| 2610 | } | 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 | } |
| 2611 | | 1681 | |
| 2612 | test "big.int div multi-multi no rem" { | 1682 | /// q = a / b (rem r) |
| 2613 | var a = try Int.initSet(testing.allocator, 0x8888999911110000ffffeeeedb4fec200ee3a4286361); | 1683 | /// |
| 2614 | defer a.deinit(); | 1684 | /// a / b are truncated (rounded towards -inf). |
| 2615 | var b = try Int.initSet(testing.allocator, 0x99990000111122223333); | 1685 | /// |
| 2616 | defer b.deinit(); | 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 | } |
| 2617 | | 1700 | |
| 2618 | var q = try Int.init(testing.allocator); | 1701 | /// r = a << shift, in other words, r = a * 2^shift |
| 2619 | defer q.deinit(); | 1702 | pub fn shiftLeft(r: *Managed, a: Managed, shift: usize) !void { |
| 2620 | var r = try Int.init(testing.allocator); | 1703 | try r.ensureCapacity(a.len() + (shift / Limb.bit_count) + 1); |
| 2621 | defer r.deinit(); | 1704 | var m = r.toMutable(); |
| 2622 | try Int.divTrunc(&q, &r, a, b); | 1705 | m.shiftLeft(a.toConst(), shift); |
| | 1706 | r.setMetadata(m.positive, m.len); |
| | 1707 | } |
| 2623 | | 1708 | |
| 2624 | testing.expect((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b); | 1709 | /// r = a >> shift |
| 2625 | testing.expect((try r.to(u128)) == 0); | 1710 | pub fn shiftRight(r: *Managed, a: Managed, shift: usize) !void { |
| 2626 | } | 1711 | if (a.len() <= shift / Limb.bit_count) { |
| | 1712 | r.metadata = 1; |
| | 1713 | r.limbs[0] = 0; |
| | 1714 | return; |
| | 1715 | } |
| 2627 | | 1716 | |
| 2628 | test "big.int div multi-multi (2 branch)" { | 1717 | try r.ensureCapacity(a.len() - (shift / Limb.bit_count)); |
| 2629 | var a = try Int.initSet(testing.allocator, 0x866666665555555588888887777777761111111111111111); | 1718 | var m = r.toMutable(); |
| 2630 | defer a.deinit(); | 1719 | m.shiftRight(a.toConst(), shift); |
| 2631 | var b = try Int.initSet(testing.allocator, 0x86666666555555554444444433333333); | 1720 | r.setMetadata(m.positive, m.len); |
| 2632 | defer b.deinit(); | 1721 | } |
| 2633 | | 1722 | |
| 2634 | var q = try Int.init(testing.allocator); | 1723 | /// r = a | b |
| 2635 | defer q.deinit(); | 1724 | /// |
| 2636 | var r = try Int.init(testing.allocator); | 1725 | /// a and b are zero-extended to the longer of a or b. |
| 2637 | defer r.deinit(); | 1726 | pub fn bitOr(r: *Managed, a: Managed, b: Managed) !void { |
| 2638 | try Int.divTrunc(&q, &r, a, b); | 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 | } |
| 2639 | | 1732 | |
| 2640 | testing.expect((try q.to(u128)) == 0x10000000000000000); | 1733 | /// r = a & b |
| 2641 | testing.expect((try r.to(u128)) == 0x44444443444444431111111111111111); | 1734 | pub fn bitAnd(r: *Managed, a: Managed, b: Managed) !void { |
| 2642 | } | 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 | } |
| 2643 | | 1740 | |
| 2644 | test "big.int div multi-multi (3.1/3.3 branch)" { | 1741 | /// r = a ^ b |
| 2645 | var a = try Int.initSet(testing.allocator, 0x11111111111111111111111111111111111111111111111111111111111111); | 1742 | pub fn bitXor(r: *Managed, a: Managed, b: Managed) !void { |
| 2646 | defer a.deinit(); | 1743 | try r.ensureCapacity(math.max(a.len(), b.len())); |
| 2647 | var b = try Int.initSet(testing.allocator, 0x1111111111111111111111111111111111111111171); | 1744 | var m = r.toMutable(); |
| 2648 | defer b.deinit(); | 1745 | m.bitXor(a.toConst(), b.toConst()); |
| | 1746 | r.setMetadata(m.positive, m.len); |
| | 1747 | } |
| 2649 | | 1748 | |
| 2650 | var q = try Int.init(testing.allocator); | 1749 | /// rma may alias x or y. |
| 2651 | defer q.deinit(); | 1750 | /// x and y may alias each other. |
| 2652 | var r = try Int.init(testing.allocator); | 1751 | /// |
| 2653 | defer r.deinit(); | 1752 | /// rma's allocator is used for temporary storage to boost multiplication performance. |
| 2654 | try Int.divTrunc(&q, &r, a, b); | 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 | }; |
| 2655 | | 1762 | |
| 2656 | testing.expect((try q.to(u128)) == 0xfffffffffffffffffff); | 1763 | /// Knuth 4.3.1, Algorithm M. |
| 2657 | testing.expect((try r.to(u256)) == 0x1111111111111111111110b12222222222222222282); | 1764 | /// |
| 2658 | } | 1765 | /// r MUST NOT alias any of a or b. |
| | 1766 | fn 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 | } |
| 2659 | | 1788 | |
| 2660 | test "big.int div multi-single zero-limb trailing" { | 1789 | // Basecase multiplication |
| 2661 | var a = try Int.initSet(testing.allocator, 0x60000000000000000000000000000000000000000000000000000000000000000); | 1790 | var i: usize = 0; |
| 2662 | defer a.deinit(); | 1791 | while (i < x.len) : (i += 1) { |
| 2663 | var b = try Int.initSet(testing.allocator, 0x10000000000000000); | 1792 | llmulDigit(r[i..], y, x[i]); |
| 2664 | defer b.deinit(); | 1793 | } |
| 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()); | | |
| 2676 | } | 1794 | } |
| 2677 | | 1795 | |
| 2678 | test "big.int div multi-multi zero-limb trailing (with rem)" { | 1796 | /// Knuth 4.3.1, Algorithm M. |
| 2679 | var a = try Int.initSet(testing.allocator, 0x86666666555555558888888777777776111111111111111100000000000000000000000000000000); | 1797 | /// |
| 2680 | defer a.deinit(); | 1798 | /// r MUST NOT alias any of a or b. |
| 2681 | var b = try Int.initSet(testing.allocator, 0x8666666655555555444444443333333300000000000000000000000000000000); | 1799 | fn llmulacc_karatsuba(allocator: *Allocator, r: []Limb, x: []const Limb, y: []const Limb) error{OutOfMemory}!void { |
| 2682 | defer b.deinit(); | 1800 | @setRuntimeSafety(false); |
| 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); | | |
| 2691 | | 1801 | |
| 2692 | const rs = try r.toString(testing.allocator, 16, false); | 1802 | assert(r.len >= x.len + y.len + 1); |
| 2693 | defer testing.allocator.free(rs); | | |
| 2694 | testing.expect(std.mem.eql(u8, rs, "4444444344444443111111111111111100000000000000000000000000000000")); | | |
| 2695 | } | | |
| 2696 | | 1803 | |
| 2697 | test "big.int div multi-multi zero-limb trailing (with rem) and dividend zero-limb count > divisor zero-limb count" { | 1804 | const split = @divFloor(x.len, 2); |
| 2698 | var a = try Int.initSet(testing.allocator, 0x8666666655555555888888877777777611111111111111110000000000000000); | 1805 | var x0 = x[0..split]; |
| 2699 | defer a.deinit(); | 1806 | var x1 = x[split..x.len]; |
| 2700 | var b = try Int.initSet(testing.allocator, 0x8666666655555555444444443333333300000000000000000000000000000000); | 1807 | var y0 = y[0..split]; |
| 2701 | defer b.deinit(); | 1808 | var y1 = y[split..y.len]; |
| 2702 | | 1809 | |
| 2703 | var q = try Int.init(testing.allocator); | 1810 | var tmp = try allocator.alloc(Limb, x1.len + y1.len + 1); |
| 2704 | defer q.deinit(); | 1811 | defer allocator.free(tmp); |
| 2705 | var r = try Int.init(testing.allocator); | 1812 | mem.set(Limb, tmp, 0); |
| 2706 | defer r.deinit(); | | |
| 2707 | try Int.divTrunc(&q, &r, a, b); | | |
| 2708 | | 1813 | |
| 2709 | testing.expect((try q.to(u128)) == 0x1); | 1814 | llmulacc(allocator, tmp, x1, y1); |
| 2710 | | 1815 | |
| 2711 | const rs = try r.toString(testing.allocator, 16, false); | 1816 | var length = llnormalize(tmp); |
| 2712 | defer testing.allocator.free(rs); | 1817 | _ = llaccum(r[split..], tmp[0..length]); |
| 2713 | testing.expect(std.mem.eql(u8, rs, "444444434444444311111111111111110000000000000000")); | 1818 | _ = llaccum(r[split * 2 ..], tmp[0..length]); |
| 2714 | } | | |
| 2715 | | 1819 | |
| 2716 | test "big.int div multi-multi zero-limb trailing (with rem) and dividend zero-limb count < divisor zero-limb count" { | 1820 | mem.set(Limb, tmp[0..length], 0); |
| 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 | } | | |
| 2736 | | 1821 | |
| 2737 | test "big.int div multi-multi fuzz case #1" { | 1822 | llmulacc(allocator, tmp, x0, y0); |
| 2738 | var a = try Int.init(testing.allocator); | | |
| 2739 | defer a.deinit(); | | |
| 2740 | var b = try Int.init(testing.allocator); | | |
| 2741 | defer b.deinit(); | | |
| 2742 | | 1823 | |
| 2743 | try a.setString(16, "ffffffffffffffffffffffffffffc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); | 1824 | length = llnormalize(tmp); |
| 2744 | try b.setString(16, "3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffc000000000000000000000000000000007fffffffffff"); | 1825 | _ = llaccum(r[0..], tmp[0..length]); |
| | 1826 | _ = llaccum(r[split..], tmp[0..length]); |
| 2745 | | 1827 | |
| 2746 | var q = try Int.init(testing.allocator); | 1828 | const x_cmp = llcmp(x1, x0); |
| 2747 | defer q.deinit(); | 1829 | const y_cmp = llcmp(y1, y0); |
| 2748 | var r = try Int.init(testing.allocator); | 1830 | if (x_cmp * y_cmp == 0) { |
| 2749 | defer r.deinit(); | 1831 | return; |
| 2750 | try Int.divTrunc(&q, &r, a, b); | 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 | } |
| 2751 | | 1842 | |
| 2752 | const qs = try q.toString(testing.allocator, 16, false); | 1843 | const y0_len = llnormalize(y0); |
| 2753 | defer testing.allocator.free(qs); | 1844 | const y1_len = llnormalize(y1); |
| 2754 | testing.expect(std.mem.eql(u8, qs, "3ffffffffffffffffffffffffffff0000000000000000000000000000000000001ffffffffffffffffffffffffffff7fffffffe000000000000000000000000000180000000000000000000003fffffbfffffffdfffffffffffffeffff800000100101000000100000000020003fffffdfbfffffe3ffffffffffffeffff7fffc00800a100000017ffe000002000400007efbfff7fe9f00000037ffff3fff7fffa004006100000009ffe00000190038200bf7d2ff7fefe80400060000f7d7f8fbf9401fe38e0403ffc0bdffffa51102c300d7be5ef9df4e5060007b0127ad3fa69f97d0f820b6605ff617ddf7f32ad7a05c0d03f2e7bc78a6000e087a8bbcdc59e07a5a079128a7861f553ddebed7e8e56701756f9ead39b48cd1b0831889ea6ec1fddf643d0565b075ff07e6caea4e2854ec9227fd635ed60a2f5eef2893052ffd54718fa08604acbf6a15e78a467c4a3c53c0278af06c4416573f925491b195e8fd79302cb1aaf7caf4ecfc9aec1254cc969786363ac729f914c6ddcc26738d6b0facd54eba026580aba2eb6482a088b0d224a8852420b91ec1")); | 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); |
| 2755 | | 1857 | |
| 2756 | const rs = try r.toString(testing.allocator, 16, false); | 1858 | length = llnormalize(tmp); |
| 2757 | defer testing.allocator.free(rs); | 1859 | llsub(r[split..], r[split..], tmp[0..length]); |
| 2758 | testing.expect(std.mem.eql(u8, rs, "310d1d4c414426b4836c2635bad1df3a424e50cbdd167ffccb4dfff57d36b4aae0d6ca0910698220171a0f3373c1060a046c2812f0027e321f72979daa5e7973214170d49e885de0c0ecc167837d44502430674a82522e5df6a0759548052420b91ec1")); | 1860 | } else { |
| | 1861 | llmulacc(allocator, r[split..], j0, j1); |
| | 1862 | } |
| 2759 | } | 1863 | } |
| 2760 | | 1864 | |
| 2761 | test "big.int div multi-multi fuzz case #2" { | 1865 | // r = r + a |
| 2762 | var a = try Int.init(testing.allocator); | 1866 | fn llaccum(r: []Limb, a: []const Limb) Limb { |
| 2763 | defer a.deinit(); | 1867 | @setRuntimeSafety(false); |
| 2764 | var b = try Int.init(testing.allocator); | 1868 | assert(r.len != 0 and a.len != 0); |
| 2765 | defer b.deinit(); | 1869 | assert(r.len >= a.len); |
| 2766 | | 1870 | |
| 2767 | try a.setString(16, "3ffffffffe00000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000000000000000000000000000000000000000000000000000000000000001fffffffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffc000000000000000000000000000000000000000000000000000000000000000"); | 1871 | var i: usize = 0; |
| 2768 | try b.setString(16, "ffc0000000000000000000000000000000000000000000000000"); | 1872 | var carry: Limb = 0; |
| 2769 | | 1873 | |
| 2770 | var q = try Int.init(testing.allocator); | 1874 | while (i < a.len) : (i += 1) { |
| 2771 | defer q.deinit(); | 1875 | var c: Limb = 0; |
| 2772 | var r = try Int.init(testing.allocator); | 1876 | c += @boolToInt(@addWithOverflow(Limb, r[i], a[i], &r[i])); |
| 2773 | defer r.deinit(); | 1877 | c += @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i])); |
| 2774 | try Int.divTrunc(&q, &r, a, b); | 1878 | carry = c; |
| | 1879 | } |
| 2775 | | 1880 | |
| 2776 | const qs = try q.toString(testing.allocator, 16, false); | 1881 | while ((carry != 0) and i < r.len) : (i += 1) { |
| 2777 | defer testing.allocator.free(qs); | 1882 | carry = @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i])); |
| 2778 | testing.expect(std.mem.eql(u8, qs, "40100400fe3f8fe3f8fe3f8fe3f8fe3f8fe4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f91e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4992649926499264991e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4792e4b92e4b92e4b92e4b92a4a92a4a92a4")); | 1883 | } |
| 2779 | | 1884 | |
| 2780 | const rs = try r.toString(testing.allocator, 16, false); | 1885 | return carry; |
| 2781 | defer testing.allocator.free(rs); | | |
| 2782 | testing.expect(std.mem.eql(u8, rs, "a900000000000000000000000000000000000000000000000000")); | | |
| 2783 | } | 1886 | } |
| 2784 | | 1887 | |
| 2785 | test "big.int shift-right single" { | 1888 | /// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively for limbs. |
| 2786 | var a = try Int.initSet(testing.allocator, 0xffff0000); | 1889 | pub fn llcmp(a: []const Limb, b: []const Limb) i8 { |
| 2787 | defer a.deinit(); | 1890 | @setRuntimeSafety(false); |
| 2788 | try a.shiftRight(a, 16); | 1891 | const a_len = llnormalize(a); |
| 2789 | | 1892 | const b_len = llnormalize(b); |
| 2790 | testing.expect((try a.to(u32)) == 0xffff); | 1893 | if (a_len < b_len) { |
| 2791 | } | 1894 | return -1; |
| | 1895 | } |
| | 1896 | if (a_len > b_len) { |
| | 1897 | return 1; |
| | 1898 | } |
| 2792 | | 1899 | |
| 2793 | test "big.int shift-right multi" { | 1900 | var i: usize = a_len - 1; |
| 2794 | var a = try Int.initSet(testing.allocator, 0xffff0000eeee1111dddd2222cccc3333); | 1901 | while (i != 0) : (i -= 1) { |
| 2795 | defer a.deinit(); | 1902 | if (a[i] != b[i]) { |
| 2796 | try a.shiftRight(a, 67); | 1903 | break; |
| | 1904 | } |
| | 1905 | } |
| 2797 | | 1906 | |
| 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 | } |
| 2799 | } | 1914 | } |
| 2800 | | 1915 | |
| 2801 | test "big.int shift-left single" { | 1916 | fn llmulDigit(acc: []Limb, y: []const Limb, xi: Limb) void { |
| 2802 | var a = try Int.initSet(testing.allocator, 0xffff); | 1917 | @setRuntimeSafety(false); |
| 2803 | defer a.deinit(); | 1918 | if (xi == 0) { |
| 2804 | try a.shiftLeft(a, 16); | 1919 | return; |
| | 1920 | } |
| 2805 | | 1921 | |
| 2806 | testing.expect((try a.to(u64)) == 0xffff0000); | 1922 | var carry: usize = 0; |
| 2807 | } | 1923 | var a_lo = acc[0..y.len]; |
| | 1924 | var a_hi = acc[y.len..]; |
| 2808 | | 1925 | |
| 2809 | test "big.int shift-left multi" { | 1926 | var j: usize = 0; |
| 2810 | var a = try Int.initSet(testing.allocator, 0x1fffe0001dddc222); | 1927 | while (j < a_lo.len) : (j += 1) { |
| 2811 | defer a.deinit(); | 1928 | a_lo[j] = @call(.{ .modifier = .always_inline }, addMulLimbWithCarry, .{ a_lo[j], y[j], xi, &carry }); |
| 2812 | try a.shiftLeft(a, 67); | 1929 | } |
| 2813 | | 1930 | |
| 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 | } |
| 2815 | } | 1935 | } |
| 2816 | | 1936 | |
| 2817 | test "big.int shift-right negative" { | 1937 | /// returns the min length the limb could be. |
| 2818 | var a = try Int.init(testing.allocator); | 1938 | fn llnormalize(a: []const Limb) usize { |
| 2819 | defer a.deinit(); | 1939 | @setRuntimeSafety(false); |
| 2820 | | 1940 | var j = a.len; |
| 2821 | try a.shiftRight(try Int.initSet(testing.allocator, -20), 2); | 1941 | while (j > 0) : (j -= 1) { |
| 2822 | defer a.deinit(); | 1942 | if (a[j - 1] != 0) { |
| 2823 | testing.expect((try a.to(i32)) == -20 >> 2); | 1943 | break; |
| | 1944 | } |
| | 1945 | } |
| 2824 | | 1946 | |
| 2825 | try a.shiftRight(try Int.initSet(testing.allocator, -5), 10); | 1947 | // Handle zero |
| 2826 | defer a.deinit(); | 1948 | return if (j != 0) j else 1; |
| 2827 | testing.expect((try a.to(i32)) == -5 >> 10); | | |
| 2828 | } | 1949 | } |
| 2829 | | 1950 | |
| 2830 | test "big.int shift-left negative" { | 1951 | /// Knuth 4.3.1, Algorithm S. |
| 2831 | var a = try Int.init(testing.allocator); | 1952 | fn llsub(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 2832 | defer a.deinit(); | 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); |
| 2833 | | 1957 | |
| 2834 | try a.shiftRight(try Int.initSet(testing.allocator, -10), 1232); | 1958 | var i: usize = 0; |
| 2835 | defer a.deinit(); | 1959 | var borrow: Limb = 0; |
| 2836 | testing.expect((try a.to(i32)) == -10 >> 1232); | | |
| 2837 | } | | |
| 2838 | | 1960 | |
| 2839 | test "big.int bitwise and simple" { | 1961 | while (i < b.len) : (i += 1) { |
| 2840 | var a = try Int.initSet(testing.allocator, 0xffffffff11111111); | 1962 | var c: Limb = 0; |
| 2841 | defer a.deinit(); | 1963 | c += @boolToInt(@subWithOverflow(Limb, a[i], b[i], &r[i])); |
| 2842 | var b = try Int.initSet(testing.allocator, 0xeeeeeeee22222222); | 1964 | c += @boolToInt(@subWithOverflow(Limb, r[i], borrow, &r[i])); |
| 2843 | defer b.deinit(); | 1965 | borrow = c; |
| | 1966 | } |
| 2844 | | 1967 | |
| 2845 | try a.bitAnd(a, b); | 1968 | while (i < a.len) : (i += 1) { |
| | 1969 | borrow = @boolToInt(@subWithOverflow(Limb, a[i], borrow, &r[i])); |
| | 1970 | } |
| 2846 | | 1971 | |
| 2847 | testing.expect((try a.to(u64)) == 0xeeeeeeee00000000); | 1972 | assert(borrow == 0); |
| 2848 | } | 1973 | } |
| 2849 | | 1974 | |
| 2850 | test "big.int bitwise and multi-limb" { | 1975 | /// Knuth 4.3.1, Algorithm A. |
| 2851 | var a = try Int.initSet(testing.allocator, maxInt(Limb) + 1); | 1976 | fn lladd(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 2852 | defer a.deinit(); | 1977 | @setRuntimeSafety(false); |
| 2853 | var b = try Int.initSet(testing.allocator, maxInt(Limb)); | 1978 | assert(a.len != 0 and b.len != 0); |
| 2854 | defer b.deinit(); | 1979 | assert(a.len >= b.len); |
| 2855 | | 1980 | assert(r.len >= a.len + 1); |
| 2856 | try a.bitAnd(a, b); | | |
| 2857 | | 1981 | |
| 2858 | testing.expect((try a.to(u128)) == 0); | 1982 | var i: usize = 0; |
| 2859 | } | 1983 | var carry: Limb = 0; |
| 2860 | | 1984 | |
| 2861 | test "big.int bitwise xor simple" { | 1985 | while (i < b.len) : (i += 1) { |
| 2862 | var a = try Int.initSet(testing.allocator, 0xffffffff11111111); | 1986 | var c: Limb = 0; |
| 2863 | defer a.deinit(); | 1987 | c += @boolToInt(@addWithOverflow(Limb, a[i], b[i], &r[i])); |
| 2864 | var b = try Int.initSet(testing.allocator, 0xeeeeeeee22222222); | 1988 | c += @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i])); |
| 2865 | defer b.deinit(); | 1989 | carry = c; |
| | 1990 | } |
| 2866 | | 1991 | |
| 2867 | try a.bitXor(a, b); | 1992 | while (i < a.len) : (i += 1) { |
| | 1993 | carry = @boolToInt(@addWithOverflow(Limb, a[i], carry, &r[i])); |
| | 1994 | } |
| 2868 | | 1995 | |
| 2869 | testing.expect((try a.to(u64)) == 0x1111111133333333); | 1996 | r[i] = carry; |
| 2870 | } | 1997 | } |
| 2871 | | 1998 | |
| 2872 | test "big.int bitwise xor multi-limb" { | 1999 | /// Knuth 4.3.1, Exercise 16. |
| 2873 | var a = try Int.initSet(testing.allocator, maxInt(Limb) + 1); | 2000 | fn lldiv1(quo: []Limb, rem: *Limb, a: []const Limb, b: Limb) void { |
| 2874 | defer a.deinit(); | 2001 | @setRuntimeSafety(false); |
| 2875 | var b = try Int.initSet(testing.allocator, maxInt(Limb)); | 2002 | assert(a.len > 1 or a[0] >= b); |
| 2876 | defer b.deinit(); | 2003 | assert(quo.len >= a.len); |
| 2877 | | 2004 | |
| 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]); |
| 2879 | | 2009 | |
| 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 | } |
| 2881 | } | 2024 | } |
| 2882 | | 2025 | |
| 2883 | test "big.int bitwise or simple" { | 2026 | fn llshl(r: []Limb, a: []const Limb, shift: usize) void { |
| 2884 | var a = try Int.initSet(testing.allocator, 0xffffffff11111111); | 2027 | @setRuntimeSafety(false); |
| 2885 | defer a.deinit(); | 2028 | assert(a.len >= 1); |
| 2886 | var b = try Int.initSet(testing.allocator, 0xeeeeeeee22222222); | 2029 | assert(r.len >= a.len + (shift / Limb.bit_count) + 1); |
| 2887 | defer b.deinit(); | | |
| 2888 | | 2030 | |
| 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); |
| 2890 | | 2033 | |
| 2891 | testing.expect((try a.to(u64)) == 0xffffffff33333333); | 2034 | var carry: Limb = 0; |
| 2892 | } | 2035 | var i: usize = 0; |
| 2893 | | 2036 | while (i < a.len) : (i += 1) { |
| 2894 | test "big.int bitwise or multi-limb" { | 2037 | const src_i = a.len - i - 1; |
| 2895 | var a = try Int.initSet(testing.allocator, maxInt(Limb) + 1); | 2038 | const dst_i = src_i + limb_shift; |
| 2896 | defer a.deinit(); | | |
| 2897 | var b = try Int.initSet(testing.allocator, maxInt(Limb)); | | |
| 2898 | defer b.deinit(); | | |
| 2899 | | 2039 | |
| 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 | } |
| 2901 | | 2048 | |
| 2902 | // TODO: big.int.cpp or is wrong on multi-limb. | 2049 | r[limb_shift - 1] = carry; |
| 2903 | testing.expect((try a.to(DoubleLimb)) == (maxInt(Limb) + 1) + maxInt(Limb)); | 2050 | mem.set(Limb, r[0 .. limb_shift - 1], 0); |
| 2904 | } | 2051 | } |
| 2905 | | 2052 | |
| 2906 | test "big.int var args" { | 2053 | fn llshr(r: []Limb, a: []const Limb, shift: usize) void { |
| 2907 | var a = try Int.initSet(testing.allocator, 5); | 2054 | @setRuntimeSafety(false); |
| 2908 | defer a.deinit(); | 2055 | assert(a.len >= 1); |
| | 2056 | assert(r.len >= a.len - (shift / Limb.bit_count)); |
| 2909 | | 2057 | |
| 2910 | const b = try Int.initSet(testing.allocator, 6); | 2058 | const limb_shift = shift / Limb.bit_count; |
| 2911 | defer b.deinit(); | 2059 | const interior_limb_shift = @intCast(Log2Limb, shift % Limb.bit_count); |
| 2912 | try a.add(a, b); | | |
| 2913 | testing.expect((try a.to(u64)) == 11); | | |
| 2914 | | 2060 | |
| 2915 | const c = try Int.initSet(testing.allocator, 11); | 2061 | var carry: Limb = 0; |
| 2916 | defer c.deinit(); | 2062 | var i: usize = 0; |
| 2917 | testing.expect(a.cmp(c) == .eq); | 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; |
| 2918 | | 2066 | |
| 2919 | const d = try Int.initSet(testing.allocator, 14); | 2067 | const src_digit = a[src_i]; |
| 2920 | defer d.deinit(); | 2068 | r[dst_i] = carry | (src_digit >> interior_limb_shift); |
| 2921 | testing.expect(a.cmp(d) != .gt); | 2069 | carry = @call(.{ .modifier = .always_inline }, math.shl, .{ |
| | 2070 | Limb, |
| | 2071 | src_digit, |
| | 2072 | Limb.bit_count - @intCast(Limb, interior_limb_shift), |
| | 2073 | }); |
| | 2074 | } |
| 2922 | } | 2075 | } |
| 2923 | | 2076 | |
| 2924 | test "big.int gcd non-one small" { | 2077 | fn llor(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 2925 | var a = try Int.initSet(testing.allocator, 17); | 2078 | @setRuntimeSafety(false); |
| 2926 | defer a.deinit(); | 2079 | assert(r.len >= a.len); |
| 2927 | var b = try Int.initSet(testing.allocator, 97); | 2080 | assert(a.len >= b.len); |
| 2928 | defer b.deinit(); | | |
| 2929 | var r = try Int.init(testing.allocator); | | |
| 2930 | defer r.deinit(); | | |
| 2931 | | 2081 | |
| 2932 | try r.gcd(a, b); | 2082 | var i: usize = 0; |
| 2933 | | 2083 | while (i < b.len) : (i += 1) { |
| 2934 | testing.expect((try r.to(u32)) == 1); | 2084 | r[i] = a[i] | b[i]; |
| | 2085 | } |
| | 2086 | while (i < a.len) : (i += 1) { |
| | 2087 | r[i] = a[i]; |
| | 2088 | } |
| 2935 | } | 2089 | } |
| 2936 | | 2090 | |
| 2937 | test "big.int gcd non-one small" { | 2091 | fn lland(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 2938 | var a = try Int.initSet(testing.allocator, 4864); | 2092 | @setRuntimeSafety(false); |
| 2939 | defer a.deinit(); | 2093 | assert(r.len >= b.len); |
| 2940 | var b = try Int.initSet(testing.allocator, 3458); | 2094 | assert(a.len >= b.len); |
| 2941 | defer b.deinit(); | | |
| 2942 | var r = try Int.init(testing.allocator); | | |
| 2943 | defer r.deinit(); | | |
| 2944 | | | |
| 2945 | try r.gcd(a, b); | | |
| 2946 | | 2095 | |
| 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 | } |
| 2948 | } | 2100 | } |
| 2949 | | 2101 | |
| 2950 | test "big.int gcd non-one large" { | 2102 | fn llxor(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 2951 | var a = try Int.initSet(testing.allocator, 0xffffffffffffffff); | 2103 | assert(r.len >= a.len); |
| 2952 | defer a.deinit(); | 2104 | assert(a.len >= b.len); |
| 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); | | |
| 2959 | | 2105 | |
| 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 | } |
| 2961 | } | 2113 | } |
| 2962 | | 2114 | |
| 2963 | test "big.int gcd large multi-limb result" { | 2115 | // Storage must live for the lifetime of the returned value |
| 2964 | var a = try Int.initSet(testing.allocator, 0x12345678123456781234567812345678123456781234567812345678); | 2116 | fn fixedIntFromSignedDoubleLimb(A: SignedDoubleLimb, storage: []Limb) Mutable { |
| 2965 | defer a.deinit(); | 2117 | assert(storage.len >= 2); |
| 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); | | |
| 2972 | | 2118 | |
| 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 | }; |
| 2974 | } | 2128 | } |
| 2975 | | 2129 | |
| 2976 | test "big.int gcd one large" { | 2130 | test "" { |
| 2977 | var a = try Int.initSet(testing.allocator, 1897056385327307); | 2131 | _ = @import("int_test.zig"); |
| 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); | | |
| 2987 | } | 2132 | } |