Numba bug without warning

Bug report

##################
Here is a minimal code to demonstrate a bug I found.
This code can run smoothly without error and warning,
but it gives an unreasonable result, with output number ‘err1’ equals ‘err2’.
However, ‘err1’ and ‘err2’ should be of opposite sign.

#############################
import numba
import time
from numba import jit
from numba import prange
import numpy as np
test=np.arange(10000).reshape((100,100))

@jit(nopython=True,parallel=True)
def bug(test,pre,err1,err2):
for k in range(0,100):
pre=pre+test[k,0]
for k in prange(0,100):
err1=err1+test[k,0]
err2=err2-test[k,0]
return(err1,err2)

err1,err2=bug(test,0,0,0)
print(err1,err2)
##############################

I found there are two ways to overcome the bug.

  1. not use prange
  2. Delete the first loop at line 10 and line11
    But, still I’d like to know how the bug arises,in case of bugs appear without warning
    next time. By the way, Could please send a copy of you responce to my email baiyunfei@iphy.ac.cn
    Lookinng forward to your reply.
    Yours sincerely

Hey @bai ,

I assume the “bug” function is not thread safe.
In the “bug” function, each thread in the parallel loop reads the current values of err1 and err2, then adds or subtracts test[k, 0] and writes the new values back.

    for k in prange(0,100):
        err1=err1+test[k,0]
        err2=err2-test[k,0]

This may cause a race condition because multiple threads may read the same values of err1 and err2 before they get updated. As a result, the final sum may not be accurate.

To avoid this, you could use += and -= operators, which implicitly perform an atomic operation.
This ensures that only one thread can update the values of err1 and err2 at a time, avoiding the race condition.
Here is an example:

@jit(nopython=True,parallel=True)
def no_bug(test,pre,err1,err2):
    for k in range(0,100):
        pre=pre+test[k,0]
    for k in prange(0,100):
        err1+=test[k,0]
        err2-=test[k,0]
    return(err1,err2)

err1,err2=f2(test,0,0,0)
print(err1,err2)
# 495000 -495000

That answers my question. Thanks for your reply!
Yours sincerely