Re: Inconsistencies and special treatment of %e vs. %pi (and numer, %enumer mess)

Stavros Macrakis <[email protected]> Tue, 9 Jun 2026 14:56:52 -0400
Newsgroups gmane.comp.mathematics.maxima.general
Message-ID <CACLVabUHQt7i7ZYLT_VUzpby-78-kFvcie8-DURyaeQD_TbZSg@mail.gmail.com>
My guess is that the purpose of special-casing *%e^x* is that people think
of it as a notation for the function *exp(x)*. It is ever desirable to
rewrite *%e^x* as *2.718^x *unless *x* is purely numeric? There is nothing
analogous for *%pi *or other constants.

By the way, I see that *bfloat(...)* preserves symbolic *%e *when it is the
base of an exponentiation, because it does not work via simplification.
*float(...)*, on the other hand, does not preserve it.

I'll also note that *xxx,float == ex(xxx,float)* is equivalent to binding
*float:true*, whereas *xxx,bfloat == ex(xxx,bfloat)* is equivalent to
*bfloat(xxx)*... which in most cases results in similar results. But I
wouldn't dare to make them consistent because I don't know how much user
code it would break.

On Tue, Jun 9, 2026 at 1:10 PM David Scherfgen via Maxima-discuss <
[email protected]> wrote:

> Dear all,
>
> First, please excuse the rather long mail. If it's too long for you to
> read it completely, please read only the example codes that show the
> problem, and then skip to "TLDR / Way forward?".
>
> While digging into the simplifier and evaluator, I noticed that %e
> receives an almost ridiculous amount of special treatment compared to,
> e.g., %pi.
>
>    - %e is the *only atom* that can be simplified to something different
>    by the simplifier: If the global flags numer and %enumer are both true,
>    %e is simplified to its numerical value. It's likely that there is
>    code at other places that (wrongly, but understandably) assumes that atoms
>    are inherently simplified and don't need to go through the simplifier,
>    which would cause bugs. The other constants like %pi aren't handled by
>    the simplifier.
>    - There is some really ugly hackery going on in the evaluator that
>    explicitly targets %e in conjunction with numer/%enumer.
>
> The global flag %enumer = false (default) is supposed to "protect" %e
> from becoming a float when numer is true in cases of %e^x, where x is
> symbolic. At first glance, this works:
>
> (%i1) %e^x + sin(%e), numer;
> (%o1) %e^x + 0.41078129050290885
>
> Here, %e^x is correctly left alone, while sin(%e) becomes a float.
> The following also works:
>
> (%i2) sin(%e^x), numer;
> (%o2) sin(%e^x)
>
> But now let's resimplify that with numer on (classically, this would be
> done with expand(%, 0, 0), but we have resimplify now):
>
> (%i3) resimplify(%), numer;
> (%o3) sin(2.718281828459045^x)
>
> Oops! Now %e became a float, even though it's the base with a symbolic
> exponent, which is exactly the case where it should have been "protected"
> by %enumer = false.
>
> What's going on here?
>
>    - When typing just sin(%e^x), numer in the REPL, the evaluator starts
>    by simplifying the leaves %e and x, then builds and simplifies %e^x,
>    and finally builds and simplifies sin(%e^x). It works its way from the
>    leaves to the root, *bottom-up*.
>    - But when we resimplify, all simp tags are stripped from the entire
>    expression, and the simplifier is called on the root, working in a
>    *top-down* fashion. The sin simplifier calls simpcheck on its
>    argument, which, due to a momentous commit described here
>    <https://sourceforge.net/p/maxima/bugs/123/>, dynamically binds %enumer
>    to numer (true). This "infects" the entire sub-tree, and all instances
>    of %e inside it are converted to a float by the simplifier, no matter
>    what.
>
> So we get a different outcome depending on whether we work bottom-up or
> top-down. It doesn't end there, though. Here's an example that shows how
> %e and %pi are treated in a fundamentally different way:
>
> /* OK, both become floats: */
> (%i4) %pi*y + %e*x, numer;
> (%o4) 3.141592653589793*y + 2.718281828459045*x
>
> /* Not OK, %e stays symbolic: */
> (%i5) [%pi, %e], numer;
> (%o5) [3.141592653589793, %e]
>
> /* If we write -%e instead of %e, it becomes a float: */
> (%i6) [%pi, -%e], numer;
> (%o6) [3.141592653589793, -2.718281828459045]
>
> *TLDR / Way forward?*
>
>    - In summary, the handling of %e, numer and %enumer is an inconsistent
>    mess that needs lots of special cases in the code, and it doesn't even work
>    as intended.
>    - I think that, as much as possible, this extra treatment of %e should
>    go away. It would make the code simpler and the results more consistent.
>    - The idea behind %enumer = false isn't bad, but there's a fundamental
>    problem with the way it's supposed to work: When working bottom-up, we
>    first see %e, but *we don't have the context*, i.e. we don't know
>    where that %e sits inside a parent expression (if any).
>       - Is it the %e in %e^x? Then it must not become a float.
>       - Is it any %e in %e^%e? Then it must become a float.
>       - Is it the %e in sin(%e)? Then it must become a float.
>       - Is it just a standalone %e? Then it must become a float.
>    - There's one way it could work, although it comes with a catch:
>       - We stop handling %e in simplifya entirely. *Nice side effect:
>       Atoms are always simplified!*
>       - Instead, we treat %e like any other constant, e.g. %pi, and let
>       the evaluator convert it to float unconditionally when numer is true
>       .
>       - Afterwards, if %enumer is false, we look explicitly for
>       2.718281828459045^(symbolic) and convert that back to %e^(symbolic).
>       Note that this is an exact comparison to %e-val that will not be
>       affected by floating point issues.
>       - The catch: If the user manually enters 2.718281828459045^x, it
>       will become %e^x. Maybe that's acceptable? I don't see any other
>       way of achieving the desired behavior.
>    - Alternatively, we could degrade %enumer to a selective switch just
>    for %e. With %enumer = false, it would always prevent %e from becoming
>    a float when numer is true. But that would include things like sin(%e),
>    where the user would probably expect a float. This behavior would probably
>    not be very useful, and I don't like the idea of changing the meaning of a
>    flag in a significant way, as it would destroy backwards-compatibility.
>
> Looking forward to the community's opinions on this.
>
> Best regards
> David Scherfgen
> _______________________________________________
> Maxima-discuss mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/maxima-discuss
>

_______________________________________________
Maxima-discuss mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/maxima-discuss