changeset 15050:73f4e0e490b7 draft

(svn r19670) -Codechange: Add CeilDiv() and RoundDiv() to simplify integer divisions with rounding.
author frosch <frosch@openttd.org>
date Sun, 18 Apr 2010 14:56:05 +0000
parents 177c89d03be1
children 11b01bb094e0
files src/aircraft_cmd.cpp src/autoreplace_cmd.cpp src/core/math_func.hpp src/depot_gui.cpp src/economy.cpp src/gfx.cpp src/industry_cmd.cpp src/map_func.h src/pathfinder/yapf/yapf_costrail.hpp src/smallmap_gui.cpp src/station_gui.cpp src/terraform_gui.cpp src/timetable_cmd.cpp src/toolbar_gui.cpp src/viewport.cpp
diffstat 15 files changed, 50 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/src/aircraft_cmd.cpp
+++ b/src/aircraft_cmd.cpp
@@ -1061,7 +1061,7 @@
 
 			/* Only start lowering when we're sufficiently close for a 1:1 glide */
 			if (delta >= t) {
-				z -= ((z - curz) + t - 1) / t;
+				z -= CeilDiv(z - curz, t);
 			}
 			if (z < curz) z = curz;
 		}
--- a/src/autoreplace_cmd.cpp
+++ b/src/autoreplace_cmd.cpp
@@ -412,7 +412,7 @@
 
 	if (old_head->type == VEH_TRAIN) {
 		/* Store the length of the old vehicle chain, rounded up to whole tiles */
-		uint16 old_total_length = (Train::From(old_head)->tcache.cached_total_length + TILE_SIZE - 1) / TILE_SIZE * TILE_SIZE;
+		uint16 old_total_length = CeilDiv(Train::From(old_head)->tcache.cached_total_length, TILE_SIZE) * TILE_SIZE;
 
 		int num_units = 0; ///< Number of units in the chain
 		for (Train *w = Train::From(old_head); w != NULL; w = w->GetNextUnit()) num_units++;
--- a/src/core/math_func.hpp
+++ b/src/core/math_func.hpp
@@ -318,4 +318,26 @@
 int LeastCommonMultiple(int a, int b);
 int GreatestCommonDivisor(int a, int b);
 
+/**
+ * Computes ceil(a / b) for non-negative a and b.
+ * @param a Numerator
+ * @param b Denominator
+ * @return Quotient, rounded up
+ */
+static FORCEINLINE uint CeilDiv(uint a, uint b)
+{
+	return (a + b - 1) / b;
+}
+
+/**
+ * Computes round(a / b) for non-negative a and b.
+ * @param a Numerator
+ * @param b Denominator
+ * @return Quotient, rounded to nearest
+ */
+static FORCEINLINE uint RoundDiv(uint a, uint b)
+{
+	return (a + b / 2) / b;
+}
+
 #endif /* MATH_FUNC_HPP */
--- a/src/depot_gui.cpp
+++ b/src/depot_gui.cpp
@@ -259,7 +259,7 @@
 				DrawTrainImage(u, image_left + (rtl ? 0 : x_space), image_right - (rtl ? x_space : 0), sprite_y - 1, this->sel, free_wagon ? 0 : this->hscroll.GetPosition());
 
 				/* Number of wagons relative to a standard length wagon (rounded up) */
-				SetDParam(0, (u->tcache.cached_total_length + 7) / 8);
+				SetDParam(0, CeilDiv(u->tcache.cached_total_length, 8));
 				DrawString(rtl ? left + WD_FRAMERECT_LEFT : right - this->count_width, rtl ? left + this->count_width : right - WD_FRAMERECT_RIGHT, y + (this->resize.step_height - FONT_HEIGHT_SMALL) / 2, STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT); // Draw the counter
 				break;
 			}
@@ -692,7 +692,7 @@
 			this->vscroll.SetCount(this->vehicle_list.Length() + this->wagon_list.Length() + 1);
 			this->hscroll.SetCount(max_width);
 		} else {
-			this->vscroll.SetCount((this->vehicle_list.Length() + this->hscroll.GetCapacity() - 1) / this->hscroll.GetCapacity());
+			this->vscroll.SetCount(CeilDiv(this->vehicle_list.Length(), this->hscroll.GetCapacity()));
 		}
 
 		/* Setup disabled buttons. */
