The limit for big integers used to be limited by RAM. There has always existed a limit, but in practice one would run out of RAM before reaching the limit for bigints. That is no longer the case, especially when running on a 64-bit computer.
The current limit is about 4 MBits or 4,194,240 bits. The value of BIG_ARITY_MAX
should be multiplied by the number of bits in a machine word (32 or 64) to obtain the maximum number of bits.
The limit used to be higher, but we lowered it in Optimize binary_to_integer/1 and friends by bjorng · Pull Request #7426 · erlang/otp · GitHub to ensure that operations on big integers would always finish in a reasonable time.
Just for fun, I did a micro-optimization of your power/2
function:
power(Base, Exp) when is_number(Base), is_integer(Exp),
0 =< Exp, Exp =< 1 bsl 24 ->
{ok, do_power(Base, Exp)};
power(_Base, _Exp) ->
{error, nil}.
Guard tests can help the JIT to emit better native code. For example, when the exponent is known to be a small integer, the div
and rem
operations can be simplified. Without the guard tests, the div
operation would look like so:
# i_int_div_jIssd
mov x2, 47
and x13, x26, 15
cmp x13, 15
b.ne L70
# optimized div by replacing with right shift
orr x0, x13, x26, 1
b L71
L70:
mov x1, x26
mov x3, 4347964816
bl L73
L71:
mov x27, x0
The first operand might not be a small integer, so the JIT needs to emit code to handle that. With the guards tests, the code for the div
operation can be simplified to:
# i_int_div_jIssd
# skipped test for smalls operands and overflow
mov x13, 15
# optimized div by replacing with right shift
orr x26, x13, x26, 1
The runtime of power/2
is dominated by the multiplication of big integers, so the actual reduction in runtime with the guard tests is minuscule.