# 3-arg float pow()

Tim Peters tim.one at home.com
Mon Sep 3 22:51:19 CEST 2001

[David C. Ullrich]
> Please note that this is not a comment on what's useful or not, I
> wouldn't know about that. Just curious:
>
> Seems like pow(3., 500., 7.) can't possibly do anything except just
> 3.**500. % 7(???),

Yes, but there are worlds of subtleties hiding in both operators there.  For
the 3.**500. part, earlier versions of Python noticed they were really
integers hiding in fp format, and did repeated multiplication.  This is
*less* accurate than using a good-quality libm pow() (which should have
worst-case final error strictly less than 1 ULP), so current CVS Python uses
the libm pow() instead.  The last few bits may differ -- or as many as the
last 15-or-so bits if the platform libm pow() truly sucks.

WRT the x % y part, the platform libm fmod(x, y) is used.  The definition of
that is subtle, so there may be some platforms that screw it up; fmod(x, y)
can always be computed exactly, but the integer N such that fmod(x, y)
equals (mathematically) x - N*y may be too large to represent as a native
double or long long, and the C std isn't especially clear that fmod has to
work exactly despite that (although the C *rationale* is clear about it --
but the rationale isn't part of the std).

> hence the random nature of the result and the utter uselessness.
? When you say you're taking away "float pow()" it's not clear to me
> exactly what's going away.

That WRT Python's builtin pow(x, y, z) on builtin types, z can be non-None
only if x, y and z are all of integer types, and y >= 0, and z != 0.  From
current CVS (which already implements this):

>>> pow(3., 500)
3.6360291795869935e+238
>>> pow(3., 500., 7.)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 3rd argument to floating pow() must be None
>>> pow(2, -5)
0.03125
>>> pow(2, -5, .1)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: integer pow() arg 3 must not be specified when arg 2 is < 0
>>> pow(2, -5, 1)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: integer pow() arg 3 must not be specified when arg 2 is < 0
>>>

> A possibility that springs to mind would be a pow() that allows
> any type for the first and third arguments but requires a positive
> integer for the exponent.

That would disallow the pow(2, -5) example above, and we don't want to
disallow that.

> So pow(3., 500, 7.) would be legal, and also would be computed
> efficiently using whatever you call the repeated-squaring thing.

test suite) I've never seen 3-argument pow with a non-None 3rd argument used
except when the first two arguments were of integer types.  Change the
example to pow(3.1, 500, 7.), and the result is doomed to be gibberish no
matter how implemented (short of heroic efforts that would bloat the code
for something never used -- but this isn't Common Lisp <wink>).

> Not that I actually see any use for this with floats, but I
> _do_ use a Pow() that works exactly like this for powers of
> matricies and things...

That's fine, but seems a different issue.