Reputation: 2469
What is the equivalent of math.remainder()
function in NumPy? Basically I would like to compute y = x - np.around(x)
for a NumPy array x
. (It is important that all elements of y
have absolute at most 1/2). Looking at NumPy documentation neither np.fmod
nor np.remainder
do the job.
Obviously, I thought about writing x - np.around(x)
but I am afraid that for large values of x
subtraction produces floating-point inaccuracies. For example:
import numpy as np
a = np.arange(1000) * 1e-9
x = a / 1e-9
y = x - np.around(x)
Should produce an all-zero vector y
, but in practice there will be some errors (that get larger if I increase the size of arrays from 1000 to 10000).
The reason I am asking this question is to figure out if there is a NumPy function for this purpose that calls directly C math library remainder
(as math.remainder
must do) so as to minimize the floating-points errors.
Upvotes: 2
Views: 498
Reputation: 9572
IMO, vectorize is the correct solution.
However, if it's considered too slow, I suggest using this:
Like this:
def np_remainder(x,y)
positive_modulo = x % y
centered_modulo = positive_modulo - y * numpy.rint(positive_modulo / y)
return centered_modulo
I think that numpy.fmod is exact, and using it avoid the problems of large rint values.
Since rint will be either 0 or 1 for y>0, the second operation will also be exact (either subtract 0 or y, which should be exact thanks to Sterbenz lemna).
Hence, the formulation above should not introduce any inaccuracy, unlike the raw formulation.
The difference with numpy.vectorize(math.remainder)
will be on edge cases of exact tie:
Upvotes: 0
Reputation: 16213
I don't think this currently exists numpy
. That said, the automagic numpy.vectorize
call does the right thing for me, e.g:
import math
import numpy as np
ieee_remainder = np.vectorize(math.remainder)
ieee_remainder(np.arange(5), 5)
this broadcasts over the parameters nicely, giving:
array([ 0., 1., 2., -2., -1.])
which might be what you want.
performance is about 10 times slower than you'd get with a native implementation. given an array of 10,000 elements my laptop takes approximately the following times:
ieee_remainder
numpy.fmod
given the complexity of glibc's remainder
implementation I'm amazed it's as fast as it is.
Upvotes: 2