| 1 | module big |
| 2 | |
| 3 | import math.bits |
| 4 | |
| 5 | // Compares the magnitude of the two unsigned integers represented the given |
| 6 | // digit arrays. Returns -1 if a < b, 0 if a == b and +1 if a > b. Here |
| 7 | // a is operand_a and b is operand_b (for brevity). |
| 8 | @[direct_array_access] |
| 9 | fn compare_digit_array(operand_a []u64, operand_b []u64) int { |
| 10 | a_len := operand_a.len |
| 11 | b_len := operand_b.len |
| 12 | if a_len != b_len { |
| 13 | return if a_len < b_len { -1 } else { 1 } |
| 14 | } |
| 15 | // They have the same number of digits now |
| 16 | // Go from the most significant digit to the least significant one |
| 17 | for index := a_len - 1; index >= 0; index-- { |
| 18 | a_digit := operand_a[index] |
| 19 | b_digit := operand_b[index] |
| 20 | if a_digit != b_digit { |
| 21 | return if a_digit < b_digit { -1 } else { 1 } |
| 22 | } |
| 23 | } |
| 24 | return 0 |
| 25 | } |
| 26 | |
| 27 | // Add the digits in operand_a and operand_b and stores the result in sum. |
| 28 | // This function does not perform any allocation and assumes that the storage is |
| 29 | // large enough. It may affect the last element, based on the presence of a carry |
| 30 | @[direct_array_access] |
| 31 | fn add_digit_array(operand_a []u64, operand_b []u64, mut sum []u64) { |
| 32 | // Zero length cases |
| 33 | if operand_a.len == 0 { |
| 34 | for index in 0 .. operand_b.len { |
| 35 | sum[index] = operand_b[index] |
| 36 | } |
| 37 | shrink_tail_zeros(mut sum) |
| 38 | return |
| 39 | } |
| 40 | if operand_b.len == 0 { |
| 41 | for index in 0 .. operand_a.len { |
| 42 | sum[index] = operand_a[index] |
| 43 | } |
| 44 | shrink_tail_zeros(mut sum) |
| 45 | return |
| 46 | } |
| 47 | |
| 48 | mut a, mut b := if operand_a.len >= operand_b.len { |
| 49 | operand_a, operand_b |
| 50 | } else { |
| 51 | operand_b, operand_a |
| 52 | } |
| 53 | mut carry := u64(0) |
| 54 | for index in 0 .. b.len { |
| 55 | partial := carry + a[index] + b[index] |
| 56 | sum[index] = partial & max_digit |
| 57 | carry = partial >> digit_bits |
| 58 | } |
| 59 | |
| 60 | for index in b.len .. a.len { |
| 61 | partial := carry + a[index] |
| 62 | sum[index] = partial & max_digit |
| 63 | carry = partial >> digit_bits |
| 64 | } |
| 65 | |
| 66 | sum[a.len] = carry |
| 67 | shrink_tail_zeros(mut sum) |
| 68 | } |
| 69 | |
| 70 | // Subtracts operand_b from operand_a and stores the difference in storage. |
| 71 | // It assumes operand_a contains the larger "integer" and that storage is |
| 72 | // the same size as operand_a and is 0 |
| 73 | @[direct_array_access] |
| 74 | fn subtract_digit_array(operand_a []u64, operand_b []u64, mut storage []u64) { |
| 75 | // Zero length cases |
| 76 | if operand_a.len == 0 { |
| 77 | // nothing to subtract from |
| 78 | return |
| 79 | } |
| 80 | if operand_b.len == 0 { |
| 81 | // nothing to subtract |
| 82 | for index in 0 .. operand_a.len { |
| 83 | storage[index] = operand_a[index] |
| 84 | } |
| 85 | return |
| 86 | } |
| 87 | |
| 88 | mut borrow := u64(0) |
| 89 | for index in 0 .. operand_b.len { |
| 90 | a := operand_a[index] |
| 91 | b := operand_b[index] + borrow |
| 92 | diff := a - b |
| 93 | borrow = (diff >> digit_bits) & 1 |
| 94 | storage[index] = diff + (borrow << digit_bits) |
| 95 | } |
| 96 | for index in operand_b.len .. operand_a.len { |
| 97 | diff := operand_a[index] - borrow |
| 98 | borrow = (diff >> digit_bits) & 1 |
| 99 | storage[index] = diff + (borrow << digit_bits) |
| 100 | } |
| 101 | |
| 102 | shrink_tail_zeros(mut storage) |
| 103 | } |
| 104 | |
| 105 | const karatsuba_multiplication_limit = 70 |
| 106 | |
| 107 | const toom3_multiplication_limit = 360 |
| 108 | |
| 109 | @[inline] |
| 110 | fn multiply_digit_array(operand_a []u64, operand_b []u64, mut storage []u64) { |
| 111 | max_len := if operand_a.len >= operand_b.len { |
| 112 | operand_a.len |
| 113 | } else { |
| 114 | operand_b.len |
| 115 | } |
| 116 | if max_len >= toom3_multiplication_limit { |
| 117 | toom3_multiply_digit_array(operand_a, operand_b, mut storage) |
| 118 | } else if max_len >= karatsuba_multiplication_limit { |
| 119 | karatsuba_multiply_digit_array(operand_a, operand_b, mut storage) |
| 120 | } else { |
| 121 | simple_multiply_digit_array(operand_a, operand_b, mut storage) |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | // Multiplies the unsigned (non-negative) integers represented in a and b and the product is |
| 126 | // stored in storage. It assumes that storage has length equal to the sum of lengths |
| 127 | // of a and b. Length refers to length of array, that is, digit count. |
| 128 | @[direct_array_access] |
| 129 | fn simple_multiply_digit_array(operand_a []u64, operand_b []u64, mut storage []u64) { |
| 130 | for b_index in 0 .. operand_b.len { |
| 131 | mut hi := u64(0) |
| 132 | mut lo := u64(0) |
| 133 | for a_index in 0 .. operand_a.len { |
| 134 | hi, lo = bits.mul_add_64(operand_a[a_index], operand_b[b_index], storage[a_index + |
| 135 | b_index] + hi) |
| 136 | storage[a_index + b_index] = lo & max_digit |
| 137 | hi = (hi << (64 - digit_bits)) | (lo >> digit_bits) |
| 138 | } |
| 139 | if hi != 0 { |
| 140 | storage[b_index + operand_a.len] = hi |
| 141 | } |
| 142 | } |
| 143 | shrink_tail_zeros(mut storage) |
| 144 | } |
| 145 | |
| 146 | // Stores the product of the unsigned (non-negative) integer represented in a and the digit in value |
| 147 | // in the storage array. It assumes storage is pre-initialised and populated with 0's |
| 148 | @[direct_array_access] |
| 149 | fn multiply_array_by_digit(operand_a []u64, value u64, mut storage []u64) { |
| 150 | if value == 0 { |
| 151 | storage.clear() |
| 152 | return |
| 153 | } |
| 154 | if value == 1 { |
| 155 | for index in 0 .. operand_a.len { |
| 156 | storage[index] = operand_a[index] |
| 157 | } |
| 158 | shrink_tail_zeros(mut storage) |
| 159 | return |
| 160 | } |
| 161 | mut hi := u64(0) |
| 162 | mut lo := u64(0) |
| 163 | for index in 0 .. operand_a.len { |
| 164 | hi, lo = bits.mul_add_64(operand_a[index], value, hi) |
| 165 | storage[index] = lo & max_digit |
| 166 | hi = hi << (64 - digit_bits) + (lo >> digit_bits) |
| 167 | } |
| 168 | |
| 169 | if hi > 0 { |
| 170 | storage[operand_a.len] = hi |
| 171 | } |
| 172 | shrink_tail_zeros(mut storage) |
| 173 | } |
| 174 | |
| 175 | // Divides the non-negative integer in a by non-negative integer b and store the two results |
| 176 | // in quotient and remainder respectively. It is different from the rest of the functions |
| 177 | // because it assumes that quotient and remainder are empty zero length arrays. They can be |
| 178 | // made to have appropriate capacity though |
| 179 | @[direct_array_access] |
| 180 | fn divide_digit_array(operand_a []u64, operand_b []u64, mut quotient []u64, mut remainder []u64) { |
| 181 | cmp_result := compare_digit_array(operand_a, operand_b) |
| 182 | // a == b => q, r = 1, 0 |
| 183 | if cmp_result == 0 { |
| 184 | quotient[0] = 1 |
| 185 | remainder.clear() |
| 186 | return |
| 187 | } |
| 188 | |
| 189 | // a < b => q, r = 0, a |
| 190 | if cmp_result < 0 { |
| 191 | quotient.clear() |
| 192 | for i in 0 .. operand_a.len { |
| 193 | remainder[i] = operand_a[i] |
| 194 | } |
| 195 | return |
| 196 | } |
| 197 | if operand_b.len == 1 { |
| 198 | divide_array_by_digit(operand_a, operand_b[0], mut quotient, mut remainder) |
| 199 | } else { |
| 200 | divide_array_by_array(operand_a, operand_b, mut quotient, mut remainder) |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | // Performs division on the non-negative dividend in a by the single digit divisor b. It assumes |
| 205 | // quotient and remainder are empty zero length arrays without previous allocation |
| 206 | @[direct_array_access] |
| 207 | fn divide_array_by_digit(operand_a []u64, divisor u64, mut quotient []u64, mut remainder []u64) { |
| 208 | if operand_a.len == 1 { |
| 209 | // 1 digit for both dividend and divisor |
| 210 | dividend := operand_a[0] |
| 211 | q := dividend / divisor |
| 212 | quotient[0] = q |
| 213 | |
| 214 | rem := dividend % divisor |
| 215 | remainder[0] = rem |
| 216 | |
| 217 | shrink_tail_zeros(mut quotient) |
| 218 | shrink_tail_zeros(mut remainder) |
| 219 | return |
| 220 | } |
| 221 | // Dividend has more digits |
| 222 | mut rem := u64(0) |
| 223 | mut quo := u64(0) |
| 224 | |
| 225 | // Perform division step by step |
| 226 | for index := operand_a.len - 1; index >= 0; index-- { |
| 227 | hi := rem >> (64 - digit_bits) |
| 228 | lo := rem << digit_bits | operand_a[index] |
| 229 | quo, rem = bits.div_64(hi, lo, divisor) |
| 230 | quotient[index] = quo & max_digit |
| 231 | } |
| 232 | |
| 233 | // Remove leading zeros from quotient |
| 234 | shrink_tail_zeros(mut quotient) |
| 235 | remainder[0] = rem |
| 236 | shrink_tail_zeros(mut remainder) |
| 237 | } |
| 238 | |
| 239 | @[inline] |
| 240 | fn divide_array_by_array(operand_a []u64, operand_b []u64, mut quotient []u64, mut remainder []u64) { |
| 241 | knuth_divide_array_by_array(operand_a, operand_b, mut quotient, mut remainder) |
| 242 | } |
| 243 | |
| 244 | // Shifts the contents of the original array by the given amount of bits to the left. |
| 245 | // This function assumes that the amount is less than `digit_bits`. The storage is expected to |
| 246 | // allocated with zeroes. |
| 247 | @[direct_array_access] |
| 248 | fn shift_digits_left(original []u64, amount u32, mut storage []u64) { |
| 249 | mut leftover := u64(0) |
| 250 | offset := digit_bits - amount |
| 251 | for index in 0 .. original.len { |
| 252 | value := (leftover | (original[index] << amount)) & max_digit |
| 253 | leftover = (original[index] & (u64(-1) << offset)) >> offset |
| 254 | storage[index] = value |
| 255 | } |
| 256 | if leftover != 0 { |
| 257 | storage << leftover |
| 258 | } |
| 259 | } |
| 260 | |
| 261 | // Shifts the contents of the original array by the given amount of bits to the right. |
| 262 | // This function assumes that the amount is less than `digit_bits`. The storage is expected to |
| 263 | // be allocated with zeroes. |
| 264 | @[direct_array_access] |
| 265 | fn shift_digits_right(original []u64, amount u32, mut storage []u64) { |
| 266 | mut moveover := u64(0) |
| 267 | mask := (u64(1) << amount) - 1 |
| 268 | offset := digit_bits - amount |
| 269 | for index := original.len - 1; index >= 0; index-- { |
| 270 | value := (moveover << offset) | (original[index] >> amount) |
| 271 | moveover = original[index] & mask |
| 272 | storage[index] = value |
| 273 | } |
| 274 | shrink_tail_zeros(mut storage) |
| 275 | } |
| 276 | |
| 277 | @[direct_array_access] |
| 278 | fn bitwise_or_digit_array(operand_a []u64, operand_b []u64, mut storage []u64) { |
| 279 | lower, upper, bigger := if operand_a.len < operand_b.len { |
| 280 | operand_a.len, operand_b.len, operand_b |
| 281 | } else { |
| 282 | operand_b.len, operand_a.len, operand_a |
| 283 | } |
| 284 | for index in 0 .. lower { |
| 285 | storage[index] = operand_a[index] | operand_b[index] |
| 286 | } |
| 287 | for index in lower .. upper { |
| 288 | storage[index] = bigger[index] |
| 289 | } |
| 290 | shrink_tail_zeros(mut storage) |
| 291 | } |
| 292 | |
| 293 | @[direct_array_access] |
| 294 | fn bitwise_and_digit_array(operand_a []u64, operand_b []u64, mut storage []u64) { |
| 295 | lower := imin(operand_a.len, operand_b.len) |
| 296 | for index in 0 .. lower { |
| 297 | storage[index] = operand_a[index] & operand_b[index] |
| 298 | } |
| 299 | shrink_tail_zeros(mut storage) |
| 300 | } |
| 301 | |
| 302 | @[direct_array_access] |
| 303 | fn bitwise_xor_digit_array(operand_a []u64, operand_b []u64, mut storage []u64) { |
| 304 | lower, upper, bigger := if operand_a.len < operand_b.len { |
| 305 | operand_a.len, operand_b.len, operand_b |
| 306 | } else { |
| 307 | operand_b.len, operand_a.len, operand_a |
| 308 | } |
| 309 | for index in 0 .. lower { |
| 310 | storage[index] = operand_a[index] ^ operand_b[index] |
| 311 | } |
| 312 | for index in lower .. upper { |
| 313 | storage[index] = bigger[index] |
| 314 | } |
| 315 | shrink_tail_zeros(mut storage) |
| 316 | } |
| 317 | |
| 318 | @[direct_array_access] |
| 319 | fn bitwise_not_digit_array(original []u64, mut storage []u64) { |
| 320 | for index in 0 .. original.len { |
| 321 | storage[index] = (~original[index]) & max_digit |
| 322 | } |
| 323 | shrink_tail_zeros(mut storage) |
| 324 | } |
| 325 | |