You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Incorrect docstring of math.exp (math.e vs Euler's number) #101594
>>> import math
>>> help(math.exp)
Help on built-in function exp in module math:
exp(x, /)
Return e raised to the power of x.
I would rephrase this as: "Return the exponential of x." (like the Mathematica docs). Same for expm1() or with log()/log1p().
The problem with the current text is that here is a disambiguation of the Euler's number e vs the math.e (an approximation of). Sometimes this is explained in the sphinx docs: e.g. for same exp() it says "Return e raised to the power x, where e = 2.718281… is the base of natural logarithms.". But sometimes not: e.g. for log() or log1p().
I think, using "the exponential of" or "the natural logarithm of" in the docstrings and sphinx docs will be better.
"Return the exponential of x" implies that it returns x to some power, which is wrong. Even if we read it the other way, "the exponential of x" doesn't tell us what number is being raised to the power of x. Which exponential? There are an infinite number of possible exponentials (something) to the power of x.
The current description is much better than the description in the Mathematica docs, where you have to click on the "Details" section to finally discover that Exp[z] is converted to E^z.
The problem with the current text is that here is a disambiguation of the Euler's number e vs the math.e (an approximation of).
That's not a problem. We know from the relevant domain knowledge that all float constants and operations refer to floats, not real numbers. We don't need to repeat that for every single function. Unlike Mathematica, the math module does not do symbolic exact maths.
In any case, the docstring does not have to repeat the full documentation. It is okay for the docstring to be an abbreviated summary.
"Return the exponential of x" implies that it returns x to some power, which is wrong.
Not. It's exactly e**x, see also the matlab docs, but indeed: maybe this convention is less popular. Other variants (more verbose): "the natural exponential function" or just "the exponential function", see the mathworld.
We know from the relevant domain knowledge that all float constants and operations refer to floats, not real numbers.
Then this will be incorrect, because the math.exp(x)is not actually the math.e**x. The mentioned full documention does explain why.
Here's my 2 cents: since the math module is based on the C standard and AFAIK math.exp simply calls exp from <math.h> (which itself is technically implementation-dependent), I would simply copy the description from §7.12.6.1/2, ISO/IEC 9899:1999:TC3, namely
Compute the base-e exponential of x.
Now, even with the above sentence or even if you say "the exponential of x", you could argue that it's still not the case since the actual result is an approximation. In particular, you cannot say that it uses Euler's number. Therefore, I don't think we need to be extremely verbose in the docstring if we have an online doc and if the actual result also depends on the libc implementation. A more precise docstring would be
Compute an approximation of the base-e exponential of x. The result is more precise than math.e ** x.
I however think that this is more confusing for normal users.
What I thought users could find confusing is the term "approximation" because the way it is approximated is entirely implementation-dependent. But if it's not confusing, then it's good, I think ? I personally come from C/C++, so I've always used exp() since I was told not to use constants directly.
Thanks all for the discussion and suggestions, and thank you to @skirpichev for the PR.
I'm going to close here: the maxim "Practicality beats purity" applies, and I don't think there's any practical problem being solved at this point; in particular, I think removing the references to e on the basis that they're technically ambiguous harms more than it helps.
I agree that there's ambiguity over whether e in any given docstring means math.e or whether it refers to Euler's number, but I'm not seeing any practical problem arising from that ambiguity. The sole exception is that it should be emphasized that users should prefer exp(x) over math.e**x for accuracy reasons, and the docs already make that point.
Technically the same applies to log: log(x) should be preferred over log(x, math.e), but in practice it makes no difference - assuming IEEE 754 arithmetic, log(math.e) evaluates to 1.0 under correct rounding, and on most platforms the libm accuracy is good enough that log(math.e) does in fact give exactly 1.0. So log(x) and log(x, math.e) give exactly the same result; the latter is just slightly less efficient. So this doesn't seem worth calling out in the docs.
So log(x) and log(x, math.e) give exactly the same result;
If we can guarantee that, sorry for a bit off-topic, then base=math.e sounds to be a good default value. What if we adapt the inspect module to keep "symbolic" name in the Signature, does this make sense for you?
@skirpichev Yes, that seems reasonable, if it can be achieved. It's philosophically wrong in that it doesn't match what the implementation actually does, and that still bugs me a little, but I think it passes the "practicality beats purity" test.
Activity
stevendaprano commentedon Feb 6, 2023
"Return the exponential of x" implies that it returns x to some power, which is wrong. Even if we read it the other way, "the exponential of x" doesn't tell us what number is being raised to the power of x. Which exponential? There are an infinite number of possible exponentials (something) to the power of x.
The current description is much better than the description in the Mathematica docs, where you have to click on the "Details" section to finally discover that
Exp[z] is converted to E^z.That's not a problem. We know from the relevant domain knowledge that all float constants and operations refer to floats, not real numbers. We don't need to repeat that for every single function. Unlike Mathematica, the
mathmodule does not do symbolic exact maths.In any case, the docstring does not have to repeat the full documentation. It is okay for the docstring to be an abbreviated summary.
skirpichev commentedon Feb 6, 2023
Not. It's exactly
e**x, see also the matlab docs, but indeed: maybe this convention is less popular. Other variants (more verbose): "the natural exponential function" or just "the exponential function", see the mathworld.Then this will be incorrect, because the
math.exp(x)is not actually themath.e**x. The mentioned full documention does explain why.That's true. But even you above mistakenly interpreted
ein the docstring as the float numbermath.e, that shows that there is an issue.picnixz commentedon Feb 7, 2023
Here's my 2 cents: since the
mathmodule is based on the C standard and AFAIKmath.expsimply callsexpfrom<math.h>(which itself is technically implementation-dependent), I would simply copy the description from §7.12.6.1/2, ISO/IEC 9899:1999:TC3, namelyNow, even with the above sentence or even if you say "the exponential of x", you could argue that it's still not the case since the actual result is an approximation. In particular, you cannot say that it uses Euler's number. Therefore, I don't think we need to be extremely verbose in the docstring if we have an online doc and if the actual result also depends on the libc implementation. A more precise docstring would be
I however think that this is more confusing for normal users.
arhadthedev commentedon Feb 7, 2023
As a normal user, I've thought that both ways are the same and
exp()is just a pre-**legacy artifact. So the precision note is crucial.picnixz commentedon Feb 7, 2023
What I thought users could find confusing is the term "approximation" because the way it is approximated is entirely implementation-dependent. But if it's not confusing, then it's good, I think ? I personally come from C/C++, so I've always used
exp()since I was told not to use constants directly.skirpichev commentedon Feb 7, 2023
In fact, what's I'm suggesting is to be less verbose in docstring and sphinx docs. E.g. the docstring of exp could be:
The sphinx docs:
And so on: we could drop remarks like
(base e)orHere e is the base of natural logarithms.pythongh-101594: Resolve a disambiguation of math.e vs the Euler's nu…
mdickinson commentedon Feb 19, 2023
Thanks all for the discussion and suggestions, and thank you to @skirpichev for the PR.
I'm going to close here: the maxim "Practicality beats purity" applies, and I don't think there's any practical problem being solved at this point; in particular, I think removing the references to
eon the basis that they're technically ambiguous harms more than it helps.I agree that there's ambiguity over whether
ein any given docstring meansmath.eor whether it refers to Euler's number, but I'm not seeing any practical problem arising from that ambiguity. The sole exception is that it should be emphasized that users should preferexp(x)overmath.e**xfor accuracy reasons, and the docs already make that point.Technically the same applies to
log:log(x)should be preferred overlog(x, math.e), but in practice it makes no difference - assuming IEEE 754 arithmetic,log(math.e)evaluates to1.0under correct rounding, and on most platforms thelibmaccuracy is good enough thatlog(math.e)does in fact give exactly1.0. Solog(x)andlog(x, math.e)give exactly the same result; the latter is just slightly less efficient. So this doesn't seem worth calling out in the docs.skirpichev commentedon Feb 19, 2023
@mdickinson, thank you for review.
If we can guarantee that, sorry for a bit off-topic, then base=math.e sounds to be a good default value. What if we adapt the inspect module to keep "symbolic" name in the Signature, does this make sense for you?
mdickinson commentedon Feb 19, 2023
@skirpichev Yes, that seems reasonable, if it can be achieved. It's philosophically wrong in that it doesn't match what the implementation actually does, and that still bugs me a little, but I think it passes the "practicality beats purity" test.
skirpichev commentedon Feb 19, 2023
Yes, I've a toy implementation: #89381 (comment)
Instead of "calculated as log(x)/log(base)" we could state something like "equal to log(x)/log(base)".