Differences between Numpy divide and Python divide?

What are the similarities and differences between numpy.divide and the Python slash / operator? As far as I can tell they behave the same, both implementing an element-wise division. The Numpy documentation mentions:

numpy.divide(x1, x2) ... Equivalent to x1 / x2 in terms of array-broadcasting. ...

Implying that np.divide(x1, x2) is not completely equivalent to x1 / x2. I have run the following snippet to compare their speed:

import numpy as np
import time

a = np.random.rand(10000, 10000)
b = np.random.rand(10000, 10000)

tic = time.time()
c = a / b
toc = time.time()
print("Python divide took: ", toc - tic)

tic = time.time()
c = np.divide(a, b)
toc = time.time()
print("Numpy divide took: ", toc - tic)

It appears that the Python divide generally runs faster which leads me to believe the Numpy divide implements some additional bells and whistles.

Any help is much appreciated!


Solution 1:

There doesn't appear to be any actual performance difference here.

When I run your code, and swap the two tests, whichever one comes second goes faster.

When I use timeit for proper benchmarking, they take about the same time (540ms for / vs. 539ms for divide).

My guess would be that the difference you measured was the time to malloc the array—the first one needs to do that, the second one can reuse the memory that just got freed.


But let's look at the source. The code in generate_umath.py creates the actual code, and it's assigning the same Ufunc (named numpy.core.umath.divide) to np.floor_divide and to the PyNumber_FloorDivide slot for np.ndarray. (If you're wondering why I looked up floor_divide when you're using divide and / instead of floor_divide and //, see the comment later where it deletes divide for Python 3 because it will be aliased it to true_divide.) IIRC, the actual code is a switch on types and sizes that ultimately ends up in one of the loop templates in loops.c.src.

So, beyond the differences in explicit Ufunc wrapper code vs. builtin method-wrapper wrapper code (which is going to be irrelevant for any array that isn't tiny), they end up in the same place.