decimo

Benchmarks

2026-10-12 · main ddd66d1 · arm64, macOS-26.6.2-arm64-arm-64bit-Mach-O

Mojo 1.1.0 (8189361e) · CPython 3.14.6 · libmpdec 4.0.1 and GMP 6.3.0, both linked from C

Each figure is the minimum over several rounds, on an idle machine. Regenerate with pixi run benchdoc.

BigDecimal

Operands of digits decimal digits at working precision, so that precision grows with the operands. libmpdec is the C library behind CPython’s decimal, timed without the interpreter. round drops the low half of the operand; parse builds the value from its string.

Verified this run: decimo and libmpdec produce the same 2000-digit product from the same 1000-digit operands.

Digits / precision Operation decimo libmpdec   CPython decimal  
9 / 28 add 11.1 ns 30.4 ns 2.73× faster 47.7 ns 4.28× faster
9 / 28 subtract 12.0 ns 31.5 ns 2.62× faster 47.3 ns 3.93× faster
9 / 28 multiply 13.2 ns 28.8 ns 2.18× faster 43.8 ns 3.32× faster
9 / 28 divide 56.3 ns 53.7 ns parity 69.6 ns 1.24× faster
9 / 28 round 8.7 ns 32.4 ns 3.71× faster 69.7 ns 8.01× faster
9 / 28 parse 52.4 ns 41.3 ns 1.27× slower 83.1 ns 1.58× faster
1,000 / 1,000 add 50.0 ns 121.4 ns 2.43× faster 109.0 ns 2.18× faster
1,000 / 1,000 subtract 52.1 ns 98.2 ns 1.88× faster 84.0 ns 1.61× faster
1,000 / 1,000 multiply 1.04 µs 8.94 µs 8.57× faster 8.93 µs 8.56× faster
1,000 / 1,000 divide 5.75 µs 14.33 µs 2.49× faster 14.21 µs 2.47× faster
1,000 / 1,000 round 55.0 ns 96.2 ns 1.75× faster 117.7 ns 2.14× faster
1,000 / 1,000 parse 1.26 µs 1.63 µs 1.30× faster 1.72 µs 1.37× faster
100,000 / 100,000 add 2.50 µs 6.00 µs 2.40× faster 5.94 µs 2.38× faster
100,000 / 100,000 subtract 2.85 µs 3.75 µs 1.32× faster 3.98 µs 1.39× faster
100,000 / 100,000 multiply 1.82 ms 2.92 ms 1.60× faster 2.93 ms 1.61× faster
100,000 / 100,000 divide 4.63 ms 14.27 ms 3.08× faster 14.25 ms 3.08× faster
100,000 / 100,000 round 2.75 µs 4.25 µs 1.55× faster 4.80 µs 1.75× faster
100,000 / 100,000 parse 115.15 µs 157.30 µs 1.37× faster 192.30 µs 1.67× faster
1,000,000 / 1,000,000 add 24.50 µs 58.50 µs 2.39× faster 58.88 µs 2.40× faster
1,000,000 / 1,000,000 subtract 28.50 µs 35.50 µs 1.25× faster 35.50 µs 1.25× faster
1,000,000 / 1,000,000 multiply 25.54 ms 30.51 ms 1.19× faster 30.89 ms 1.21× faster
1,000,000 / 1,000,000 divide 123.85 ms 161.69 ms 1.31× faster 162.57 ms 1.31× faster
1,000,000 / 1,000,000 round 27.50 µs 41.50 µs 1.51× faster 41.06 µs 1.49× faster
1,000,000 / 1,000,000 parse 1.19 ms 1.57 ms 1.32× faster 1.91 ms 1.61× faster

sqrt, exp, ln, power

A fixed set, chosen before the results were seen. 2.3456789, and ** 1.5 for power. 100 000 digits is left out because mpd_exp needs 82 seconds there and mpd_ln 239 seconds.

Precision Operation decimo libmpdec  
28 sqrt 406.4 ns 901.3 ns 2.22× faster
28 exp 2.19 µs 4.74 µs 2.17× faster
28 ln 2.40 µs 13.29 µs 5.55× faster
28 power 6.63 µs 37.42 µs 5.64× faster
100 sqrt 2.15 µs 4.67 µs 2.18× faster
100 exp 5.98 µs 16.49 µs 2.76× faster
100 ln 13.43 µs 43.05 µs 3.20× faster
100 power 17.17 µs 84.08 µs 4.90× faster
1,000 sqrt 21.13 µs 228.48 µs 10.81× faster
1,000 exp 173.00 µs 4.76 ms 27.54× faster
1,000 ln 1.18 ms 5.91 ms 4.99× faster
1,000 power 301.94 µs 11.75 ms 38.92× faster
10,000 sqrt 552.00 µs 23.72 ms 42.96× faster
10,000 exp 24.94 ms 1.425 s 57.13× faster
10,000 ln 486.45 ms 3.372 s 6.93× faster
10,000 power 47.43 ms 4.827 s 101.76× faster

