Repository: sympy/sympy

Issue:
Bidirectional limit of floor(sin(x)/x) at 0, is not correct
```python
>>> pprint(Limit(floor(sin(x)/x),x,0,'+-'))

    ⎢sin(x)⎥
lim ⎢──────⎥
x─→0⎣  x   ⎦

>>> limit(floor(sin(x)/x),x,0,'+')
1

>>> limit(floor(sin(x)/x),x,0,'-')
1
```
The correct limit should evaluate to 0.
Also confirmed from [WA](http://www.wolframalpha.com/input/?i=limit(floor(sin(x)%2Fx),x,0)).

Discussion:

Patch:
diff --git a/sympy/functions/elementary/integers.py b/sympy/functions/elementary/integers.py
index b91b2b19d8..92e71e5813 100644
--- a/sympy/functions/elementary/integers.py
+++ b/sympy/functions/elementary/integers.py
@@ -11,7 +11,7 @@
 from sympy.core.relational import Gt, Lt, Ge, Le, Relational, is_eq
 from sympy.core.symbol import Symbol
 from sympy.core.sympify import _sympify
-from sympy.functions.elementary.complexes import im
+from sympy.functions.elementary.complexes import im, re
 from sympy.multipledispatch import dispatch
 
 ###############################################################################
@@ -144,6 +144,9 @@ def _eval_as_leading_term(self, x, logx=None, cdir=0):
         arg = self.args[0]
         arg0 = arg.subs(x, 0)
         r = self.subs(x, 0)
+        if arg0 is S.NaN:
+            arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
+            r = floor(arg0)
         if arg0.is_finite:
             if arg0 == r:
                 if cdir == 0:
@@ -162,13 +165,16 @@ def _eval_as_leading_term(self, x, logx=None, cdir=0):
     def _eval_nseries(self, x, n, logx, cdir=0):
         arg = self.args[0]
         arg0 = arg.subs(x, 0)
+        r = self.subs(x, 0)
+        if arg0 is S.NaN:
+            arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
+            r = floor(arg0)
         if arg0.is_infinite:
             from sympy.calculus.accumulationbounds import AccumBounds
             from sympy.series.order import Order
             s = arg._eval_nseries(x, n, logx, cdir)
             o = Order(1, (x, 0)) if n <= 0 else AccumBounds(-1, 0)
             return s + o
-        r = self.subs(x, 0)
         if arg0 == r:
             ndir = arg.dir(x, cdir=cdir if cdir != 0 else 1)
             return r - 1 if ndir.is_negative else r
@@ -302,6 +308,9 @@ def _eval_as_leading_term(self, x, logx=None, cdir=0):
         arg = self.args[0]
         arg0 = arg.subs(x, 0)
         r = self.subs(x, 0)
+        if arg0 is S.NaN:
+            arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
+            r = ceiling(arg0)
         if arg0.is_finite:
             if arg0 == r:
                 if cdir == 0:
@@ -320,13 +329,16 @@ def _eval_as_leading_term(self, x, logx=None, cdir=0):
     def _eval_nseries(self, x, n, logx, cdir=0):
         arg = self.args[0]
         arg0 = arg.subs(x, 0)
+        r = self.subs(x, 0)
+        if arg0 is S.NaN:
+            arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
+            r = ceiling(arg0)
         if arg0.is_infinite:
             from sympy.calculus.accumulationbounds import AccumBounds
             from sympy.series.order import Order
             s = arg._eval_nseries(x, n, logx, cdir)
             o = Order(1, (x, 0)) if n <= 0 else AccumBounds(0, 1)
             return s + o
-        r = self.subs(x, 0)
         if arg0 == r:
             ndir = arg.dir(x, cdir=cdir if cdir != 0 else 1)
             return r if ndir.is_negative else r + 1


Test patch:
diff --git a/sympy/functions/elementary/tests/test_integers.py b/sympy/functions/elementary/tests/test_integers.py
index 4e44c0d2c2..73d97a593f 100644
--- a/sympy/functions/elementary/tests/test_integers.py
+++ b/sympy/functions/elementary/tests/test_integers.py
@@ -7,7 +7,7 @@
 from sympy.functions.elementary.exponential import (exp, log)
 from sympy.functions.elementary.integers import (ceiling, floor, frac)
 from sympy.functions.elementary.miscellaneous import sqrt
-from sympy.functions.elementary.trigonometric import sin
+from sympy.functions.elementary.trigonometric import sin, cos, tan
 
 from sympy.core.expr import unchanged
 from sympy.testing.pytest import XFAIL
@@ -548,6 +548,40 @@ def test_series():
     assert ceiling(-x).nseries(x, 0, 100) == 0
 
 
+def test_issue_14355():
+    # This test checks the leading term and series for the floor and ceil
+    # function when arg0 evaluates to S.NaN.
+    assert floor((x**3 + x)/(x**2 - x)).as_leading_term(x, cdir = 1) == -2
+    assert floor((x**3 + x)/(x**2 - x)).as_leading_term(x, cdir = -1) == -1
+    assert floor((cos(x) - 1)/x).as_leading_term(x, cdir = 1) == -1
+    assert floor((cos(x) - 1)/x).as_leading_term(x, cdir = -1) == 0
+    assert floor(sin(x)/x).as_leading_term(x, cdir = 1) == 0
+    assert floor(sin(x)/x).as_leading_term(x, cdir = -1) == 0
+    assert floor(-tan(x)/x).as_leading_term(x, cdir = 1) == -2
+    assert floor(-tan(x)/x).as_leading_term(x, cdir = -1) == -2
+    assert floor(sin(x)/x/3).as_leading_term(x, cdir = 1) == 0
+    assert floor(sin(x)/x/3).as_leading_term(x, cdir = -1) == 0
+    assert ceiling((x**3 + x)/(x**2 - x)).as_leading_term(x, cdir = 1) == -1
+    assert ceiling((x**3 + x)/(x**2 - x)).as_leading_term(x, cdir = -1) == 0
+    assert ceiling((cos(x) - 1)/x).as_leading_term(x, cdir = 1) == 0
+    assert ceiling((cos(x) - 1)/x).as_leading_term(x, cdir = -1) == 1
+    assert ceiling(sin(x)/x).as_leading_term(x, cdir = 1) == 1
+    assert ceiling(sin(x)/x).as_leading_term(x, cdir = -1) == 1
+    assert ceiling(-tan(x)/x).as_leading_term(x, cdir = 1) == -1
+    assert ceiling(-tan(x)/x).as_leading_term(x, cdir = 1) == -1
+    assert ceiling(sin(x)/x/3).as_leading_term(x, cdir = 1) == 1
+    assert ceiling(sin(x)/x/3).as_leading_term(x, cdir = -1) == 1
+    # test for series
+    assert floor(sin(x)/x).series(x, 0, 100, cdir = 1) == 0
+    assert floor(sin(x)/x).series(x, 0, 100, cdir = 1) == 0
+    assert floor((x**3 + x)/(x**2 - x)).series(x, 0, 100, cdir = 1) == -2
+    assert floor((x**3 + x)/(x**2 - x)).series(x, 0, 100, cdir = -1) == -1
+    assert ceiling(sin(x)/x).series(x, 0, 100, cdir = 1) == 1
+    assert ceiling(sin(x)/x).series(x, 0, 100, cdir = -1) == 1
+    assert ceiling((x**3 + x)/(x**2 - x)).series(x, 0, 100, cdir = 1) == -1
+    assert ceiling((x**3 + x)/(x**2 - x)).series(x, 0, 100, cdir = -1) == 0
+
+
 @XFAIL
 def test_issue_4149():
     assert floor(3 + pi*I + y*I) == 3 + floor(pi + y)*I
diff --git a/sympy/series/tests/test_limits.py b/sympy/series/tests/test_limits.py
index 6f7de1e357..4044d3784a 100644
--- a/sympy/series/tests/test_limits.py
+++ b/sympy/series/tests/test_limits.py
@@ -225,6 +225,14 @@ def test_ceiling_requires_robust_assumptions():
     assert limit(ceiling(5 + cos(x)), x, 0, "-") == 6
 
 
+def test_issue_14355():
+    assert limit(floor(sin(x)/x), x, 0, '+') == 0
+    assert limit(floor(sin(x)/x), x, 0, '-') == 0
+    # test comment https://github.com/sympy/sympy/issues/14355#issuecomment-372121314
+    assert limit(floor(-tan(x)/x), x, 0, '+') == -2
+    assert limit(floor(-tan(x)/x), x, 0, '-') == -2
+
+
 def test_atan():
     x = Symbol("x", real=True)
     assert limit(atan(x)*sin(1/x), x, 0) == 0