In [1]:
n1=500
n2=500
arr=np.random.randn(n1,n2)

Python, Numpy


In [2]:
def normal_py(arr,n1,n2):
    mxabs=0.
    for i1 in xrange(n1):
        for i2 in xrange(n2):
            val=abs(arr[i1,i2])
            if val > mxabs: mxabs=val
    for i1 in xrange(n1):
        for i2 in xrange(n2):
            arr[i1,i2]/=mxabs
    return arr

def normal_np(arr):
    return arr/abs(arr).max()

In [3]:
%timeit -r 3 -n 10 normal_py(arr,n1,n2)


10 loops, best of 3: 209 ms per loop

In [4]:
%timeit -r 3 -n 10 normal_np(arr)


10 loops, best of 3: 678 µs per loop

Numba


In [5]:
from numba import autojit
normal_nb=autojit(normal_py)

In [6]:
%timeit -r 3 -n 10 normal_nb(arr,n1,n2)


10 loops, best of 3: 1.02 ms per loop

Cython


In [1]:
%load_ext cythonmagic

In [2]:
%%cython
import cython
cimport numpy as np

@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
def normal_cy(np.ndarray[double,ndim=2] arr,int n1,int n2):
    cdef double val,mxabs=0.
    cdef int i1,i2
    for i1 in xrange(n1):
        for i2 in xrange(n2):
            val=abs(arr[i1,i2])
            if val > mxabs: mxabs=val
    for i1 in xrange(n1):
        for i2 in xrange(n2):
            arr[i1,i2]/=mxabs
    return arr

In [9]:
%timeit -r 3 -n 10 normal_cy(arr,n1,n2)


10 loops, best of 3: 801 µs per loop

Fortran


In [10]:
%%file normal.f90

subroutine normal(arr_out,arr,n1,n2)
implicit none
integer,intent(in):: n1,n2
real(kind=8),intent(in):: arr(n1,n2)
real(kind=8),intent(out):: arr_out(n1,n2)
integer i1,i2
real(kind=8):: mxabs,val
mxabs=0.d0
do i2=1,n2
do i1=1,n1
    val=arr(i1,i2)
    if(val>mxabs) mxabs=val
enddo
enddo
do i2=1,n2
do i1=1,n1
    arr_out(i1,i2)=arr(i1,i2)/mxabs
enddo
enddo
end subroutine

subroutine normal_v(arr_out,arr,n1,n2)
implicit none
integer,intent(in):: n1,n2
real(kind=8),intent(in):: arr(n1,n2)
real(kind=8),intent(out):: arr_out(n1,n2)
arr_out=arr/maxval(abs(arr))
end subroutine


Overwriting normal.f90

In [11]:
!f2py -c -m normal_f normal.f90 --f90exec=/opt/local/bin/gfortran-mp-4.9 > log.txt

In [12]:
import normal_f
print normal_f.__doc__


This module 'normal_f' is auto-generated with f2py (version:2).
Functions:
  arr_out = normal(arr,n1=shape(arr,0),n2=shape(arr,1))
  arr_out = normal_v(arr,n1=shape(arr,0),n2=shape(arr,1))
.

In [13]:
arr_t=arr.T

In [14]:
%timeit -r 3 -n 10 normal_f.normal(arr_t)


10 loops, best of 3: 834 µs per loop

In [15]:
%timeit -r 3 -n 10 normal_f.normal_v(arr_t)


10 loops, best of 3: 579 µs per loop

In [16]:
r=normal_py(arr,n1,n2)
print r.max(),r.min()
imshow(r)


0.977602407298 -1.0
Out[16]:
<matplotlib.image.AxesImage at 0x10c907d50>

In [17]:
r=normal_np(arr)
print r.max(),r.min()
imshow(r)


0.977602407298 -1.0
Out[17]:
<matplotlib.image.AxesImage at 0x10fca16d0>

In [18]:
r=normal_nb(arr,n1,n2)
print r.max(),r.min()
imshow(r)


0.977602407298 -1.0
Out[18]:
<matplotlib.image.AxesImage at 0x10fd3f710>

In [19]:
r=normal_cy(arr,n1,n2)
print r.max(),r.min()
imshow(r)


0.977602407298 -1.0
Out[19]:
<matplotlib.image.AxesImage at 0x10fd6dbd0>

In [20]:
r=normal_f.normal_v(arr_t).T
print r.max(),r.min()
imshow(r)


0.977602407298 -1.0
Out[20]:
<matplotlib.image.AxesImage at 0x10fd99fd0>

In [20]: