Repository: sympy/sympy

Issue:
proper conversion from decimal to float for nan and +/- inf
Conversion from decimal.Decimal to sympy.Float should work for nan and +/- infinity. Currently, conversion throws an exception for all of them.

    import decimal
    import sympy
    
    x = sympy.symbols('x')
    
    c_finite = decimal.Decimal('1.34551')
    c_nan = decimal.Decimal('nan')
    c_inf = decimal.Decimal('Infinity')
    c_neg_inf = decimal.Decimal('-Infinity')
    
    c_finite*x
    
    c_nan*x  # ValueError: invalid literal for int() with base 10: 'nan'
    c_inf*x  # ValueError: invalid literal for int() with base 10: 'infinity'
    c_neg_inf*x  # ValueError: invalid literal for int() with base 10: '-infinity'

This issue is being created coincident with a pull request to fix this, per development workflow guidelines.

Discussion:

Patch:
diff --git a/sympy/core/numbers.py b/sympy/core/numbers.py
index 13bbc6ab06..3b65841c01 100644
--- a/sympy/core/numbers.py
+++ b/sympy/core/numbers.py
@@ -719,7 +719,17 @@ def __new__(cls, num, prec=None):
         elif isinstance(num, str):
             _mpf_ = mlib.from_str(num, prec, rnd)
         elif isinstance(num, decimal.Decimal):
-            _mpf_ = mlib.from_str(str(num), prec, rnd)
+            if num.is_finite():
+                _mpf_ = mlib.from_str(str(num), prec, rnd)
+            elif num.is_nan():
+                _mpf_ = _mpf_nan
+            elif num.is_infinite():
+                if num > 0:
+                    _mpf_ = _mpf_inf
+                else:
+                    _mpf_ = _mpf_ninf
+            else:
+                raise ValueError("unexpected decimal value %s" % str(num))
         elif isinstance(num, Rational):
             _mpf_ = mlib.from_rational(num.p, num.q, prec, rnd)
         elif isinstance(num, tuple) and len(num) in (3, 4):
diff --git a/sympy/functions/elementary/exponential.py b/sympy/functions/elementary/exponential.py
index c11f07e62e..01559e77d8 100644
--- a/sympy/functions/elementary/exponential.py
+++ b/sympy/functions/elementary/exponential.py
@@ -676,7 +676,13 @@ def _eval_is_finite(self):
         return arg.is_finite
 
     def _eval_is_positive(self):
-        return (self.args[0] - 1).is_positive
+        arg = self.args[0]
+        if arg.is_positive:
+            if arg.is_infinite:
+                return True
+            if arg.is_zero:
+                return False
+            return (arg - 1).is_positive
 
     def _eval_is_zero(self):
         return (self.args[0] - 1).is_zero
diff --git a/sympy/functions/elementary/integers.py b/sympy/functions/elementary/integers.py
index 47464f9f91..e1062e0fa4 100644
--- a/sympy/functions/elementary/integers.py
+++ b/sympy/functions/elementary/integers.py
@@ -86,32 +86,25 @@ class floor(RoundFunction):
     value not greater than its argument. However this implementation
     generalizes floor to complex numbers.
 
-    Examples
-    ========
-
-    >>> from sympy import floor, E, I, Float, Rational
-    >>> floor(17)
-    17
-    >>> floor(Rational(23, 10))
-    2
-    >>> floor(2*E)
-    5
-    >>> floor(-Float(0.567))
-    -1
-    >>> floor(-I/2)
-    -I
+    More information can be found in "Concrete mathematics" by Graham,
+    pp. 87 or visit http://mathworld.wolfram.com/FloorFunction.html.
+
+        >>> from sympy import floor, E, I, Float, Rational
+        >>> floor(17)
+        17
+        >>> floor(Rational(23, 10))
+        2
+        >>> floor(2*E)
+        5
+        >>> floor(-Float(0.567))
+        -1
+        >>> floor(-I/2)
+        -I
 
     See Also
     ========
 
-    sympy.functions.elementary.integers.ceiling
-
-    References
-    ==========
-
-    .. [1] "Concrete mathematics" by Graham, pp. 87
-    .. [2] http://mathworld.wolfram.com/FloorFunction.html
-
+    ceiling
     """
     _dir = -1
 
@@ -157,32 +150,25 @@ class ceiling(RoundFunction):
     value not less than its argument. Ceiling function is generalized
     in this implementation to complex numbers.
 
-    Examples
-    ========
-
-    >>> from sympy import ceiling, E, I, Float, Rational
-    >>> ceiling(17)
-    17
-    >>> ceiling(Rational(23, 10))
-    3
-    >>> ceiling(2*E)
-    6
-    >>> ceiling(-Float(0.567))
-    0
-    >>> ceiling(I/2)
-    I
+    More information can be found in "Concrete mathematics" by Graham,
+    pp. 87 or visit http://mathworld.wolfram.com/CeilingFunction.html.
+
+        >>> from sympy import ceiling, E, I, Float, Rational
+        >>> ceiling(17)
+        17
+        >>> ceiling(Rational(23, 10))
+        3
+        >>> ceiling(2*E)
+        6
+        >>> ceiling(-Float(0.567))
+        0
+        >>> ceiling(I/2)
+        I
 
     See Also
     ========
 
-    sympy.functions.elementary.integers.floor
-
-    References
-    ==========
-
-    .. [1] "Concrete mathematics" by Graham, pp. 87
-    .. [2] http://mathworld.wolfram.com/CeilingFunction.html
-
+    floor
     """
     _dir = 1
 


Test patch:
diff --git a/sympy/core/tests/test_numbers.py b/sympy/core/tests/test_numbers.py
index caf229226c..c5f5537266 100644
--- a/sympy/core/tests/test_numbers.py
+++ b/sympy/core/tests/test_numbers.py
@@ -453,6 +453,9 @@ def teq(a):
     assert Float(S.One) == Float(1.0)
 
     assert Float(decimal.Decimal('0.1'), 3) == Float('.1', 3)
+    assert Float(decimal.Decimal('nan')) == S.NaN
+    assert Float(decimal.Decimal('Infinity')) == S.Infinity
+    assert Float(decimal.Decimal('-Infinity')) == S.NegativeInfinity
 
     assert '{0:.3f}'.format(Float(4.236622)) == '4.237'
     assert '{0:.35f}'.format(Float(pi.n(40), 40)) == '3.14159265358979323846264338327950288'
diff --git a/sympy/functions/elementary/tests/test_exponential.py b/sympy/functions/elementary/tests/test_exponential.py
index 708937531d..a2057365d8 100644
--- a/sympy/functions/elementary/tests/test_exponential.py
+++ b/sympy/functions/elementary/tests/test_exponential.py
@@ -261,10 +261,6 @@ def test_log_assumptions():
     p = symbols('p', positive=True)
     n = symbols('n', negative=True)
     z = symbols('z', zero=True)
-    x = symbols('x', infinite=True, positive=True)
-
-    assert log(z).is_positive is False
-    assert log(x).is_positive is True
     assert log(2) > 0
     assert log(1, evaluate=False).is_zero
     assert log(1 + z).is_zero