BigInt against GMP and CPython’s int

GMP is the reference implementation for big integers and the harder opponent, timed in C. CPython’s integers can only be reached through the interpreter, so those include its overhead — read the large sizes as the real ones. Division is 2n-by-n; two operands of the same width would give a one-digit quotient and measure nothing.

An mpz_t always lives on the heap. Adding two 100-digit values costs GMP 19.9 ns into a fresh result against 5.9 ns into a reused one, so most of it is malloc and free. decimo keeps small values inside the struct, which is why it leads at the small end and trails at the large one, where the algorithm is all that is left.

Digits Operation decimo GMP   CPython int  
10 add 5.8 ns 15.5 ns 2.66× faster 22.7 ns 3.89× faster
10 multiply 7.4 ns 15.9 ns 2.16× faster 29.8 ns 4.05× faster
10 floor divide 11.1 ns 24.2 ns 2.18× faster 50.9 ns 4.59× faster
10 sqrt 2.8 ns 18.9 ns 6.88× faster 30.8 ns 11.17× faster
100 add 10.4 ns 19.9 ns 1.90× faster 27.9 ns 2.67× faster
100 multiply 44.0 ns 31.1 ns 1.41× slower 118.4 ns 2.69× faster
100 floor divide 122.3 ns 82.9 ns 1.48× slower 334.3 ns 2.73× faster
100 sqrt 122.7 ns 58.6 ns 2.09× slower 323.0 ns 2.63× faster
1,000 add 31.4 ns 32.8 ns parity 94.1 ns 3.00× faster
1,000 multiply 1.05 µs 630.2 ns 1.66× slower 5.67 µs 5.42× faster
1,000 floor divide 1.84 µs 1.27 µs 1.45× slower 13.21 µs 7.16× faster
1,000 sqrt 1.55 µs 367.0 ns 4.22× slower 4.61 µs 2.98× faster
10,000 add 165.0 ns 150.0 ns 1.10× slower 831.5 ns 5.04× faster
10,000 multiply 45.10 µs 19.90 µs 2.27× slower 276.22 µs 6.12× faster
10,000 floor divide 90.20 µs 51.71 µs 1.74× slower 567.09 µs 6.29× faster
10,000 sqrt 23.84 µs 8.56 µs 2.79× slower 277.55 µs 11.64× faster
100,000 add 1.70 µs 1.35 µs 1.26× slower 8.01 µs 4.71× faster
100,000 multiply 1.26 ms 442.45 µs 2.84× slower 9.03 ms 7.17× faster
100,000 floor divide 3.82 ms 1.12 ms 3.42× slower 18.56 ms 4.86× faster
100,000 sqrt 980.15 µs 302.70 µs 3.24× slower 8.58 ms 8.75× faster
1,000,000 add 17.50 µs 13.00 µs 1.35× slower 87.73 µs 5.01× faster
1,000,000 multiply 25.28 ms 6.27 ms 4.03× slower 380.13 ms 15.03× faster
1,000,000 floor divide 107.09 ms 16.47 ms 6.50× slower 765.47 ms 7.15× faster
1,000,000 sqrt 31.89 ms 5.89 ms 5.41× slower 350.23 ms 10.98× faster

pi()

Each measurement in a fresh process, since mpmath and MPFR cache the constant. Includes conversion to a decimal string, for every library.

The two decimo columns compute the same series through the same integer code and differ only in where the digits end up; BigFloat is asked for the computation its own cache would have missed on, so that it is measured cold like the rest.

Digits decimo (BigDecimal) decimo (BigFloat) mpmath + GMP MPFR mpmath (pure Python)
100 2.45 µs 3.10 µs 43.12 µs 45.04 µs 29.38 µs
1,000 22.93 µs 23.75 µs 105.96 µs 65.71 µs 158.83 µs
10,000 712.55 µs 713.50 µs 871.21 µs 727.25 µs 5.89 ms
100,000 26.69 ms 26.45 ms 15.43 ms 23.16 ms 183.29 ms
1,000,000 715.99 ms 712.10 ms 267.82 ms 421.13 ms 8.430 s