Previously, we saw the bigints library. There, I mentioned the following:
"I know that in D Lang, BigInt performance is optimized for numbers below ~1000 decimal digits. I'm not sure but I think it's similar in Nim too."
I made some tests and yes, the bigints library is slow if you want to work with really HUGE numbers. However, if your big integer consists of just a few thousands of digits, bigints is perfectly fine.
Exercise
Let's solve this exercise in various ways. In short: determine the value of 2136,279,841-1 . We know that this number consists of 41,024,320 digits. For the sake of simplicity, our programs will just print the number of digits, not the entire number.
All tests were executed on my desktop computer that has an Intel Core i7-8700 CPU @ 3.20GHz.
(1) Pure Python solution ✅
import sys
sys.set_int_max_str_digits(41_100_000)
PRIME = 2**136_279_841 - 1
print(len(str(PRIME))) # 41024320
Runtime: 27.64 seconds.
(2) Nim solution using the bigints library ❌
import bigints
proc main() =
let
base = 2.initBigInt
exponent = 136_279_841
number = base.pow(exponent) - 1.initBigInt
echo len($number) # ??? was too slow
main()
I let the program run for 181 minutes (3 hours) and it still didn't finish, so I stopped it. The process didn't consume any memory (htop reported 0%), only a CPU core was at 100%.
(3) Nim program calling Python ✅
Previously, we saw here that it's possible to call Python from Nim.
helper.py :
def myeval(code):
return eval(code)
main.nim :
import std/os
import pkg/nimpy # 3rd-party library
proc main() =
let sys = pyImport("sys")
discard sys.set_int_max_str_digits(41_100_000)
discard sys.path.insert(0, getAppDir()) # directory of the running binary
let
helper = pyImport("helper")
result = helper.myeval("len(str(2 ** 136_279_841 - 1))").to(int)
echo result # 41024320
main()
Runtime: 27.54 seconds. Same as the pure Python solution. Well, it's not surprising since we called Python from Nim and Python did all the hard work for us.
Conclusion
bigints is fine if the big numbers contain just a few thousands of digits. But don't believe me, test your code, do some experiments.
- If you want to work with really HUGE numbers in Nim, you can pass the job to Python. Interestingly, Python's BigInt implementation is surprisingly fast!
Fun fact 🌌
In the observable universe, there are about 10^80 atoms. This number looks like this:
>>> 10 ** 80
100000000000000000000000000000000000000000000000000000000000000000000000000000000
>>>
I think we can safely say that any number larger than this is just too big :)