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
Well, that's floating-point arithmetic for you. log(x, y) simply computes
log(x)/log(y) behind the scenes; since both log computations and the
floating-point division can introduce errors, the result will frequently
not be correctly rounded.
I don't really see the benefit of special-casing log(x, 10). In what
circumstances does it matter that log(x, 10) != log10(x)? I could
understand people being upset that log(10**n, 10) doesn't return n
exactly, but that's what log10 is there for.
Mark,
"... that's what log10 is there for". That would be a good point if the
documentation said that. However, all the docs for log10 say is:
math.log10(x)
Returnthebase-10logarithmofx.
So we have a python function log10() which looks like it is redundant
since we can use log(a, 10) instead. But it actually functions
differently to log(a, 10), and the Python user would never know this
from looking at the documentation.
I think Tim Peters missed one important guideline in his "The Zen of
Python". The principle of least astonishment (or surprise) - when two
elements of an interface conflict, or are ambiguous, the behaviour
should be that which will least surprise the human user or programmer at
the time the conflict arises.
Its easy for the python developer to ignore this guideline. They know
the implementation, and are rarely surprised by inconsistent behaviour
since they have seen it before, or even created it without documenting it.
If Python functions are inconsistent then I think they should either be
made consistent, or if that's not possible they should be clearly
documented as being inconsistent.
The docs for log(x[, base]) could be improved to say:
"this function preserves the consistency of log(a,b) == log(a)/log(b)
but breaks consistency with log(a,10) == log10(a)"
The docs for log10(x) could be improved to say:
"this function gives the correct result for powers of 10,
but breaks consistency with log(a,10) == log10(a)"
If Python functions are inconsistent then I think they should either
be
made consistent, or if that's not possible they should be clearly
documented as being inconsistent.
I think 'inconsistent' is a bit strong for what happens here. In my
view, the expressions log10(x) and log(x, 10) behave consistently: they
both give (good) floating-point approximations to the base-10 logarithm
of x. However, since they use slightly different methods to get those
approximations, the approximations are not identical.
Would you also say that atan2(y, x) is inconsistent with atan(y/x) (for
positive x, y, say), because they give minutely different results in
some cases?
The docs for log10(x) could be improved to say:
"this function gives the correct result for powers of 10,
but breaks consistency with log(a,10) == log10(a)"
I find this unnecessarily negative. I propose instead to leave the log
documentation as it is, and add something like the following to the
log10 documentation, as an explanation of why log10 is still valuable in
the presence of the two-argument log function:
"""Since this function directly wraps the platform log10 function, log10(x) will usually (depending on the platform) be faster and more
accurate than the mathematically equivalent log(x, 10)."""
Note that historically, the two-argument version of math.log appeared
long after math.log10 did; this might help explain the apparent
redundancy. (I'd actually argue that the two-argument log should not
have been added in the first place: it doesn't wrap a standard C math
function, and it's really no different from log(x)/log(y), except that
having it as a built-in library function gives the illusion that it
might be more accurate than it actually is. However, that's academic
now.)
One possible 'fix' for this situation does occur to me: instead of
computing log(x, y) internally as log(x)/log(y), compute it as
log10(x)/log10(y). This at least doesn't involve extensive changes or
additions to the code. I don't think it really makes any practical
difference, except perhaps in reducing the number of bug reports like
this one. And it won't help make log2(x) == log(x, 2) if/when the C99
log2 function is added to the math library, either. I'd be -0 on making
this change.
I wasn't keen to add the 2-argument log() extension either. However, I
bet it would help if the docs for that were changed to explain that
log(x, base) is just a convenient shorthand for computing
log(x)/log(base), and therefore may be a little less accurate than a
function that directly computed the logarithm wrt the given base.
Activity
steve21 commentedon Aug 23, 2009
You would expect the results to be the same.
Internally math.log() could call math.log10() when base==10. That would
ensure they are consistent.
mdickinson commentedon Aug 23, 2009
Well, that's floating-point arithmetic for you. log(x, y) simply computes
log(x)/log(y) behind the scenes; since both log computations and the
floating-point division can introduce errors, the result will frequently
not be correctly rounded.
I don't really see the benefit of special-casing log(x, 10). In what
circumstances does it matter that log(x, 10) != log10(x)? I could
understand people being upset that log(10**n, 10) doesn't return n
exactly, but that's what log10 is there for.
See also the discussion in bpo-3724.
steve21 commentedon Aug 24, 2009
Mark,
"... that's what log10 is there for". That would be a good point if the
documentation said that. However, all the docs for log10 say is:
So we have a python function log10() which looks like it is redundant
since we can use log(a, 10) instead. But it actually functions
differently to log(a, 10), and the Python user would never know this
from looking at the documentation.
I think Tim Peters missed one important guideline in his "The Zen of
Python". The principle of least astonishment (or surprise) - when two
elements of an interface conflict, or are ambiguous, the behaviour
should be that which will least surprise the human user or programmer at
the time the conflict arises.
Its easy for the python developer to ignore this guideline. They know
the implementation, and are rarely surprised by inconsistent behaviour
since they have seen it before, or even created it without documenting it.
If Python functions are inconsistent then I think they should either be
made consistent, or if that's not possible they should be clearly
documented as being inconsistent.
The docs for log(x[, base]) could be improved to say:
"this function preserves the consistency of log(a,b) == log(a)/log(b)
but breaks consistency with log(a,10) == log10(a)"
The docs for log10(x) could be improved to say:
"this function gives the correct result for powers of 10,
but breaks consistency with log(a,10) == log10(a)"
mdickinson commentedon Aug 24, 2009
I think 'inconsistent' is a bit strong for what happens here. In my
view, the expressions log10(x) and log(x, 10) behave consistently: they
both give (good) floating-point approximations to the base-10 logarithm
of x. However, since they use slightly different methods to get those
approximations, the approximations are not identical.
Would you also say that atan2(y, x) is inconsistent with atan(y/x) (for
positive x, y, say), because they give minutely different results in
some cases?
I find this unnecessarily negative. I propose instead to leave the log
documentation as it is, and add something like the following to the
log10 documentation, as an explanation of why log10 is still valuable in
the presence of the two-argument log function:
"""Since this function directly wraps the platform log10 function,
log10(x)will usually (depending on the platform) be faster and moreaccurate than the mathematically equivalent
log(x, 10)."""Note that historically, the two-argument version of math.log appeared
long after math.log10 did; this might help explain the apparent
redundancy. (I'd actually argue that the two-argument log should not
have been added in the first place: it doesn't wrap a standard C math
function, and it's really no different from log(x)/log(y), except that
having it as a built-in library function gives the illusion that it
might be more accurate than it actually is. However, that's academic
now.)
One possible 'fix' for this situation does occur to me: instead of
computing log(x, y) internally as log(x)/log(y), compute it as
log10(x)/log10(y). This at least doesn't involve extensive changes or
additions to the code. I don't think it really makes any practical
difference, except perhaps in reducing the number of bug reports like
this one. And it won't help make log2(x) == log(x, 2) if/when the C99
log2 function is added to the math library, either. I'd be -0 on making
this change.
tim-one commentedon Aug 24, 2009
I wasn't keen to add the 2-argument log() extension either. However, I
bet it would help if the docs for that were changed to explain that
log(x, base) is just a convenient shorthand for computing
log(x)/log(base), and therefore may be a little less accurate than a
function that directly computed the logarithm wrt the given base.
terryjreedy commentedon Aug 28, 2009
Reopening as doc issue. This is at least the second time this issue has
been reported (see bpo-3724), with some agreement on doc tweak, but not done.
Specific suggestions for math module doc, 9.2.2:
add: ", calculated as log(x)/log(base)" before period.
[This could be removed if better method ever implemented.]
add: "This is usually more accurate than log(x, 10)."
birkenfeld commentedon Sep 1, 2009
Okay, I made changes along Terry' suggestions in r74617.