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