Python big integer vs. Julia big integer arithmetic

Here’s how one runs it from an interactive read-eval-print command loop in Maxima:

(%i14) block([modulus:102], rat(3)^100000);
Warning: assigning 102, a non-prime, to ‘modulus’
(%o14)/R/ 69

I have never personally run Maxima from a bash or windows command prompt, but I understand that it is possible by (essentially) sneaking stuff into the file that Maxima uses when it starts up (maxima.bat). In which case outputting to std might require using “print” or “format”… something like
command line prompt maxima ? block([modulus:102], print(rat(3)^100000), exit());

Doing arithmetic modulo 102 which has factors 2, 3, 17 results in a warning,as shown above. I suppose that message would go to stdout or stderr if that is available, from a command line.
If you really want to do bignum arithmetic, any Common Lisp will support that, and may use the highly-tuned GMP library available for different architectures.
A reasonable Lisp program for powermod(n,power,modulus) would be a few lines of code, using about log_2(power) multiplies and remainders.

In some Lisps, a newly-defined program is run interpretively but can be compiled on request. In other Lisps it is immediately compiled. Lisps allow, but do not require, type declarations and hints for optimization (like in-line expansion).
I hope that some of the lessons from Common Lisp design and implementation have been considered by people implementing Julia.

~ $ time maxima --very-quiet --batch-string=''

real	0m0.089s
user	0m0.079s
sys	0m0.017s
~ $ time julia -e ''

real	0m0.438s
user	0m0.421s
sys	0m0.140s
~ $ time maxima --very-quiet --batch-string='block([modulus:102], print(rat(3)^10000000000000), exit());'

block([modulus:102],print(rat(3)^10000000000000),exit())
warning: assigning 102, a non-prime, to 'modulus'
69 
                                    exit()

real	0m0.092s
user	0m0.077s
sys	0m0.022s
~ $ time julia -e 'println( powermod(3, 10000000000000, 102) )'
69

real	0m0.545s
user	0m0.552s
sys	0m0.116s

If I see it the right way Julia could spawn Maxima on this one instead of itself to get the result faster instead of calculating it by itself - or is there something wrong with this conclusion?

Spawning julia is slow, so spawning Julia to do a single small arithmetic calculation will be inefficient. If that’s how you want to use Julia, you are better off with bc.

That’s not how other people typically use, Julia, however—or, for that matter, how they use most other programming languages, including Python. They spawn Julia (or whatever program) once and then do lots of calculations. For this pattern, tools like @btime and timeit are more useful and revealing, because they measure the marginal cost of a single small operation.

5 Likes
~$ time julia -E 'sum(i for i in 1:2)'
3
user=0.49s system=0.08s cpu=390% total=0.144

Wow, Julia took 0.4s to add two numbers. That means if I ask it to add together 1000 numbers it should take ~8 minutes.

~$ time julia -E 'sum(i for i in 1:1000)'
500500
user=0.47s system=0.04s cpu=443% total=0.115

Huh, weird. It’s almost like time isn’t measuring the addition operation :upside_down_face:

9 Likes

Oh, and just for reference:

~$ time juliaclient -E 'powermod(3, 10000000000000, 102)'
69
user=0.00s system=0.00s cpu=0% total=0.073

where juliaclient is a tool that re-uses a Julia session I wrote. This is much better than time julia ..., and @btime is better again.

2 Likes

May you provide a code example which demonstrates that Julia will be faster considering the default use case you mention compared to Maxima? Just mentioning that the demonstrated timing is not representative would be much more expressive along with providing evidence, wouldn’t it?

Sorry … I have trouble with both, Julia and Maxima which are new to me, failing on constructing appropriate examples of code myself.

Then you would first spawn Julia, then spawn Maxima, and then Maxima would calculate powermod more slowly than Julia does (?).

That does not seem optimal.

1 Like

