[pypy-svn] pypy default: Fix a crash in pow() with nonfinite values

amauryfa commits-noreply at bitbucket.org
Fri Feb 4 01:40:39 CET 2011


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: 
Changeset: r41592:c5f9e9eb2e26
Date: 2011-02-04 01:38 +0100
http://bitbucket.org/pypy/pypy/changeset/c5f9e9eb2e26/

Log:	Fix a crash in pow() with nonfinite values

diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py
--- a/pypy/objspace/std/floatobject.py
+++ b/pypy/objspace/std/floatobject.py
@@ -412,6 +412,48 @@
     x = w_float1.floatval
     y = w_float2.floatval
 
+    # Sort out special cases here instead of relying on pow()
+    if y == 0.0:
+        # x**0 is 1, even 0**0
+        return W_FloatObject(1.0)
+    if isnan(x):
+        # nan**y = nan, unless y == 0
+        return W_FloatObject(x)
+    if isnan(y):
+        # x**nan = nan, unless x == 1; x**nan = x
+        if x == 1.0:
+            return W_FloatObject(1.0)
+        else:
+            return W_FloatObject(y)
+    if isinf(y):
+        # x**inf is: 0.0 if abs(x) < 1; 1.0 if abs(x) == 1; inf if
+        # abs(x) > 1 (including case where x infinite)
+        #
+        # x**-inf is: inf if abs(x) < 1; 1.0 if abs(x) == 1; 0.0 if
+        # abs(x) > 1 (including case where v infinite)
+        x = abs(x)
+        if x == 1.0:
+            return W_FloatObject(1.0)
+        elif (y > 0.0) == (x > 1.0):
+            return W_FloatObject(INFINITY)
+        else:
+            return W_FloatObject(0.0)
+    if isinf(x):
+        # (+-inf)**w is: inf for w positive, 0 for w negative; in oth
+        # cases, we need to add the appropriate sign if w is an odd
+        # integer.
+        y_is_odd = math.fmod(abs(y), 2.0) == 1.0
+        if y > 0.0:
+            if y_is_odd:
+                return W_FloatObject(x)
+            else:
+                return W_FloatObject(abs(x))
+        else:
+            if y_is_odd:
+                return W_FloatObject(copysign(0.0, x))
+            else:
+                return W_FloatObject(0.0)
+
     if x == 0.0:
         if y < 0.0:
             if isinf(y):

diff --git a/pypy/objspace/std/test/test_floatobject.py b/pypy/objspace/std/test/test_floatobject.py
--- a/pypy/objspace/std/test/test_floatobject.py
+++ b/pypy/objspace/std/test/test_floatobject.py
@@ -204,6 +204,21 @@
             assert pw(0.0, float("-inf")) == float("inf")
             assert math.isnan(pw(-3, float("nan")))
             assert math.isnan(pw(-3., float("nan")))
+            assert pw(-1.0, -float('inf')) == 1.0
+            assert pw(-1.0, float('inf')) == 1.0
+            assert pw(float('inf'), 0) == 1.0
+            assert pw(float('nan'), 0) == 1.0
+
+            assert math.isinf(pw(-0.5, float('-inf')))
+            assert math.isinf(pw(+0.5, float('-inf')))
+            assert pw(-1.5, float('-inf')) == 0.0
+            assert pw(+1.5, float('-inf')) == 0.0
+
+            assert str(pw(float('-inf'), -0.5)) == '0.0'
+            assert str(pw(float('-inf'), -2.0)) == '0.0'
+            assert str(pw(float('-inf'), -1.0)) == '-0.0'
+            assert str(pw(float('-inf'), 1.0)) == '-inf'
+            assert str(pw(float('-inf'), 2.0)) == 'inf'
 
     def test_pow_neg_base(self):
         import math


More information about the Pypy-commit mailing list