(svn r1951) Introduced SeedModChance() (which is like SeedChance() but uses simple modulo instead of bitshifting and multiplication), explained why does it work better, used it in MakeCzechTownName() and added a TODO note about possibly using it in the other town name generators too.
authorpasky
Sun, 06 Mar 2005 23:21:57 +0000
changeset 1447 3f1c82502413
parent 1446 415d83e81629
child 1448 ab3017415479
(svn r1951) Introduced SeedModChance() (which is like SeedChance() but uses simple modulo instead of bitshifting and multiplication), explained why does it work better, used it in MakeCzechTownName() and added a TODO note about possibly using it in the other town name generators too.
namegen.c
--- a/namegen.c	Sun Mar 06 22:28:35 2005 +0000
+++ b/namegen.c	Sun Mar 06 23:21:57 2005 +0000
@@ -9,6 +9,20 @@
 	return ((uint16)(seed >> shift_by) * max) >> 16;
 }
 
+static inline uint32 SeedModChance(int shift_by, int max, uint32 seed)
+{
+	/* This actually gives *MUCH* more even distribution of the values
+	 * than SeedChance(), which is absolutely horrible in that. If
+	 * you do not believe me, try with i.e. the Czech town names,
+	 * compare the words (nicely visible on prefixes) generated by
+	 * SeedChance() and SeedModChance(). Do not get dicouraged by the
+	 * never-use-modulo myths, which hold true only for the linear
+	 * congruential generators (and Random() isn't such a generator).
+	 * --pasky */
+	// TODO: Perhaps we should use it for all the name generators? --pasky
+	return (seed >> shift_by) % max;
+}
+
 static inline int32 SeedChanceBias(int shift_by, int max, uint32 seed, int bias)
 {
 	return SeedChance(shift_by, max + bias, seed) - bias;
@@ -330,22 +344,22 @@
 	enum CzechAllow allow;
 
 	// 1:3 chance to use a real name.
-	if (SeedChance(0, 4, seed) == 0) {
-		strcpy(buf, name_czech_real[SeedChance(1, lengthof(name_czech_real), seed)]);
+	if (SeedModChance(0, 4, seed) == 0) {
+		strcpy(buf, name_czech_real[SeedModChance(4, lengthof(name_czech_real), seed)]);
 		return 0;
 	}
 
 	// NUL terminates the string for strcat()
 	strcpy(buf, "");
 
-	prob_tails = SeedChance(2, 32, seed);
+	prob_tails = SeedModChance(2, 32, seed);
 	do_prefix = prob_tails < 12;
 	do_suffix = prob_tails > 11 && prob_tails < 17;
 
-	if (do_prefix) prefix = SeedChance(5, lengthof(name_czech_adj), seed);
-	if (do_suffix) suffix = SeedChance(7, lengthof(name_czech_suffix), seed);
+	if (do_prefix) prefix = SeedModChance(5, lengthof(name_czech_adj) * 12, seed) / 12;
+	if (do_suffix) suffix = SeedModChance(7, lengthof(name_czech_suffix), seed);
 	// 3:1 chance 3:1 to use dynamic substantive
-	stem = SeedChance(9, lengthof(name_czech_subst_full)
+	stem = SeedModChance(9, lengthof(name_czech_subst_full)
 	                     + 3 * lengthof(name_czech_subst_stem),
 	                   seed);
 	if (stem < (int) lengthof(name_czech_subst_full)) {
@@ -369,7 +383,7 @@
 		allow = name_czech_subst_stem[stem].allow;
 
 		// Load the postfix (1:1 chance that a postfix will be inserted)
-		postfix = SeedChance(14, lengthof(name_czech_subst_postfix) * 2, seed);
+		postfix = SeedModChance(14, lengthof(name_czech_subst_postfix) * 2, seed);
 
 		if (choose & CZC_POSTFIX) {
 			// Always get a real postfix.
@@ -415,7 +429,7 @@
 		assert(i > 0);
 
 		// Load the ending
-		ending = map[SeedChance(16, i, seed)];
+		ending = map[SeedModChance(16, i, seed)];
 		// Override possible CZG_*FREE; this must be a real gender,
 		// otherwise we get overflow when modifying the adjectivum.
 		gender = name_czech_subst_ending[ending].gender;