Repository: numba/numba

Issue:
Unexpected behaviour of numpy.linspace within am njitted funciton
<!--

Thanks for opening an issue! To help the Numba team handle your information
efficiently, please first ensure that there is no other issue present that
already describes the issue you have
(search at https://github.com/numba/numba/issues?&q=is%3Aissue).

-->

## Reporting a bug

<!--

Before submitting a bug report please ensure that you can check off these boxes:

-->

- [x ] I have tried using the latest released version of Numba (most recent is
 visible in the change log (https://github.com/numba/numba/blob/master/CHANGE_LOG).
Numba version: 0.54.0

**Summary.**
np.linspace() within a njitted func is not behaving the same than np.linspace() alone. The 'stop' number is surpassed by +1e-6

**Explanation.**
Hi there!
I have a function that generates an array of 'num' values from 0 to 100. I use numpy linspace since 'num' is determined by the size of another array within the function, so for me, it's quite agile. Now, this linspace function is used thousands of times, and very few times, it generates a wrong linspace output array. I can't share the data because it comes from several databases and the error can only be replied in very few (specific) cases, but maybe this image might help:

![image](https://user-images.githubusercontent.com/83791151/132054447-ec634d0e-e39b-4cb4-9482-cfb146cc2804.png)


When I use the function without the numba decorator, np.linspace is not giving this problem ever, works fine. When I use it with the njit, it only breaks very few times (like 15 time out of thousands), but I guess that's an unexpected behaviour. It might be related with the lenght of 'num', because it always breaks with the same input datasets

In the image above the length used for np.linspace is num=1298

In my particular case, I can solve this by just making the np.linspace(0,99.9999,num), because the code does not allow any number larger than 100. Yet, I guess that feedback might be helpful, at least for the record

Thanks a lot for your time! And for Numba!





Discussion:

Resolving patch:
diff --git a/numba/np/arrayobj.py b/numba/np/arrayobj.py
--- a/numba/np/arrayobj.py
+++ b/numba/np/arrayobj.py
@@ -4074,11 +4074,13 @@ def linspace(start, stop, num):
         div = num - 1
         if div > 0:
             delta = stop - start
-            step = delta / div
+            step = np.divide(delta, div)
             for i in range(0, num):
                 arr[i] = start + (i * step)
         else:
             arr[0] = start
+        if num > 1:
+            arr[-1] = stop
         return arr
 
     res = context.compile_internal(builder, linspace, sig, args)


Test patch:
diff --git a/numba/tests/test_dyn_array.py b/numba/tests/test_dyn_array.py
--- a/numba/tests/test_dyn_array.py
+++ b/numba/tests/test_dyn_array.py
@@ -1241,7 +1241,7 @@ def pyfunc(n, m):
             return np.linspace(n, m)
         self.check_outputs(pyfunc,
                            [(0, 4), (1, 100), (-3.5, 2.5), (-3j, 2+3j),
-                            (2, 1), (1+0.5j, 1.5j)], exact=False)
+                            (2, 1), (1+0.5j, 1.5j)])
 
     def test_linspace_3(self):
         def pyfunc(n, m, p):
@@ -1249,8 +1249,7 @@ def pyfunc(n, m, p):
         self.check_outputs(pyfunc,
                            [(0, 4, 9), (1, 4, 3), (-3.5, 2.5, 8),
                             (-3j, 2+3j, 7), (2, 1, 0),
-                            (1+0.5j, 1.5j, 5), (1, 1e100, 1)],
-                           exact=False)
+                            (1+0.5j, 1.5j, 5), (1, 1e100, 1)])
 
     def test_linspace_accuracy(self):
         # Checking linspace reasonably replicates NumPy's algorithm