Wrap integer values to fixed range

I had a project where I wanted to select a window of days centered on a specific day of year (DOY), but the window had to also be defined by DOY. For example, for DOY 2 (Jan. 2nd), a 7 day window (3 before and 3 after) would go from DOY 364 (Dec. 30th, non-leap years) to DOY 5 (Jan. 5th). This could probably be done using Python datetime objects or some built-in Python module, but I also needed to implement this in JavaScript and on Google Earth Engine also, so I thought it would be fun to come up with a generic algorithm.

It seemed like the modulo operator (%) would be a good place to start. For the range 0-n, x % n for x > 0 will be the correctly wrapped value.

x_list = range(8, 23)
print(x_list)
[8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
print([x % 10 for x in x_list])
[8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2]

In Python, the modulo operator gets the sign of the output from the divisor. So for negative values the modulo will still correctly wrap the value.

x_list = range(-12,3)
print(x_list)
[-12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2]
print([x % 10 for x in x_list])
[8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2]

This doesn’t work in JavaScript though, or any language where the sign of the output comes from the dividend. To show this in Python you can use the to get the sign from the dividend.

import math
x_list = range(-12,3)
print(x_list)
[-12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2]
print([int(math.fmod(x,10)) for x in x_list])
[-2, -1, 0, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1]

The divisor based modulo operator can be implemented from the dividend based one as:
((x % n) + n) % n

import math
x_list = range(-12,3)
print(x_list)
[-12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2]
print([int(math.fmod(math.fmod(x,10) + 10, 10)) for x in x_list])
[8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2]

This will wrap values to the range 0-n, but what about the range a-b? For this I decided to just shift the range down to 0-n, wrap the values, then shift them back to a-b.
(x - a) % (b - a + 1) + a

The following Python example will wrap the values to the range 2-7. To do the same thing in Earth Engine or JavaScript just means including the extra operations from above.

a = 2
b = 7
x_list = range(-5,12)
print(x_list)
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
print([((x - a) % (b - a + 1) + a) for x in x_list])
[7, 2, 3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 7, 2, 3, 4, 5]
Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s