It seems that it is the symbolic evaluation that is the culprit. More particularly, as @CarlWoll pointed out, it is Abs
that is the problem:
{res = Tanh[Power[E, Power[Pi, E]]]; // MaxMemoryUsed // AbsoluteTiming, res}
{res = Abs[Tanh[Power[E, Power[Pi, E]]]]; // MaxMemoryUsed // AbsoluteTiming, res}
(*
{{0.00004, 672}, Tanh[E^π^E]}
{{2.84414, 2046458944}, Tanh[E^π^E]}
*)
My guess is that automatic, internal evaluation/simplification rules are being tried. It's quite possible that numeric routines are being used internally to determine whether the absolute value can be simplified, but I'm not sure how to see that, since the internals appear to be hidden. In fact, they appear to be hidden from the MemoryConstrained[]
environment. This is not completely surprising, since some rules, such as for Plus
, are applied before the standard evaluation procedure. It is done for the sake of efficiency. This seems to be an edge case where the "efficiency" might be called into question.
MaxMemoryUsed[
res = MemoryConstrained[Abs[Tanh[Power[E, Power[Pi, E]]]],
65536]]
res
(*
2046458968
$Aborted
*)
If the symbolic evaluation happens first, then we see that numericizing it uses little memory. Interestingly, little memory is also used if you prevent symbolic evaluation with Unevaluated
.
expr = Abs[Tanh[Power[E, Power[Pi, E]]]];
MaxMemoryUsed[res = MemoryConstrained[N@expr, 65536]]
res
(*
192
1.
*)
MaxMemoryUsed[
res = MemoryConstrained[N[Unevaluated@Abs[Tanh[Power[E, Power[Pi, E]]]]],
65536]]
res
(*
192
1.
*)
OTOH, evaluating expr
with arbitrary precision ("bignum") does use about as much memory as the symbolic evaluation. It is also not constrained by the memory constraint, at least not until some 2GB of memory have been used. This coincidence suggests bignums might underlie the symbolic evaluation.
MaxMemoryUsed[res = MemoryConstrained[N[expr, 10], 65536]]
res
Divide::infy: Infinite expression 2/0.*10^2147483648 encountered.
(*
2046481544
$Aborted
*)
Interestingly, setting $MaxExtraPrecision
to 0
prevents the huge use of memory. It also prevents a useful result.
Block[{$MaxExtraPrecision = 0},
MaxMemoryUsed[res = MemoryConstrained[N[expr, 10], 65536]]
]
res
Divide::infy: Infinite expression 2/0.*10^2147483648 encountered.
(*
13136
ComplexInfinity
*)
However, setting $MaxExtraPrecision
to 0
does not help with the symbolic evaluation. The limit could be reset internally. One cannot tell. (Indeed, I tried to observe it with Dynamic@{$MaxExtraPrecision, Clock[]}
, but dynamic updating hangs while the symbolic expression is being evaluated. That seems significant, but I don't know exactly what it signifies.)
Block[{$MaxExtraPrecision = 0},
MaxMemoryUsed[
res = MemoryConstrained[N[Abs[Tanh[Power[E, Power[Pi, E]]]]], 65536]]
]
res
(*
2046458992
$Aborted
*)
N[Tanh[Pi^Cosh[Cosh[2]]], 32]
This one immediately request 18 GB of memory, so be prepared to kill Kernel. Only method to prevent this is to replace 2 with numerical value. $\endgroup$Internal`$MaxExponent
from defaultInfinity
to some finite value. Same forUnderflow
, e.g.Internal`$MinExponent=-1024
. Information from Technical Support. $\endgroup$