This issue tracker has been migrated to GitHub ,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2010年09月27日 13:23 by akira, last changed 2022年04月11日 14:57 by admin. This issue is now closed.
| Files | ||||
|---|---|---|---|---|
| File name | Uploaded | Description | Edit | |
| math_log_power_two.diff | akira, 2010年09月27日 18:14 | |||
| test_log_power_two.py | akira, 2010年09月27日 18:15 | Find n such as int(math.log(2**n, 2)) != n | ||
| Messages (7) | |||
|---|---|---|---|
| msg117444 - (view) | Author: Akira Li (akira) * | Date: 2010年09月27日 13:23 | |
$ python3.1 -c'import math; f = math.log(4,2); print(int(f), f.as_integer_ratio())' 2 (2, 1) $ python3.2 -c'import math; f = math.log(4,2); print(int(f), f.as_integer_ratio())' 1 (9007199254740991, 4503599627370496) Python 3.2a2+ (py3k:85028, Sep 27 2010, 16:46:11) [GCC 4.4.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import math >>> f = math.log(32, 2) >>> f 4.999999999999999 >>> int(f) 4 >>> f.as_integer_ratio() (5629499534213119, 1125899906842624) I'm not sure whether it is a bug, but it is an unexpected change in behavior between 3.1 and 3.2. |
|||
| msg117447 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2010年09月27日 14:09 | |
No, it's not really a bug: math.log(x, 2) isn't an atomic operation: it's computed internally as something like log(x) / log(2), and since each of the three steps (computation of the logs, division) can introduce a small rounding error, you shouldn't be surprised if the result doesn't come out exactly. The difference between 3.1 and 3.2 was a side-effect of a change to remove the dependence of the math module on the internal long integer representation. Having said that, it would be possible to improve the algorithm that's used to compute log of an integer (see the loghelper function in Modules/mathmodule.c): currently, for positive k, log(2**k) ends up being computed as log(0.5) + (k+1)*log(2), which doesn't help; it would be slightly better if it were computed directly as k*log(2) instead. But you still can't (and shouldn't) rely on log(x, 2) giving exact results for powers of 2. I'm not sure what you're using math.log(x, 2) for, but you may be interested in the int.bit_length method. |
|||
| msg117457 - (view) | Author: Akira Li (akira) * | Date: 2010年09月27日 18:14 | |
> No, it's not really a bug: math.log(x, 2) isn't an atomic operation: It is not a bug, but values of math.log(4) differs between 3.1 and 3.2 i.e., math.log(4.0) in 3.2 returns value that is consistent with math.log(4) in 3.1 but math.log(4) in 3.2 doesn't. > I'm not sure what you're using math.log(x, 2) for, but you may be interested in the int.bit_length method. The docs for int.bit_length say: > if x is nonzero, then x.bit_length() is the unique positive integer k such that 2**(k-1) <= abs(x) < 2**k. Equivalently, when abs(x) is small enough to have a correctly rounded logarithm, then k = 1 + int(log(abs(x), 2)). It is expected that int(log(n,2)) produces correct result for small n. > Having said that, it would be possible to improve the algorithm that's used to compute log of an integer (see the loghelper function in Modules/mathmodule.c): currently, for positive k, log(2**k) ends up being computed as log(0.5) + (k+1)*log(2), which doesn't help; it would be slightly better if it were computed directly as k*log(2) instead. But you still can't (and shouldn't) rely on log(x, 2) giving exact results for powers of 2. I've changed loghelper() to return improved result for power of 2 |
|||
| msg117470 - (view) | Author: Raymond Hettinger (rhettinger) * (Python committer) | Date: 2010年09月27日 20:28 | |
It is not a reasonable request for math float functions to produce exact integer values and there is some harm in making further alterations to the existing algorithm (the more you tweak it in one place, the more you create oddities somewhere else). There may be a case for a separate math.log2() function but this has never been requested before, so it is a low priority. If the docs for bit_length() bug you, I can change them. They are meant to be the exact math definition of bit_length, not an executable exact result using limited precision floating point. Those docs are trying to inform users about bit_length() and are not making a promise about the behavior of math.log(). If you're wanting exact log results for integer inputs and bases, the math module is going to disappoint you no matter what we do. This is a limited-precision-floating-point fact of life. |
|||
| msg117507 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2010年09月28日 07:22 | |
I've tweaked the loghelper algorithm in r85048. Looking at [n for n in range(100) if log(2**n) != n], I get: Python 3.1: 14 bad values out of 1st 100; first is 29 Python 3.2 (patched): 10 bad values; first is 29 Python 3.2 (unpatched): 25 bad values; first is 2. |
|||
| msg117508 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2010年09月28日 07:23 | |
> [n for n in range(100) if log(2**n) != n] Should be: [n for n in range(100) if log(2**n, 2) != n] |
|||
| msg117645 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2010年09月29日 19:14 | |
Applied further tweaks in r85120: for an integer n, log(n) is now computed as log(float(n)), provided only that n is small enough to be converted to a float without overflow. This puts log on a more equal footing with all the other math module functions, and satisfies the (reasonable, IMO) expectation that log(n) == log(float(n)) for small integers n. As a nice side-effect, this change guarantees that on a machine where log10 has reasonable accuracy (e.g., accurate to within 0.9 ulps or so), log10(10**n)==n for any nonnegative integer n such that 10**n is within the range of a double. |
|||
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2022年04月11日 14:57:06 | admin | set | github: 54168 |
| 2010年09月29日 19:14:07 | mark.dickinson | set | messages: + msg117645 |
| 2010年09月28日 07:23:40 | mark.dickinson | set | messages: + msg117508 |
| 2010年09月28日 07:22:44 | mark.dickinson | set | status: open -> closed resolution: fixed messages: + msg117507 |
| 2010年09月27日 20:28:28 | rhettinger | set | priority: normal -> low nosy: + rhettinger messages: + msg117470 |
| 2010年09月27日 18:38:49 | akira | set | type: behavior -> enhancement |
| 2010年09月27日 18:15:54 | akira | set | files: + test_log_power_two.py |
| 2010年09月27日 18:14:22 | akira | set | files:
+ math_log_power_two.diff keywords: + patch messages: + msg117457 |
| 2010年09月27日 14:09:22 | mark.dickinson | set | assignee: mark.dickinson messages: + msg117447 nosy: + mark.dickinson |
| 2010年09月27日 13:23:02 | akira | create | |