msg166275 - (view) |
Author: andrea bergamini (andrea.bergamini) |
Date: 2012-07-24 10:57 |
math.pow(43, 10) gives the wrong result: 21611482313284248.0 Instead, the build-in function 43**10 and pow(43, 10) give the correct result: 21611482313284249L. This bug has been seen on ActivePython 2.5.1.1. Sorry no tests on recent versions. |
|
|
msg166277 - (view) |
Author: Ezio Melotti (ezio.melotti) *  |
Date: 2012-07-24 11:32 |
This is what I get on both 2.7 and 3.3: >>> import math >>> math.pow(43, 10) 2.161148231328425e+16 >>> pow(43, 10) 21611482313284249 >>> 43**10 21611482313284249 >>> int(math.pow(43, 10)) 21611482313284248 |
|
|
msg166278 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) *  |
Date: 2012-07-24 11:42 |
>>> (43**10).bit_length() 55 >>> sys.float_info.mant_dig 53 See http://docs.python.org/faq/design.html#why-are-floating-point-calculations-so-inaccurate |
|
|
msg166283 - (view) |
Author: andrea bergamini (andrea.bergamini) |
Date: 2012-07-24 12:18 |
Ok, but math.pow IMPO has to be aligned to pow and built-in pow (**), otherwise this kind of "inaccuracies" can compromise the application behavior. I was using this funcion in a cryptographic mechanisms, and this issue resulted in a failure. Generally speaking, integer numbers should not be affected by inaccuracies. I mean, there's no floating point. |
|
|
msg166284 - (view) |
Author: R. David Murray (r.david.murray) *  |
Date: 2012-07-24 12:30 |
If I understand correctly, the math module is providing C standard (Annex F) *floating point* mathematical functions. Mark will have the definitive answer once he gets a chance to comment. Perhaps a documentation clarification is in order on this point. |
|
|
msg166285 - (view) |
Author: Stefan Krah (skrah) *  |
Date: 2012-07-24 12:38 |
I think Serhiy has already explained that 43**10 is too large to be represented exactly in 53-bit floating point arithmetic. The math module wraps the floating point functions from the C standard: "It provides access to the mathematical functions defined by the C standard." "Except when explicitly noted otherwise, all return values are floats." So there's no bug, and the documentation looks fine to me, too. |
|
|
msg166286 - (view) |
Author: Antoine Pitrou (pitrou) *  |
Date: 2012-07-24 12:39 |
Well, the math.pow() doc could use a "seealso" pointing to the built-in pow() function perhaps. |
|
|
msg166287 - (view) |
Author: Stefan Krah (skrah) *  |
Date: 2012-07-24 12:45 |
How about changing the title to something like: math -- 53-bit floating point arithmetic |
|
|
msg166288 - (view) |
Author: Stefan Krah (skrah) *  |
Date: 2012-07-24 12:46 |
"Title" referring to the section header of http://docs.python.org/dev/library/math.html ... |
|
|
msg166289 - (view) |
Author: Antoine Pitrou (pitrou) *  |
Date: 2012-07-24 12:53 |
That could help, but you easily miss the title when looking up the doc for a given function. And since log2() already has a seealso for the corresponding int method, pow() could grow one as well. (and in all honesty I don't know the difference between the "**" operator and the built-in pow() function :-)) |
|
|
msg166290 - (view) |
Author: andrea bergamini (andrea.bergamini) |
Date: 2012-07-24 13:02 |
Well, from a library I'm used to expect a good result or an exception. Not a value that differs from the correct of one unit! I agree with Antoine, the doc should warn about this behavior. I've lost a lot of time before discovering my application issue came from the py math library... |
|
|
msg166293 - (view) |
Author: R. David Murray (r.david.murray) *  |
Date: 2012-07-24 13:49 |
Your problems didn't come from the "Python" math library, it came from the C math library that Python provides a wrapper for, which the documentation does clearly state. And the result you got is accurate...for a floating point calculation. |
|
|
msg166337 - (view) |
Author: Raymond Hettinger (rhettinger) *  |
Date: 2012-07-24 23:18 |
The math module is primarily about exposing the C floating point library functions. Any integer arguments are converted to double. We could add more docs but that usually doesn't help someone who already has an expectation that math.pow does the same thing as int ** int. |
|
|
msg166370 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2012-07-25 08:59 |
Agreed that this is at worst a doc issue. [Antoine] > and in all honesty I don't know the difference between the "**" operator > and the built-in pow() function :-) None, as far as I know, apart from the pow function's ability to take a 3rd argument. Both ultimately call PyNumber_Power, and the various type-specific __pow__ methods take over from there. [+1 for removing pow from the builtins and shunting three-argument pow to the math module in Python 5000000.] |
|
|
msg166398 - (view) |
Author: Ramchandra Apte (Ramchandra Apte) * |
Date: 2012-07-25 13:46 |
> [+1 for removing pow from the builtins and shunting three-argument pow to the math module in Python 5000000.] Me too. Anybody who uses pow with to arguments can use arg1**arg2 Anybody who uses pow with three is doing something mathematical and has most likely imported math already. |
|
|
msg166402 - (view) |
Author: Stefan Krah (skrah) *  |
Date: 2012-07-25 14:03 |
Ramchandra Apte <report@bugs.python.org> wrote: > > [+1 for removing pow from the builtins and shunting three-argument pow to the math module in Python 5000000.] > Anybody who uses pow with three is doing something mathematical and has most likely imported math already. Wouldn't that reinforce the misconception that math is for arbitrary precision number theoretical functions? The OP used it for cryptography. |
|
|
msg166403 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2012-07-25 14:13 |
> Wouldn't that reinforce the misconception that math is for arbitrary > precision number theoretical functions? Perhaps. We already have math.factorial, though; adding math.powmod wouldn't seem so much of a stretch. Just to be clear, I'm not seriously proposing this for any version of Python before 4.0; apologies for derailing the issue thread. |
|
|
msg166476 - (view) |
Author: andrea bergamini (andrea.bergamini) |
Date: 2012-07-26 12:29 |
Ok guys, ticket closed, but I'm still confused: I'm not a Python expert, I've understood that math is a sort of wrapper of C math.h or something like this, but: - I can't find any reason in using math.pow if I can get errors like the one explained. - I've used math.h in my C++ code without having experienced any problem in that pow operation. I'm surely missing something but I'm a bit confused... |
|
|
msg166478 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) *  |
Date: 2012-07-26 12:52 |
> - I can't find any reason in using math.pow if I can get errors like the one explained. The reason is your intention to get the error. >>> pow(-1, 0.5) (6.123031769111886e-17+1j) >>> math.pow(-1, 0.5) Traceback (most recent call last): File "", line 1, in ValueError: math domain error >Â - I've used math.h in my C++ code without having experienced any problem in that pow operation. What you get in C++ as result of pow(43, 10)? Technically, in C++Â you should use header, not <math.h>. |
|
|
msg166479 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2012-07-26 12:56 |
- I can't find any reason in using math.pow if I can get errors like the one explained. Yep---don't use math.pow if you want *exact* integer results. If you're doing numerical calculations and errors of around 1 part in 1 thousand million million are acceptable to you, then math.pow works just fine. Just like the other math functions (math.log, math.exp, math.sin, etc.), it's using floating-point arithmetic, so converts its inputs to float and gives a float result. Unlike Python ints, which have unbounded precision, Python floats have a fixed size (64 bits), so there are only finitely many values (less than 2**64) that can be represented exactly. The fact is that the number you were expecting, 21611482313284249, isn't one of those numbers: it *doesn't exist* as a float, because it's not exactly representable in the usual 64-bit floating-point type that Python uses internally. - I've used math.h in my C++ code without having experienced any problem in that pow operation. I'd be quite surprised if this were true: if you're using the double type with C or C++, and the pow function from math.h / cmath, you should expect to see *exactly* the same issues. With the 'long double' type, you may get a little more precision (depending on the platform), but that just delays the point at which those issues would appear. By the way, don't close the issue just yet! There's still ongoing discussion here about whether there's potential for a documentation improvement. |
|
|
msg166493 - (view) |
Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) *  |
Date: 2012-07-26 16:48 |
C comparison rules are different from Python's. In the program below (which outputs 1), the mixed comparison will first convert the literal to a double, and lost some precision. Python does the opposite: the (imprecise) float is converted to a long, so all digits are compared. #include <math.h> #include <stdio.h> int main() { printf("result: %d\n", (pow(43,10) == 21611482313284249)); } |
|
|
msg166504 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2012-07-26 19:33 |
Ah yes; a comparison like that could indeed give the impression that C/C++ was computing things exactly. :-) |
|
|
msg166693 - (view) |
Author: Antoine Pitrou (pitrou) *  |
Date: 2012-07-28 21:08 |
Changing the incredible issue title :-) |
|
|
msg179317 - (view) |
Author: Ezio Melotti (ezio.melotti) *  |
Date: 2013-01-08 07:17 |
> Well, the math.pow() doc could use a "seealso" pointing to the built-in > pow() function perhaps. Pointing to ``**`` is probably better. I think that a simple note that mentions the ** operator and when it's better to use it (and possibly the limitations of math.pow) is enough. Anyone wants to suggest a specific wording? |
|
|
msg180760 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2013-01-27 10:48 |
> Anyone wants to suggest a specific wording? How about the attached patch? |
|
|
msg180773 - (view) |
Author: R. David Murray (r.david.murray) *  |
Date: 2013-01-27 15:34 |
I don't think it should be .. note, but otherwise it looks fine to me. |
|
|
msg181835 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2013-02-10 18:35 |
Updated patch. Thanks Ezio and David for reviewing. |
|
|
msg181836 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2013-02-10 18:36 |
Whoops. Removing a bonus non-grammatical 'function'. |
|
|
msg182233 - (view) |
Author: Ezio Melotti (ezio.melotti) *  |
Date: 2013-02-16 17:33 |
LGTM. (Maybe build the doc and double check that all the links are correct before committing.) |
|
|
msg182708 - (view) |
Author: Roundup Robot (python-dev)  |
Date: 2013-02-23 02:56 |
New changeset ad0712f4b3e0 by Ezio Melotti in branch '2.7': #15438: add a note to math.pow() that suggests using **/pow() for integers. Patch by Mark Dickinson. http://hg.python.org/cpython/rev/ad0712f4b3e0 New changeset 7d95a0aa6b5a by Ezio Melotti in branch '3.2': #15438: add a note to math.pow() that suggests using **/pow() for integers. Patch by Mark Dickinson. http://hg.python.org/cpython/rev/7d95a0aa6b5a New changeset a305901366a6 by Ezio Melotti in branch '3.3': #15438: merge with 3.2. http://hg.python.org/cpython/rev/a305901366a6 New changeset e0f940829eb6 by Ezio Melotti in branch 'default': #15438: merge with 3.3. http://hg.python.org/cpython/rev/e0f940829eb6 |
|
|
msg182744 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2013-02-23 13:59 |
Thanks, Ezio; I didn't get around to dealing with this as quickly as I meant to. |
|
|