--- a/src/economy.cpp
+++ b/src/economy.cpp
@@ -1165,7 +1165,7 @@
 		byte load_amount = e->info.load_amount;
 
 		/* The default loadamount for mail is 1/4 of the load amount for passengers */
-		if (v->type == VEH_AIRCRAFT && !Aircraft::From(v)->IsNormalAircraft()) load_amount = (load_amount + 3) / 4;
+		if (v->type == VEH_AIRCRAFT && !Aircraft::From(v)->IsNormalAircraft()) load_amount = CeilDiv(load_amount, 4);
 
 		if (_settings_game.order.gradual_loading && HasBit(e->info.callback_mask, CBM_VEHICLE_LOAD_AMOUNT)) {
 			uint16 cb_load_amount = GetVehicleCallback(CBID_VEHICLE_LOAD_AMOUNT, 0, 0, v->engine_type, v);
--- a/src/gfx.cpp
+++ b/src/gfx.cpp
@@ -550,8 +550,7 @@
 				break;
 
 			case SA_CENTER:
-				/* The second + 1 is to round to the closest number */
-				left  = (initial_right + 1 + initial_left - w + 1) / 2;
+				left  = RoundDiv(initial_right + 1 + initial_left - w, 2);
 				/* right + 1 = left + w */
 				right = left + w - 1;
 				break;
@@ -824,7 +823,7 @@
 		total_height = (num + 1) * mt;
 	}
 
