public.odin 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. package math_big
  2. /*
  3. Copyright 2021 Jeroen van Rijn <[email protected]>.
  4. Made available under Odin's BSD-3 license.
  5. An arbitrary precision mathematics implementation in Odin.
  6. For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
  7. The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
  8. This file contains basic arithmetic operations like `add`, `sub`, `mul`, `div`, ...
  9. */
  10. /*
  11. ===========================
  12. User-level routines
  13. ===========================
  14. */
  15. /*
  16. High-level addition. Handles sign.
  17. */
  18. int_add :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
  19. assert_if_nil(dest, a, b);
  20. context.allocator = allocator;
  21. internal_clear_if_uninitialized(dest, a, b) or_return;
  22. /*
  23. All parameters have been initialized.
  24. */
  25. return #force_inline internal_int_add_signed(dest, a, b);
  26. }
  27. /*
  28. Adds the unsigned `DIGIT` immediate to an `Int`,
  29. such that the `DIGIT` doesn't have to be turned into an `Int` first.
  30. dest = a + digit;
  31. */
  32. int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
  33. assert_if_nil(dest, a);
  34. context.allocator = allocator;
  35. internal_clear_if_uninitialized(a) or_return;
  36. /*
  37. Grow destination as required.
  38. */
  39. grow(dest, a.used + 1) or_return;
  40. /*
  41. All parameters have been initialized.
  42. */
  43. return #force_inline internal_int_add_digit(dest, a, digit);
  44. }
  45. /*
  46. High-level subtraction, dest = number - decrease. Handles signs.
  47. */
  48. int_sub :: proc(dest, number, decrease: ^Int, allocator := context.allocator) -> (err: Error) {
  49. assert_if_nil(dest, number, decrease);
  50. context.allocator = allocator;
  51. internal_clear_if_uninitialized(dest, number, decrease) or_return;
  52. /*
  53. All parameters have been initialized.
  54. */
  55. return #force_inline internal_int_sub_signed(dest, number, decrease);
  56. }
  57. /*
  58. Adds the unsigned `DIGIT` immediate to an `Int`,
  59. such that the `DIGIT` doesn't have to be turned into an `Int` first.
  60. dest = a - digit;
  61. */
  62. int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
  63. assert_if_nil(dest, a);
  64. context.allocator = allocator;
  65. internal_clear_if_uninitialized(a) or_return;
  66. /*
  67. Grow destination as required.
  68. */
  69. grow(dest, a.used + 1) or_return;
  70. /*
  71. All parameters have been initialized.
  72. */
  73. return #force_inline internal_int_sub_digit(dest, a, digit);
  74. }
  75. /*
  76. dest = src / 2
  77. dest = src >> 1
  78. */
  79. int_halve :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
  80. assert_if_nil(dest, src);
  81. context.allocator = allocator;
  82. internal_clear_if_uninitialized(dest, src) or_return;
  83. /*
  84. Grow destination as required.
  85. */
  86. if dest != src { grow(dest, src.used + 1) or_return }
  87. return #force_inline internal_int_shr1(dest, src);
  88. }
  89. halve :: proc { int_halve, };
  90. shr1 :: halve;
  91. /*
  92. dest = src * 2
  93. dest = src << 1
  94. */
  95. int_double :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
  96. assert_if_nil(dest, src);
  97. context.allocator = allocator;
  98. internal_clear_if_uninitialized(dest, src) or_return;
  99. /*
  100. Grow destination as required.
  101. */
  102. if dest != src { grow(dest, src.used + 1) or_return; }
  103. return #force_inline internal_int_shl1(dest, src);
  104. }
  105. double :: proc { int_double, };
  106. shl1 :: double;
  107. /*
  108. Multiply by a DIGIT.
  109. */
  110. int_mul_digit :: proc(dest, src: ^Int, multiplier: DIGIT, allocator := context.allocator) -> (err: Error) {
  111. assert_if_nil(dest, src);
  112. context.allocator = allocator;
  113. internal_clear_if_uninitialized(src, dest) or_return;
  114. return #force_inline internal_int_mul_digit(dest, src, multiplier);
  115. }
  116. /*
  117. High level multiplication (handles sign).
  118. */
  119. int_mul :: proc(dest, src, multiplier: ^Int, allocator := context.allocator) -> (err: Error) {
  120. assert_if_nil(dest, src, multiplier);
  121. context.allocator = allocator;
  122. internal_clear_if_uninitialized(dest, src, multiplier) or_return;
  123. return #force_inline internal_int_mul(dest, src, multiplier);
  124. }
  125. mul :: proc { int_mul, int_mul_digit, };
  126. sqr :: proc(dest, src: ^Int) -> (err: Error) { return mul(dest, src, src); }
  127. /*
  128. divmod.
  129. Both the quotient and remainder are optional and may be passed a nil.
  130. */
  131. int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int, allocator := context.allocator) -> (err: Error) {
  132. context.allocator = allocator;
  133. /*
  134. Early out if neither of the results is wanted.
  135. */
  136. if quotient == nil && remainder == nil { return nil; }
  137. internal_clear_if_uninitialized(numerator, denominator) or_return;
  138. return #force_inline internal_divmod(quotient, remainder, numerator, denominator);
  139. }
  140. int_divmod_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT, allocator := context.allocator) -> (remainder: DIGIT, err: Error) {
  141. assert_if_nil(quotient, numerator);
  142. context.allocator = allocator;
  143. internal_clear_if_uninitialized(numerator) or_return;
  144. return #force_inline internal_divmod(quotient, numerator, denominator);
  145. }
  146. divmod :: proc{ int_divmod, int_divmod_digit, };
  147. int_div :: proc(quotient, numerator, denominator: ^Int, allocator := context.allocator) -> (err: Error) {
  148. assert_if_nil(quotient, numerator, denominator);
  149. context.allocator = allocator;
  150. internal_clear_if_uninitialized(numerator, denominator) or_return;
  151. return #force_inline internal_divmod(quotient, nil, numerator, denominator);
  152. }
  153. int_div_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT, allocator := context.allocator) -> (err: Error) {
  154. assert_if_nil(quotient, numerator);
  155. context.allocator = allocator;
  156. internal_clear_if_uninitialized(numerator) or_return;
  157. _ = #force_inline internal_divmod(quotient, numerator, denominator) or_return;
  158. return;
  159. }
  160. div :: proc { int_div, int_div_digit, };
  161. /*
  162. remainder = numerator % denominator.
  163. 0 <= remainder < denominator if denominator > 0
  164. denominator < remainder <= 0 if denominator < 0
  165. */
  166. int_mod :: proc(remainder, numerator, denominator: ^Int, allocator := context.allocator) -> (err: Error) {
  167. assert_if_nil(remainder, numerator, denominator);
  168. context.allocator = allocator;
  169. internal_clear_if_uninitialized(numerator, denominator) or_return;
  170. return #force_inline internal_int_mod(remainder, numerator, denominator);
  171. }
  172. int_mod_digit :: proc(numerator: ^Int, denominator: DIGIT, allocator := context.allocator) -> (remainder: DIGIT, err: Error) {
  173. return #force_inline internal_divmod(nil, numerator, denominator, allocator);
  174. }
  175. mod :: proc { int_mod, int_mod_digit, };
  176. /*
  177. remainder = (number + addend) % modulus.
  178. */
  179. int_addmod :: proc(remainder, number, addend, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
  180. assert_if_nil(remainder, number, addend);
  181. context.allocator = allocator;
  182. internal_clear_if_uninitialized(number, addend, modulus) or_return;
  183. return #force_inline internal_addmod(remainder, number, addend, modulus);
  184. }
  185. addmod :: proc { int_addmod, };
  186. /*
  187. remainder = (number - decrease) % modulus.
  188. */
  189. int_submod :: proc(remainder, number, decrease, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
  190. assert_if_nil(remainder, number, decrease);
  191. context.allocator = allocator;
  192. internal_clear_if_uninitialized(number, decrease, modulus) or_return;
  193. return #force_inline internal_submod(remainder, number, decrease, modulus);
  194. }
  195. submod :: proc { int_submod, };
  196. /*
  197. remainder = (number * multiplicand) % modulus.
  198. */
  199. int_mulmod :: proc(remainder, number, multiplicand, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
  200. assert_if_nil(remainder, number, multiplicand);
  201. context.allocator = allocator;
  202. internal_clear_if_uninitialized(number, multiplicand, modulus) or_return;
  203. return #force_inline internal_mulmod(remainder, number, multiplicand, modulus);
  204. }
  205. mulmod :: proc { int_mulmod, };
  206. /*
  207. remainder = (number * number) % modulus.
  208. */
  209. int_sqrmod :: proc(remainder, number, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
  210. assert_if_nil(remainder, number, modulus);
  211. context.allocator = allocator;
  212. internal_clear_if_uninitialized(number, modulus) or_return;
  213. return #force_inline internal_sqrmod(remainder, number, modulus);
  214. }
  215. sqrmod :: proc { int_sqrmod, };
  216. int_factorial :: proc(res: ^Int, n: int, allocator := context.allocator) -> (err: Error) {
  217. if n < 0 || n > FACTORIAL_MAX_N { return .Invalid_Argument; }
  218. assert_if_nil(res);
  219. return #force_inline internal_int_factorial(res, n, allocator);
  220. }
  221. factorial :: proc { int_factorial, };
  222. /*
  223. Number of ways to choose `k` items from `n` items.
  224. Also known as the binomial coefficient.
  225. TODO: Speed up.
  226. Could be done faster by reusing code from factorial and reusing the common "prefix" results for n!, k! and n-k!
  227. We know that n >= k, otherwise we early out with res = 0.
  228. So:
  229. n-k, keep result
  230. n, start from previous result
  231. k, start from previous result
  232. */
  233. int_choose_digit :: proc(res: ^Int, n, k: int, allocator := context.allocator) -> (err: Error) {
  234. assert_if_nil(res);
  235. context.allocator = allocator;
  236. if n < 0 || n > FACTORIAL_MAX_N { return .Invalid_Argument; }
  237. if k > n { return internal_zero(res); }
  238. /*
  239. res = n! / (k! * (n - k)!)
  240. */
  241. n_fac, k_fac, n_minus_k_fac := &Int{}, &Int{}, &Int{};
  242. defer internal_destroy(n_fac, k_fac, n_minus_k_fac);
  243. #force_inline internal_int_factorial(n_minus_k_fac, n - k) or_return;
  244. #force_inline internal_int_factorial(k_fac, k) or_return;
  245. #force_inline internal_mul(k_fac, k_fac, n_minus_k_fac) or_return;
  246. #force_inline internal_int_factorial(n_fac, n) or_return;
  247. #force_inline internal_div(res, n_fac, k_fac) or_return;
  248. return;
  249. }
  250. choose :: proc { int_choose_digit, };
  251. /*
  252. Function computing both GCD and (if target isn't `nil`) also LCM.
  253. */
  254. int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
  255. if res_gcd == nil && res_lcm == nil { return nil; }
  256. assert_if_nil(a, b);
  257. context.allocator = allocator;
  258. internal_clear_if_uninitialized(a, b) or_return;
  259. return #force_inline internal_int_gcd_lcm(res_gcd, res_lcm, a, b);
  260. }
  261. gcd_lcm :: proc { int_gcd_lcm, };
  262. /*
  263. Greatest Common Divisor.
  264. */
  265. int_gcd :: proc(res, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
  266. return #force_inline int_gcd_lcm(res, nil, a, b, allocator);
  267. }
  268. gcd :: proc { int_gcd, };
  269. /*
  270. Least Common Multiple.
  271. */
  272. int_lcm :: proc(res, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
  273. return #force_inline int_gcd_lcm(nil, res, a, b, allocator);
  274. }
  275. lcm :: proc { int_lcm, };
  276. /*
  277. remainder = numerator % (1 << bits)
  278. */
  279. int_mod_bits :: proc(remainder, numerator: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
  280. assert_if_nil(remainder, numerator);
  281. context.allocator = allocator;
  282. internal_clear_if_uninitialized(remainder, numerator) or_return;
  283. if bits < 0 { return .Invalid_Argument; }
  284. return #force_inline internal_int_mod_bits(remainder, numerator, bits);
  285. }
  286. mod_bits :: proc { int_mod_bits, };
  287. /*
  288. Logs and roots and such.
  289. */
  290. int_log :: proc(a: ^Int, base: DIGIT, allocator := context.allocator) -> (res: int, err: Error) {
  291. assert_if_nil(a);
  292. context.allocator = allocator;
  293. internal_clear_if_uninitialized(a) or_return;
  294. return #force_inline internal_int_log(a, base);
  295. }
  296. digit_log :: proc(a: DIGIT, base: DIGIT) -> (log: int, err: Error) {
  297. return #force_inline internal_digit_log(a, base);
  298. }
  299. log :: proc { int_log, digit_log, };
  300. /*
  301. Calculate `dest = base^power` using a square-multiply algorithm.
  302. */
  303. int_pow :: proc(dest, base: ^Int, power: int, allocator := context.allocator) -> (err: Error) {
  304. assert_if_nil(dest, base);
  305. context.allocator = allocator;
  306. internal_clear_if_uninitialized(dest, base) or_return;
  307. return #force_inline internal_int_pow(dest, base, power);
  308. }
  309. /*
  310. Calculate `dest = base^power` using a square-multiply algorithm.
  311. */
  312. int_pow_int :: proc(dest: ^Int, base, power: int, allocator := context.allocator) -> (err: Error) {
  313. assert_if_nil(dest);
  314. return #force_inline internal_pow(dest, base, power, allocator);
  315. }
  316. pow :: proc { int_pow, int_pow_int, small_pow, };
  317. exp :: pow;
  318. small_pow :: proc(base: _WORD, exponent: _WORD) -> (result: _WORD) {
  319. return #force_inline internal_small_pow(base, exponent);
  320. }
  321. /*
  322. This function is less generic than `root_n`, simpler and faster.
  323. */
  324. int_sqrt :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
  325. assert_if_nil(dest, src);
  326. context.allocator = allocator;
  327. internal_clear_if_uninitialized(dest, src) or_return;
  328. return #force_inline internal_int_sqrt(dest, src);
  329. }
  330. sqrt :: proc { int_sqrt, };
  331. /*
  332. Find the nth root of an Integer.
  333. Result found such that `(dest)**n <= src` and `(dest+1)**n > src`
  334. This algorithm uses Newton's approximation `x[i+1] = x[i] - f(x[i])/f'(x[i])`,
  335. which will find the root in `log(n)` time where each step involves a fair bit.
  336. */
  337. int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.allocator) -> (err: Error) {
  338. context.allocator = allocator;
  339. /*
  340. Fast path for n == 2.
  341. */
  342. if n == 2 { return sqrt(dest, src); }
  343. assert_if_nil(dest, src);
  344. /*
  345. Initialize dest + src if needed.
  346. */
  347. internal_clear_if_uninitialized(dest, src) or_return;
  348. return #force_inline internal_int_root_n(dest, src, n);
  349. }
  350. root_n :: proc { int_root_n, };
  351. /*
  352. Comparison routines.
  353. */
  354. int_is_initialized :: proc(a: ^Int) -> bool {
  355. if a == nil { return false; }
  356. return #force_inline internal_int_is_initialized(a);
  357. }
  358. int_is_zero :: proc(a: ^Int, allocator := context.allocator) -> (zero: bool, err: Error) {
  359. assert_if_nil(a);
  360. context.allocator = allocator;
  361. internal_clear_if_uninitialized(a) or_return;
  362. return #force_inline internal_is_zero(a), nil;
  363. }
  364. int_is_positive :: proc(a: ^Int, allocator := context.allocator) -> (positive: bool, err: Error) {
  365. assert_if_nil(a);
  366. context.allocator = allocator;
  367. internal_clear_if_uninitialized(a) or_return;
  368. return #force_inline internal_is_positive(a), nil;
  369. }
  370. int_is_negative :: proc(a: ^Int, allocator := context.allocator) -> (negative: bool, err: Error) {
  371. assert_if_nil(a);
  372. context.allocator = allocator;
  373. internal_clear_if_uninitialized(a) or_return;
  374. return #force_inline internal_is_negative(a), nil;
  375. }
  376. int_is_even :: proc(a: ^Int, allocator := context.allocator) -> (even: bool, err: Error) {
  377. assert_if_nil(a);
  378. context.allocator = allocator;
  379. internal_clear_if_uninitialized(a) or_return;
  380. return #force_inline internal_is_even(a), nil;
  381. }
  382. int_is_odd :: proc(a: ^Int, allocator := context.allocator) -> (odd: bool, err: Error) {
  383. assert_if_nil(a);
  384. context.allocator = allocator;
  385. internal_clear_if_uninitialized(a) or_return;
  386. return #force_inline internal_is_odd(a), nil;
  387. }
  388. platform_int_is_power_of_two :: #force_inline proc(a: int) -> bool {
  389. return ((a) != 0) && (((a) & ((a) - 1)) == 0);
  390. }
  391. int_is_power_of_two :: proc(a: ^Int, allocator := context.allocator) -> (res: bool, err: Error) {
  392. assert_if_nil(a);
  393. context.allocator = allocator;
  394. internal_clear_if_uninitialized(a) or_return;
  395. return #force_inline internal_is_power_of_two(a), nil;
  396. }
  397. /*
  398. Compare two `Int`s, signed.
  399. */
  400. int_compare :: proc(a, b: ^Int, allocator := context.allocator) -> (comparison: int, err: Error) {
  401. assert_if_nil(a, b);
  402. context.allocator = allocator;
  403. internal_clear_if_uninitialized(a, b) or_return;
  404. return #force_inline internal_cmp(a, b), nil;
  405. }
  406. int_cmp :: int_compare;
  407. /*
  408. Compare an `Int` to an unsigned number upto the size of the backing type.
  409. */
  410. int_compare_digit :: proc(a: ^Int, b: DIGIT, allocator := context.allocator) -> (comparison: int, err: Error) {
  411. assert_if_nil(a);
  412. context.allocator = allocator;
  413. internal_clear_if_uninitialized(a) or_return;
  414. return #force_inline internal_cmp_digit(a, b), nil;
  415. }
  416. int_cmp_digit :: int_compare_digit;
  417. /*
  418. Compare the magnitude of two `Int`s, unsigned.
  419. */
  420. int_compare_magnitude :: proc(a, b: ^Int, allocator := context.allocator) -> (res: int, err: Error) {
  421. assert_if_nil(a, b);
  422. context.allocator = allocator;
  423. internal_clear_if_uninitialized(a, b) or_return;
  424. return #force_inline internal_cmp_mag(a, b), nil;
  425. }
  426. /*
  427. Check if remainders are possible squares - fast exclude non-squares.
  428. Returns `true` if `a` is a square, `false` if not.
  429. Assumes `a` not to be `nil` and to have been initialized.
  430. */
  431. int_is_square :: proc(a: ^Int, allocator := context.allocator) -> (square: bool, err: Error) {
  432. assert_if_nil(a);
  433. context.allocator = allocator;
  434. internal_clear_if_uninitialized(a) or_return;
  435. return #force_inline internal_int_is_square(a);
  436. }