Repository: sympy/sympy
Pull request: Fixes bug in Series
<!-- Your title above should be a short description of what
was changed. Do not include the issue number in the title. -->

#### References to other Issues or PRs
<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact
format, e.g. "Fixes #1234" (see
https://tinyurl.com/auto-closing for more information). Also, please
write a comment on that issue linking back to this pull request once it is
open. -->
#Fixes #10503
#### Brief description of what is fixed or changed
Now, 
`f=exp(x**3)*cos(x**6)`
`f.series(x, 0, 14)`
return correct result.

#### Other comments


#### Release Notes

<!-- Write the release notes for this release below. See
https://github.com/sympy/sympy/wiki/Writing-Release-Notes for more information
on how to write release notes. The bot will check your release notes
automatically to see if they are formatted correctly. -->

<!-- BEGIN RELEASE NOTES -->
NO ENTRY
<!-- END RELEASE NOTES -->

Problem statement:
Series return an incorrect result
The latest sympy master:

```
In [1]: f=exp(x**3)*cos(x**6)

In [2]: f.series(x, 0, 14)
Out[2]: 
          6    9    12         
     3   x    x    x      ⎛ 14⎞
1 + x  + ── + ── + ─── + O⎝x  ⎠
         2    6     24         

In [3]: f.series(x, 0, 19)
Out[3]: 
          6    9       12       15        18         
     3   x    x    11⋅x     59⋅x     179⋅x      ⎛ 19⎞
1 + x  + ── + ── - ────── - ────── - ─────── + O⎝x  ⎠
         2    6      24      120       720           
```

Hints from issue discussion:
This appears to be caused by the way `range(nterms)` works: `nterms` itself is not included on [this line](https://github.com/sympy/sympy/blob/master/sympy/core/function.py#L646). This is taken care of in many cases by the addition of 2 to the number of terms, but after division by the order `cf` of the argument the effect may be lost
In this example `cf` is 6:

```
    In [25]: series(cos(x**6), x, 0, 14)
Out[25]: 
     ⎛ 14⎞
1 + O⎝x  ⎠
```

With n + 2 = 16 `nterms` becomes `int(16/6) = 2`, and only the first two terms of the series of cos are taken into account, the constant 1 and the linear term 0.

Is this issue solved, i would like to work on it.

I is simple enough to not predict, but I am not sure what to put for the power of the Order term:

``` diff
diff --git a/sympy/core/function.py b/sympy/core/function.py
index 17f7d40..42a922c 100644
--- a/sympy/core/function.py
+++ b/sympy/core/function.py
@@ -548,6 +548,7 @@ def _eval_nseries(self, x, n, logx):
         """
         This function does compute series for multivariate functio
         but the expansion is always in terms of *one* variable.
+
         Examples
         ========

@@ -637,17 +638,15 @@ def _eval_nseries(self, x, n, logx):
             return e1.nseries(x, n=n, logx=logx)
         arg = self.args[0]
         l = []
+        i = 0
         g = None
-        # try to predict a number of terms needed
-        nterms = n + 2
-        cf = Order(arg.as_leading_term(x), x).getn()
-        if cf != 0:
-            nterms = int(nterms / cf)
-        for i in range(nterms):
+        while len(l) != n:
             g = self.taylor_term(i, arg, g)
             g = g.nseries(x, n=n, logx=logx)
-            l.append(g)
-        return Add(*l) + Order(x**n, x)
+            if g:
+                l.append(g)
+            i += 1  # can we be smarter about skipping terms?
+        return Add(*l) + Order(x**???, x)

     def fdiff(self, argindex=1):
```

Commit message: added spaces around '='

Patch to review:
diff --git a/sympy/core/function.py b/sympy/core/function.py
index 386141961350..547235801e34 100644
--- a/sympy/core/function.py
+++ b/sympy/core/function.py
@@ -716,17 +716,15 @@ def _eval_nseries(self, x, n, logx):
             return e1.nseries(x, n=n, logx=logx)
         arg = self.args[0]
         l = []
+        i = 0
         g = None
-        # try to predict a number of terms needed
-        nterms = n + 2
-        cf = Order(arg.as_leading_term(x), x).getn()
-        if cf != 0:
-            nterms = int(nterms / cf)
-        for i in range(nterms):
+        while len(l) <= n:
             g = self.taylor_term(i, arg, g)
             g = g.nseries(x, n=n, logx=logx)
-            l.append(g)
-        return Add(*l) + Order(x**n, x)
+            if g:
+                l.append(g)
+            i += 1
+        return Add(*l) + Order(g,x)
 
     def fdiff(self, argindex=1):
         """
diff --git a/sympy/core/tests/test_function.py b/sympy/core/tests/test_function.py
index 97bb7d3e11ab..6ed938d4b250 100644
--- a/sympy/core/tests/test_function.py
+++ b/sympy/core/tests/test_function.py
@@ -1350,3 +1350,8 @@ def test_Derivative_free_symbols():
     f = Function('f')
     n = Symbol('n', integer=True, positive=True)
     assert diff(f(x), (x, n)).free_symbols == {n, x}
+
+
+def test_issue_10503():
+    f = exp(x**3)*cos(x**6)
+    assert f.series(x, 0, 14) == 1 + x**3 + x**6/2 + x**9/6 - 11*x**12/24 + O(x**14)


Code review comments:
diff_hunk: @@ -716,17 +716,15 @@ def _eval_nseries(self, x, n, logx):
             return e1.nseries(x, n=n, logx=logx)
         arg = self.args[0]
         l = []
+        i = 0
         g = None
-        # try to predict a number of terms needed
-        nterms = n + 2
-        cf = Order(arg.as_leading_term(x), x).getn()
-        if cf != 0:
-            nterms = int(nterms / cf)
-        for i in range(nterms):
+        while len(l) <= n:
path: sympy/core/function.py
text: @user1:
This is inefficient. `n` is not the number of terms but the order (exponent of the order term). For `cos(x**6).series(x, 0, 14)`  this loop would compute 14 non-zero terms though only 2 are needed (3 if also the linear term `0*arg` is counted).

@author:
Okay I will done the changes suggested by you.