(svn r11454) -Fix: the CHANCE16 functions were biased; a 32768 in 65536 chance was really a 32769 in 65536 chance.
authorrubidium
Sat, 17 Nov 2007 23:16:41 +0000
changeset 8399 1f301df8328a
parent 8398 c697de71a52c
child 8400 89e1ee0c796c
(svn r11454) -Fix: the CHANCE16 functions were biased; a 32768 in 65536 chance was really a 32769 in 65536 chance.
src/macros.h
src/town_cmd.cpp
--- a/src/macros.h	Sat Nov 17 22:33:53 2007 +0000
+++ b/src/macros.h	Sat Nov 17 23:16:41 2007 +0000
@@ -476,7 +476,7 @@
  * @param b The denominator of the fraction, must of course not be null
  * @return True in (a/b) percent
  */
-#define CHANCE16(a, b) ((uint16)Random() <= (uint16)((65536 * (a)) / (b)))
+#define CHANCE16(a, b) CHANCE16I(a, b, Random())
 
 /**
  * Flips a coin with a given probability and saves the randomize-number in a variable.
@@ -484,18 +484,25 @@
  * This macro uses the same parameters as the CHANCE16 marco. The third parameter
  * must be a variable the randomize-number from Random() is saved in.
  *
+ * The low 16 bits of r will already be used and can therefor not be passed to
+ * CHANCE16I. One can only send the high 16 bits to CHANCE16I.
+ *
  * @param a The numerator of the fraction, see CHANCE16
  * @param b The denominator of the fraction, see CHANCE16
  * @param r The variable to save the randomize-number from Random()
  * @return True in (a/b) percent
  */
-#define CHANCE16R(a, b, r) ((uint16)(r = Random()) <= (uint16)((65536 * (a)) / (b)))
+#define CHANCE16R(a, b, r) CHANCE16I(a, b, r = Random())
 
 /**
  * Checks if a given randomize-number is below a given probability.
  *
  * This macro is used to check if the given probability by the fraction of (a/b)
- * is greater than the given randomize-number v.
+ * is greater than low 16 bits of the given randomize-number v.
+ *
+ * Do not use this function twice on the same random 16 bits as it will yield
+ * the same result. One can use a random number for two calls to CHANCE16I,
+ * where one call sends the low 16 bits and the other the high 16 bits.
  *
  * @param a The numerator of the fraction, see CHANCE16
  * @param b The denominator of the fraction, see CHANCE16
@@ -504,7 +511,7 @@
  */
 static inline bool CHANCE16I(const uint a, const uint b, const uint32 r)
 {
-	return (uint16)r <= (uint16)((65536 * a) / b);
+	return (uint16)r < (uint16)((65536 * a) / b);
 }
 
 
--- a/src/town_cmd.cpp	Sat Nov 17 22:33:53 2007 +0000
+++ b/src/town_cmd.cpp	Sat Nov 17 23:16:41 2007 +0000
@@ -731,16 +731,14 @@
 		 * maybe terraform some. */
 		desired_slope = (dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? SLOPE_NW : SLOPE_NE;
 		if (desired_slope != cur_slope && ComplementSlope(desired_slope) != cur_slope) {
-			uint32 r = Random();
-
-			if (CHANCE16I(1, 8, r)) {
+			if (CHANCE16(1, 8)) {
 				CommandCost res = CMD_ERROR;
-				if (!_generating_world && CHANCE16I(1, 10, r >> 4)) {
+				if (!_generating_world && CHANCE16(1, 10)) {
 					/* Note: Do not replace " ^ 0xF" with ComplementSlope(). The slope might be steep. */
-					res = DoCommand(tile, CHANCE16I(1, 16, r >> 8) ? cur_slope : cur_slope ^ 0xF, 0,
+					res = DoCommand(tile, CHANCE16(1, 16) ? cur_slope : cur_slope ^ 0xF, 0,
 							DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
 				}
-				if (CmdFailed(res) && CHANCE16I(1, 3, r >> 16)) {
+				if (CmdFailed(res) && CHANCE16(1, 3)) {
 					/* We can consider building on the slope, though. */
 					goto no_slope;
 				}