-	int y = (align == SA_CENTER) ? (bottom + top - total_height + 1) / 2 : top;
+	int y = (align == SA_CENTER) ? RoundDiv(bottom + top - total_height, 2) : top;
 	const char *src = buffer;
 
 	for (;;) {
@@ -1324,8 +1323,8 @@
 
 void ScreenSizeChanged()
 {
-	_dirty_bytes_per_line = (_screen.width + DIRTY_BLOCK_WIDTH - 1) / DIRTY_BLOCK_WIDTH;
-	_dirty_blocks = ReallocT<byte>(_dirty_blocks, _dirty_bytes_per_line * ((_screen.height + DIRTY_BLOCK_HEIGHT - 1) / DIRTY_BLOCK_HEIGHT));
+	_dirty_bytes_per_line = CeilDiv(_screen.width, DIRTY_BLOCK_WIDTH);
+	_dirty_blocks = ReallocT<byte>(_dirty_blocks, _dirty_bytes_per_line * CeilDiv(_screen.height, DIRTY_BLOCK_HEIGHT));
 
 	/* check the dirty rect */
 	if (_invalid_rect.right >= _screen.width) _invalid_rect.right = _screen.width;
--- a/src/industry_cmd.cpp
+++ b/src/industry_cmd.cpp
@@ -2332,8 +2332,8 @@
 	 * For non-smooth economy these should always be synchronized with prod_level */
 	if (recalculate_multipliers) {
 		/* Rates are rounded up, so e.g. oilrig always produces some passengers */
-		i->production_rate[0] = min((indspec->production_rate[0] * i->prod_level + PRODLEVEL_DEFAULT - 1) / PRODLEVEL_DEFAULT, 0xFF);
-		i->production_rate[1] = min((indspec->production_rate[1] * i->prod_level + PRODLEVEL_DEFAULT - 1) / PRODLEVEL_DEFAULT, 0xFF);
+		i->production_rate[0] = min(CeilDiv(indspec->production_rate[0] * i->prod_level, PRODLEVEL_DEFAULT), 0xFF);
+		i->production_rate[1] = min(CeilDiv(indspec->production_rate[1] * i->prod_level, PRODLEVEL_DEFAULT), 0xFF);
 	}
 
 	/* Close if needed and allowed */
--- a/src/map_func.h
+++ b/src/map_func.h
@@ -12,6 +12,7 @@
 #ifndef MAP_FUNC_H
 #define MAP_FUNC_H
 
+#include "core/math_func.hpp"
 #include "tile_type.h"
 #include "map_type.h"
 #include "direction_func.h"
@@ -126,9 +127,8 @@
 static inline uint ScaleByMapSize(uint n)
 {
 	/* Subtract 12 from shift in order to prevent integer overflow
-	 * for large values of n. It's safe since the min mapsize is 64x64.
-	 * Add (1<<4)-1 to round upwards. */
-	return ((n << (MapLogX() + MapLogY() - 12)) + (1 << 4) - 1) >> 4;
+	 * for large values of n. It's safe since the min mapsize is 64x64. */
+	return CeilDiv(n << (MapLogX() + MapLogY() - 12), 1 << 4);
 }
 
 
@@ -142,9 +142,8 @@
 {
 	/* Normal circumference for the X+Y is 256+256 = 1<<9
 	 * Note, not actually taking the full circumference into account,
-	 * just half of it.
-	 * (1<<9) - 1 is there to scale upwards. */
-	return ((n << MapLogX()) + (n << MapLogY()) + (1 << 9) - 1) >> 9;
+	 * just half of it. */
+	return CeilDiv((n << MapLogX()) + (n << MapLogY()), 1 << 9);
 }
 
 /**
--- a/src/pathfinder/yapf/yapf_costrail.hpp
+++ b/src/pathfinder/yapf/yapf_costrail.hpp
@@ -259,7 +259,7 @@
 		assert(v != NULL);
 		assert(v->type == VEH_TRAIN);
 		assert(v->tcache.cached_total_length != 0);
-		int missing_platform_length = (v->tcache.cached_total_length + TILE_SIZE - 1) / TILE_SIZE - platform_length;
+		int missing_platform_length = CeilDiv(v->tcache.cached_total_length, TILE_SIZE) - platform_length;
 		if (missing_platform_length < 0) {
 			/* apply penalty for longer platform than needed */
 			cost += Yapf().PfGetSettings().rail_longer_platform_penalty + Yapf().PfGetSettings().rail_longer_platform_per_tile_penalty * -missing_platform_length;
--- a/src/smallmap_gui.cpp
+++ b/src/smallmap_gui.cpp
@@ -984,7 +984,7 @@
 	 */
 	inline uint GetMaxLegendHeight() const
 	{
-		uint num_rows = max(this->min_number_of_fixed_rows, (_smallmap_industry_count + this->min_number_of_columns - 1) / this->min_number_of_columns);
+		uint num_rows = max(this->min_number_of_fixed_rows, CeilDiv(_smallmap_industry_count, this->min_number_of_columns));
 		return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + num_rows * FONT_HEIGHT_SMALL;
 	}
 
@@ -1010,7 +1010,7 @@
 	uint GetLegendHeight(uint width) const
 	{
 		uint num_columns = this->GetNumberColumnsLegend(width);
-		uint num_rows = max(this->min_number_of_fixed_rows, (_smallmap_industry_count + num_columns - 1) / num_columns);
+		uint num_rows = max(this->min_number_of_fixed_rows, CeilDiv(_smallmap_industry_count, num_columns));
 		return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + num_rows * FONT_HEIGHT_SMALL;
 	}
 
@@ -1067,7 +1067,7 @@
 
 			case SM_WIDGET_LEGEND: {
 				uint columns = this->GetNumberColumnsLegend(r.right - r.left + 1);
-				uint number_of_rows = max(this->map_type == SMT_INDUSTRY ? (_smallmap_industry_count + columns - 1) / columns : 0, this->min_number_of_fixed_rows);
+				uint number_of_rows = max(this->map_type == SMT_INDUSTRY ? CeilDiv(_smallmap_industry_count, columns) : 0, this->min_number_of_fixed_rows);
 				bool rtl = _dynlang.text_dir == TD_RTL;
 				uint y_org = r.top + WD_FRAMERECT_TOP;
 				uint x = rtl ? r.right - this->column_width - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT;
@@ -1195,7 +1195,7 @@
 					const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_LEGEND); // Label panel
 					uint line = (pt.y - wi->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_SMALL;
 					uint columns = this->GetNumberColumnsLegend(wi->current_x);
-					uint number_of_rows = max((_smallmap_industry_count + columns - 1) / columns, this->min_number_of_fixed_rows);
+					uint number_of_rows = max(CeilDiv(_smallmap_industry_count, columns), this->min_number_of_fixed_rows);
 					if (line >= number_of_rows) break;
 
 					bool rtl = _dynlang.text_dir == TD_RTL;
--- a/src/station_gui.cpp
+++ b/src/station_gui.cpp
@@ -1105,7 +1105,7 @@
 		}
 		Rect s = {r.left + WD_FRAMERECT_LEFT, r.top + WD_FRAMERECT_TOP, r.right - WD_FRAMERECT_RIGHT, INT32_MAX};
 		int bottom = DrawCargoListText(cargo_mask, s, STR_STATION_VIEW_ACCEPTS_CARGO);
-		return (bottom - r.top - WD_FRAMERECT_TOP + FONT_HEIGHT_NORMAL - 1) / FONT_HEIGHT_NORMAL;
+		return CeilDiv(bottom - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL);
 	}
 
 	/** Draw cargo ratings in the #SVW_ACCEPTLIST widget.
@@ -1131,7 +1131,7 @@
 			DrawString(r.left + WD_FRAMERECT_LEFT + 6, r.right - WD_FRAMERECT_RIGHT - 6, y, STR_STATION_VIEW_CARGO_RATING);
 			y += FONT_HEIGHT_NORMAL;
 		}
-		return (y - r.top - WD_FRAMERECT_TOP + FONT_HEIGHT_NORMAL - 1) / FONT_HEIGHT_NORMAL;
+		return CeilDiv(y - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL);
 	}
 
 	void HandleCargoWaitingClick(int row)
--- a/src/terraform_gui.cpp
+++ b/src/terraform_gui.cpp
@@ -649,8 +649,8 @@
 	{
 		if (widget != ETTW_DOTS) return;
 
-		int center_x = (r.left + r.right + 1) / 2;
-		int center_y = (r.top + r.bottom + 1) / 2;
+		int center_x = RoundDiv(r.left + r.right, 2);
+		int center_y = RoundDiv(r.top + r.bottom, 2);
 
 		int n = _terraform_size * _terraform_size;
 		const int8 *coords = &_multi_terraform_coords[0][0];
--- a/src/timetable_cmd.cpp
+++ b/src/timetable_cmd.cpp
@@ -279,7 +279,7 @@
 			/* Round the time taken up to the nearest day, as this will avoid
 			 * confusion for people who are timetabling in days, and can be
 			 * adjusted later by people who aren't. */
-			time_taken = (((time_taken - 1) / DAY_TICKS) + 1) * DAY_TICKS;
+			time_taken = CeilDiv(time_taken, DAY_TICKS) * DAY_TICKS;
 
 			ChangeTimetable(v, v->cur_order_index, time_taken, travelling);
 		}
--- a/src/toolbar_gui.cpp
+++ b/src/toolbar_gui.cpp
@@ -1113,7 +1113,7 @@
 		};
 
 		/* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */
-		uint full_buttons = max((width + this->smallest_x - 1) / this->smallest_x, SMALLEST_ARRANGEMENT);
+		uint full_buttons = max(CeilDiv(width, this->smallest_x), SMALLEST_ARRANGEMENT);
 		if (full_buttons > BIGGEST_ARRANGEMENT) {
 			button_count = arrangable_count = lengthof(arrange_all);
 			spacer_count = this->spacers;
--- a/src/viewport.cpp
+++ b/src/viewport.cpp
@@ -2478,7 +2478,7 @@
 			 * 2 tiles have a length of 1. To bias towards the ceiling we add
 			 * one before division. It feels more natural to count 3 lengths as 2 */
 			if ((b & HT_DIR_MASK) != HT_DIR_X && (b & HT_DIR_MASK) != HT_DIR_Y) {
-				distance = (distance + 1) / 2;
+				distance = CeilDiv(distance, 2);
 			}
 
 			params[index++] = distance;