If I see it right Julia spawning Maxima and getting the result from Maxima will be in the total time still faster then letting Julia itself calculating it … or have I overseen something comparing the timings?

How would

spawning Julia + spawning Maxima + calculating powermod in Maxima

be faster than

spawning Julia + calculating powermod in Julia
?

Would Julia compilation of powermod be that slow? Julia should be faster than Maxima, no?

From what I can see in the timings Julia time for performing the calculation minus the time for spawning Julia is in the order of 0.1 second, where time for performing the calculation including spawning Maxima is not much but still slightly less than that. And comparing the pure calculation time suggests that Maximal is an order of magnitude faster on this one. Or is there anything I have erroneously overseen here?

*cough

3 Likes

Yes, this is just extremely noisy, and likely to be off by orders of magnitude.

2 Likes
~ $ time juliaclient -E 'powermod(3, 10000000000000, 102)'
juliaclient: command not found

real	0m0.669s
user	0m0.149s
sys	0m0.031s

Sorry, I am not able to reproduce your result … any hints towards the reason for this?

yes:

1 Like

First of all, almost none of Maxima is being used. A Common Lisp system and one program could do this task. I think this program would work…
(defun powermod(n pow mod)
(cond((= pow 0) 1)
((= pow 1)(rem n mod))
((evenp pow)(powermod (rem (* n n) mod) (ash pow -1)mod))
(t (rem (* n (powermod n (1- pow) mod)) mod))))
[sorry, the indentation was removed by “discourse”.]

If you want to leave a Maxima or a Lisp client sitting around, that would eliminate most of the start-up time. It works for me.
It seems to me that the routine “Oh, I just wrote a program in language X. I’ll have to start up an X-compiler-environment to run it” is turning the clock back 60 years, to pre-timesharing computing. It helps that computers are so much faster, and we don’t use punched cards… but
read-eval-print loops and interactive computing has made me more productive, I think. If we are losing that, and today programmers edit some text interactively, and then essentially fire up a batch processing system… maybe start a browser, download an app on a phone, connect to a cloud…maybe use some elaborate deployment strategy… doesn’t seem like much fun. Oh well, times change.
RJF

2 Likes

Surely. Most of the functions you call in julia will be compiled the first time you call it. This goes for powermod, and for run, which you would use to spawn maxima. After powermod has been compiled, I’ve shown you elsewhere that the actual runtime for powermod is around 200 nanoseconds (it’s really just a few hundred cpu cycles). After run has been compiled (it might take longer than to compile powermod) it will take some milliseconds to start maxima.
So using maxima to perform this calculation from julia would most likely take longer time.

Now, normally you don’t do just a single calculation. If you want to do, say, one million, it will take milliseconds with julia, and 10 minutes or so if you spawn maxima a million times.

1 Like

I should probably mention since it won’t be clear, this comes from installing GitHub - tecosaur/DaemonConductor.jl: Run many times, compile once. and running DaemonConductor.install() (linux only).

The result is that for things Julia does quickly, most of the time will actually be taken up by the socket initialisation, which takes a few ms.

~$ hyperfine -N "juliaclient -E 'powermod(3, 10000000000000, 102)'"
Benchmark 1: juliaclient -E 'powermod(3, 10000000000000, 102)'
  Time (mean ± σ):       5.3 ms ±   6.2 ms    [User: 1.3 ms, System: 1.0 ms]
  Range (min … max):     4.3 ms …  84.3 ms    172 runs

This is an unfair comparison. Let’s start maxima once for the million times too to arrive at a fair one … Any code for such comparison?

@oOosys people already told you Julia is slow to start-up, sometimes compile, and fast to execute…that’s really all of it

5 Likes

Wrap your code in triple backticks to get proper formatting and monospace font.

Using a REPL is the idiomatic way to use Julia. Starting Julia from the command line to run I small piece of code is contrary to that, I didn’t catch why the OP wants to do it.

2 Likes