%%cython -a
# cython: boundscheck=False

from math import sin, cos

cdef inline double versine(double x): 
    return 1.0 - cos(x)

def versine_array_py(double[:] x):
    cdef int i, n = x.shape[0]
    for i in range(n):
        x[i] = versine(x[i])

"""
Explanation: 10 Secret trigonometry functions you never heard of!
Are you intrigued? Was the heading sufficiently click-baity?  See:
https://en.wikipedia.org/wiki/Versine and this blog
Let's make a Cython library for them!

Versine: versin(θ)=1-cos(θ)
Vercosine: vercosin(θ)=1+cos(θ)
Coversine: coversin(θ)=1-sin(θ)
Covercosine: covercosine(θ)=1+sin(θ)
Haversine: haversin(θ)=versin(θ)/2
Havercosine: havercosin(θ)=vercosin(θ)/2
Hacoversine: hacoversin(θ)=coversin(θ)/2
Hacovercosine: hacovercosin(θ)=covercosin(θ)/2
Exsecant: exsec(θ)=sec(θ)-1
Excosecant: excsc(θ)=csc(θ)-1

Approach 1: Using math from Python
Note: this is a Cython cell, and all variables are typed. This should be very fast
End of explanation
"""


%%cython -a
# cython: boundscheck=False

from libc.math cimport sin, cos

cdef inline double versine(double x): 
    return 1.0 - cos(x)

def versine_array_cy(double[:] x):
    cdef int i, n = x.shape[0]
    for i in range(n):
        x[i] = versine(x[i])

"""
Explanation: Approach 2: Using math from the C Standard Library
 This code is <u>exactly the same</u> as method1, all that's different is the call to a sin() function.
End of explanation
"""


import numpy

data = numpy.random.rand(10000)
%timeit versine_array_py(data)

data = numpy.random.rand(10000)
%timeit versine_array_cy(data)

"""
Explanation: Speed test
End of explanation
"""


from math import cos
def versine_array_pyonly(x):
    for i in range(len(x)):
        x[i] = 1 - cos(x[i])

data = numpy.random.rand(10000)
%timeit versine_array_pyonly(data)

"""
Explanation: Roughly 13 X slower than using C math directly
Remember, we used types for everything.  What about just plain Python?
End of explanation
"""


