Question: Im currently trying to collect some weather data from an API, and to reduce the amount of API calls im trying to batch the calls on 0.5degree longitude and latitude chunks due to its resolution. I had this code def round_to_grid_center(coordinate,grid_spacing=0.5 ): offset = grid_spacing / 2 return round(((coordinate - offset) / grid_spacing)) * grid_spacing + offset  but this function rounded values at 0.5 down to 0.25 instead of up to 0.75,  so i added this fix. It works for me, but I'm sure there is a better more efficient method to round the coordinates to their closest grid square centre. Please let me know! def round_to_grid_center(coordinate,grid_spacing=0.5 ): #temp fix for round down error if ((coordinate % 0.5)== 0 and (coordinate % 1 )!= 0): offset = grid_spacing / 2 return round(((coordinate + 0.01 - offset) / grid_spacing)) * grid_spacing + offset else: offset = grid_spacing / 2 return round(((coordinate - offset) / grid_spacing)) * grid_spacing + offset  

Answer: Given: round half to even The round() function uses "round half to even" rounding mode, as mentioned in the Built-in Types doc, section Numeric types (emphasis by me):     Operation Result     round(x[, n]) x rounded to n digits, rounding half to even. If n is omitted, it defaults to 0.     "Rounding half to even" means that a floating point number with a decimal part of .5 is rounded towards the closest even integer rather than the closest greater integer. For example, both round(1.5) and round(2.5) will produce 2. In entry 5 (coordinate=38.5, grid_spacing=0.5, offset=0.25), you will consequently get round((38.5-0.25)/0.5)) = round(76.5) = 76, and thus a rounded-down result for the part of your calculation before spacing and offset correction. The Wikipedia article on rounding provides as motivation for this rounding mode:  This function minimizes the expected error when summing over rounded figures, even when the inputs are mostly positive or mostly negative, provided they are neither mostly even nor mostly odd.  If one needs further convincing that this rounding mode makes sense, one might want to have a look at the very detailed answer to this question ("rounding half to even" is called "banker's rounding" there). Required: round half up In any case, what you want is round half up instead. You can follow the answers to this question for potential solutions, e.g. rather than using round(x), you could use int(x + .5) or float(Decimal(x).to_integral_value(rounding=ROUND_HALF_UP)). Altogether, this could look as follows: from decimal import Decimal, ROUND_HALF_UP values = [(33.87, 151.21), (33.85, 151.22), ( 38.75, 149.85), (35.15, 150.85), (38.50, 149.87), (-38.50, 149.95)] def round_to_grid_center(coordinate, grid_spacing=0.5): offset = grid_spacing / 2 return round((coordinate - offset) / grid_spacing) * grid_spacing + offset def round_with_int(coordinate, grid_spacing=0.5): offset = grid_spacing / 2 return int(.5 + ((coordinate - offset) / grid_spacing)) * grid_spacing + offset def round_with_decimal(coordinate, grid_spacing=0.5): offset = grid_spacing / 2 return float(Decimal((coordinate - offset) / grid_spacing).to_integral_value(rounding=ROUND_HALF_UP)) * grid_spacing + offset for round_current in [round_to_grid_center, round_with_int, round_with_decimal]: print(f"\n{round_current.__name__}():") for i, (v1, v2) in enumerate(values): print(f"{i+1}: {v1}→{round_current(v1)}, {v2}→{round_current(v2)}")  Which prints: round_to_grid_center(): 1: 33.87→33.75, 151.21→151.25 2: 33.85→33.75, 151.22→151.25 3: 38.75→38.75, 149.85→149.75 4: 35.15→35.25, 150.85→150.75 5: 38.5→38.25, 149.87→149.75 6: -38.5→-38.75, 149.95→149.75 round_with_int(): 1: 33.87→33.75, 151.21→151.25 2: 33.85→33.75, 151.22→151.25 3: 38.75→38.75, 149.85→149.75 4: 35.15→35.25, 150.85→150.75 5: 38.5→38.75, 149.87→149.75 6: -38.5→-38.25, 149.95→149.75 round_with_decimal(): 1: 33.87→33.75, 151.21→151.25 2: 33.85→33.75, 151.22→151.25 3: 38.75→38.75, 149.85→149.75 4: 35.15→35.25, 150.85→150.75 5: 38.5→38.75, 149.87→149.75 6: -38.5→-38.75, 149.95→149.75  Note how the values differ for negative numbers though (which I included as entry 6): with int(), "up" means "towards positive infinity"; with Decimal, "up" means "away from zero". Last but not least – be aware of numerical imprecision in floating point representation and arithmetic: depending on the size of coordinate and the value of grid_spacing, round-off error may lead to unexpected results.