Ruby out performs Crystal significantly on this numerical algorithm

This is what Common Lisp has done since the 80s. Variables can hold anything, but you can also add type restrictions all over the place to speed things up or get certain types of behavior. Of course it’s up to the implementation to actually respect these declarations, but most high performance ones seem to. But it’s also a double-edged sword, because getting code highly tuned for performance means extra verbosity, and it can mean extra steps and cognition on the part of the programmer when messing with code that expects overflows. I’ve encountered this plenty of times in the past. The compiler also has to be much more complex and smart about how it generates code, since it has to add a bunch of extra checks at runtime for overflows and such.

Numbers will also automatically upcast to a big num as-needed in Common Lisp, transparently, so maybe that’s where the Ruby devs got the idea. I believe Python does the same, but I haven’t used Python since 3.0 was still new, so I could be wrong. Again, double-edged sword. It can be really nice sometimes, but it can also be a pain when you want to do lower-level stuff, because sometimes, you want a number to stay an exact type. Some use cases just benefit from more strictness, some cases require overflows to be a thing, and some cases just need to be more aware of memory usage. Not to mention the benefits that static typing brings to finding bugs…

EDIT: for completeness sake, I ran the code on two separate and very different machines as well.

Machine 1

CPU: 10-core Intel Core i9-10850K (-MT MCP-) speed/min/max: 3600/800/5200 MHz
Kernel: 6.2.9 x86_64 Up: 6d 20h 46m Mem: 4439.0/64245.5 MiB (6.9%)
Storage: 4.09 TiB (24.0% used) Procs: 346 Shell: Bash inxi: 3.3.12

Ruby: 0.924378318
Crystal (mpz_powm_sec, crystal build --release --no-debug): 1.715
Crystal (mpz_powm, crystal build --release --no-debug): 0.924

Machine 2

CPU: dual core AMD Ryzen 3 3200U with Radeon Vega Mobile Gfx (-MT MCP-)
speed/min/max: 2114/1400/2600 MHz Kernel: 6.2.9 x86_64 Up: 6d 13h 50m
Mem: 3326.4/9870.8 MiB (33.7%) Storage: 494.65 GiB (30.2% used) Procs: 264
Shell: Bash inxi: 3.3.12

Ruby: 1.639495515
Crystal (mpz_powm_sec, crystal build --release --no-debug): 2.668
Crystal (mpz_powm, crystal build --release --no-debug): 1.532

Ruby is 3.0.6 on both machines.