[pypy-svn] pypy cmath: (david, lac, arigo)

arigo commits-noreply at bitbucket.org
Tue Jan 18 13:02:52 CET 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: cmath
Changeset: r40841:b621137f9070
Date: 2011-01-18 12:23 +0100
http://bitbucket.org/pypy/pypy/changeset/b621137f9070/

Log:	(david, lac, arigo)

	Fix for translating -0.0, avoiding confusion with 0.0 in a couple of
	places.

diff --git a/pypy/translator/c/test/test_genc.py b/pypy/translator/c/test/test_genc.py
--- a/pypy/translator/c/test/test_genc.py
+++ b/pypy/translator/c/test/test_genc.py
@@ -269,25 +269,40 @@
     res = f1(3)
     assert res == 1.5
 
-def test_nan():
+def test_nan_and_special_values():
     from pypy.translator.c.primitive import isnan, isinf
+    from pypy.rlib.rarithmetic import copysign
     inf = 1e300 * 1e300
     assert isinf(inf)
     nan = inf/inf
     assert isnan(nan)
 
-    l = [nan]
-    def f():
-        return nan
-    f1 = compile(f, [])
-    res = f1()
-    assert isnan(res)
+    for value, checker in [
+            (inf,   lambda x: isinf(x) and x > 0.0),
+            (-inf,  lambda x: isinf(x) and x < 0.0),
+            (nan,   isnan),
+            (0.0,   lambda x: not x and copysign(1., x) == 1.),
+            (-0.0,  lambda x: not x and copysign(1., x) == -1.),
+            ]:
+        def f():
+            return value
+        f1 = compile(f, [])
+        res = f1()
+        assert checker(res)
 
-    def g(x):
-        return l[x]
-    g2 = compile(g, [int])
-    res = g2(0)
-    assert isnan(res)
+        l = [value]
+        def g(x):
+            return l[x]
+        g2 = compile(g, [int])
+        res = g2(0)
+        assert checker(res)
+
+        l2 = [(-value, -value), (value, value)]
+        def h(x):
+            return l2[x][1]
+        h3 = compile(h, [int])
+        res = h3(1)
+        assert checker(res)
 
 def test_prebuilt_instance_with_dict():
     class A:

diff --git a/pypy/annotation/model.py b/pypy/annotation/model.py
--- a/pypy/annotation/model.py
+++ b/pypy/annotation/model.py
@@ -163,11 +163,16 @@
     immutable = True
 
     def __eq__(self, other):
-        # NaN unpleasantness.
         if (type(self) is SomeFloat and type(other) is SomeFloat and
-            self.is_constant() and other.is_constant() and
-            isnan(self.const) and isnan(other.const)):
-            return True
+            self.is_constant() and other.is_constant()):
+            # NaN unpleasantness.
+            if isnan(self.const) and isnan(other.const):
+                return True
+            # 0.0 vs -0.0 unpleasantness.
+            if not self.const and not other.const:
+                from pypy.rlib.rarithmetic import copysign
+                return copysign(1., self.const) == copysign(1., other.const)
+            #
         return super(SomeFloat, self).__eq__(other)
 
     def can_be_none(self):

diff --git a/pypy/tool/uid.py b/pypy/tool/uid.py
--- a/pypy/tool/uid.py
+++ b/pypy/tool/uid.py
@@ -38,26 +38,36 @@
     key in dictionaries.  This is based on id() for mutable objects and on
     real hash/compare for immutable ones.
     """
-    __slots__ = ["key", "value"]
+    __slots__ = ["_key", "value"]
     
     def __init__(self, value):
         self.value = value     # a concrete value
         # try to be smart about constant mutable or immutable values
         key = type(self.value), self.value  # to avoid confusing e.g. 0 and 0.0
+        #
+        # we also have to avoid confusing 0.0 and -0.0 (needed e.g. for
+        # translating the cmath module)
+        if key[0] is float and not self.value:
+            from pypy.rlib.rarithmetic import copysign
+            if copysign(1., self.value) == 1.:    # +0.0
+                key = (float, "+0.0")
+            else:
+                key = (float, "-0.0")
+        #
         try:
             hash(key)
         except TypeError:
             key = id(self.value)
-        self.key = key
+        self._key = key
 
     def __eq__(self, other):
-        return self.__class__ is other.__class__ and self.key == other.key
+        return self.__class__ is other.__class__ and self._key == other._key
 
     def __ne__(self, other):
         return not (self == other)
 
     def __hash__(self):
-        return hash(self.key)
+        return hash(self._key)
 
     def __repr__(self):
         return '(%s)' % (self,)


More information about the Pypy-commit mailing list