# Numpy ufunc

An ufunc in Numpy means Universal function, that operates on ndarrays in entry by entry manner, with support for typecasting, broadcasting, and many other different features. Universal functions are the instances of the numpy.ufunc class. Basically, an ufunc provides a vectorized wrapper for a function, that can take n scalar inputs and generates n scalar outputs.

Most of the predefined functions (ufunc) are implemented in compiled C code, but ufunc instances can be generated with the frompyfunc factory function too.

## What is the purpose ufuncs?

ufuncs can be used to implement vectorization. Vectorization is faster than iterating over elements.
ufunc provides broadcasting and additional methods like reduce, accumulate, etc to make computation easier.

A few additional arguments can also be given to ufuncs, such as,

• where boolean array or condition describing where the operations must be applied.
• dtype to define the return type of elements.
• out is an output array where the return value would be stored.

## Vectorization

Vector-based operations are faster and efficient in comparison to normal iteration based operations because modern CPUs are optimized for these operations. Transforming iterative statements into such operations is known as vectorization.

For example, adding two lists can be done using iteration, with the help of zip operation easily, for example,

```l1 = [1, 2, 3, 4]
l2 = [4, 5, 6, 7]
jointlist = []

for i, j in zip(l1, l2):
jointlist.append(i + j)
print(jointlist)

#Output
[5, 7, 9, 11]
```

The same operation on the same list elements can be performed using vectorization.

```import numpy as np

l1 = [1, 2, 3, 4]
l2 = [4, 5, 6, 7]

print(jointlist)

#Output
[ 5  7  9 11]
```

## Predefined ufuncs

There are more than 60 ufuncs made available Numpy itself. We can perform several operations using these ufuncs. A few of these are called automatically on the arrays, if a proper infix notation is applied, such as add(x, y), when only x+y is written and x and y both are ndarrays. However, we may still want to use additional argument(s), to keep the result into the object(s) of our desire.

Some available ufuncs are,

• add(x1, x2, /[, out, where, casting, order, ...]) Add arguments element-wise.
• subtract(x1, x2, /[, out, where, casting, ...]) Subtract arguments, element-wise.
• multiply(x1, x2, /[, out, where, casting, ...]) Multiply arguments element-wise.
• divide(x1, x2, /[, out, where, casting, ...]) Divide arguments element-wise.
• logaddexp(x1, x2, /[, out, where, casting, ...]) Logarithm of the sum of exponentiations of the inputs.
• logaddexp2(x1, x2, /[, out, where, casting, ...]) Logarithm of the sum of exponentiations of the inputs in base-2.
• true_divide(x1, x2, /[, out, where, ...]) Returns a true division of the inputs, element-wise.
• floor_divide(x1, x2, /[, out, where, ...]) Return the largest integer smaller or equal to the division of the inputs.
• negative(x, /[, out, where, casting, order, ...]) Numerical negative, element-wise.
• positive(x, /[, out, where, casting, order, ...]) Numerical positive, element-wise.
• power(x1, x2, /[, out, where, casting, ...]) First array elements raised to powers from second array, element-wise.
• remainder(x1, x2, /[, out, where, casting, ...]) Return element-wise remainder of division.
• mod(x1, x2, /[, out, where, casting, order, ...]) Return element-wise remainder of division.