Annotation of brogue-ce/src/brogue/Math.c, Revision 1.1.1.1
1.1 rubenllo 1: /*
2: * RogueMain.c
3: * Brogue
4: *
5: * Created by Brian Walker on 12/26/08.
6: * Copyright 2012. All rights reserved.
7: *
8: * This file is part of Brogue.
9: *
10: * This program is free software: you can redistribute it and/or modify
11: * it under the terms of the GNU Affero General Public License as
12: * published by the Free Software Foundation, either version 3 of the
13: * License, or (at your option) any later version.
14: *
15: * This program is distributed in the hope that it will be useful,
16: * but WITHOUT ANY WARRANTY; without even the implied warranty of
17: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18: * GNU Affero General Public License for more details.
19: *
20: * You should have received a copy of the GNU Affero General Public License
21: * along with this program. If not, see <http://www.gnu.org/licenses/>.
22: */
23:
24: #include <time.h>
25: #include <limits.h>
26: #include <stdint.h> // C99
27:
28: #include "Rogue.h"
29: #include "IncludeGlobals.h"
30:
31:
32: // Random number generation
33:
34: short randClump(randomRange theRange) {
35: return randClumpedRange(theRange.lowerBound, theRange.upperBound, theRange.clumpFactor);
36: }
37:
38: // Get a random int between lowerBound and upperBound, inclusive, with probability distribution
39: // affected by clumpFactor.
40: short randClumpedRange(short lowerBound, short upperBound, short clumpFactor) {
41: if (upperBound <= lowerBound) {
42: return lowerBound;
43: }
44: if (clumpFactor <= 1) {
45: return rand_range(lowerBound, upperBound);
46: }
47:
48: short i, total = 0, numSides = (upperBound - lowerBound) / clumpFactor;
49:
50: for(i=0; i < (upperBound - lowerBound) % clumpFactor; i++) {
51: total += rand_range(0, numSides + 1);
52: }
53:
54: for(; i< clumpFactor; i++) {
55: total += rand_range(0, numSides);
56: }
57:
58: return (total + lowerBound);
59: }
60:
61: // Get a random int between lowerBound and upperBound, inclusive
62: boolean rand_percent(short percent) {
63: return (rand_range(0, 99) < clamp(percent, 0, 100));
64: }
65:
66: void shuffleList(short *list, short listLength) {
67: short i, r, buf;
68: for (i=0; i<listLength; i++) {
69: r = rand_range(0, listLength-1);
70: if (i != r) {
71: buf = list[r];
72: list[r] = list[i];
73: list[i] = buf;
74: }
75: }
76: }
77:
78: void fillSequentialList(short *list, short listLength) {
79: short i;
80: for (i=0; i<listLength; i++) {
81: list[i] = i;
82: }
83: }
84:
85: //typedef unsigned long int u4;
86: typedef uint32_t u4;
87: typedef struct ranctx { u4 a; u4 b; u4 c; u4 d; } ranctx;
88:
89: static ranctx RNGState[2];
90:
91: #define rot(x,k) (((x)<<(k))|((x)>>(32-(k))))
92: u4 ranval( ranctx *x ) {
93: u4 e = x->a - rot(x->b, 27);
94: x->a = x->b ^ rot(x->c, 17);
95: x->b = x->c + x->d;
96: x->c = x->d + e;
97: x->d = e + x->a;
98: return x->d;
99: }
100:
101: void raninit( ranctx *x, u4 seed ) {
102: u4 i;
103: x->a = 0xf1ea5eed, x->b = x->c = x->d = seed;
104: for (i=0; i<20; ++i) {
105: (void)ranval(x);
106: }
107: }
108:
109: /* ----------------------------------------------------------------------
110: range
111:
112: returns a number between 0 and N-1
113: without any bias.
114:
115: */
116:
117: #define RAND_MAX_COMBO ((unsigned long) UINT32_MAX)
118:
119: long range(long n, short RNG) {
120: unsigned long div;
121: long r;
122:
123: div = RAND_MAX_COMBO/n;
124:
125: do {
126: r = ranval(&(RNGState[RNG])) / div;
127: } while (r >= n);
128:
129: return r;
130: }
131:
132: // Get a random int between lowerBound and upperBound, inclusive, with uniform probability distribution
133:
134: #ifdef AUDIT_RNG // debug version
135: long rand_range(long lowerBound, long upperBound) {
136: int retval;
137: char RNGMessage[100];
138: if (upperBound <= lowerBound) {
139: return lowerBound;
140: }
141: long interval = upperBound - lowerBound + 1;
142: brogueAssert(interval > 1); // to verify that we didn't wrap around
143: retval = lowerBound + range(interval, rogue.RNG);
144: if (rogue.RNG == RNG_SUBSTANTIVE) {
145: randomNumbersGenerated++;
146: if (1) { //randomNumbersGenerated >= 1128397) {
147: sprintf(RNGMessage, "\n#%lu, %ld to %ld: %ld", randomNumbersGenerated, lowerBound, upperBound, retval);
148: RNGLog(RNGMessage);
149: }
150: }
151: return retval;
152: }
153: #else // normal version
154: long rand_range(long lowerBound, long upperBound) {
155: if (upperBound <= lowerBound) {
156: return lowerBound;
157: }
158: if (rogue.RNG == RNG_SUBSTANTIVE) {
159: randomNumbersGenerated++;
160: }
161: long interval = upperBound - lowerBound + 1;
162: brogueAssert(interval > 1); // to verify that we didn't wrap around
163: return lowerBound + range(interval, rogue.RNG);
164: }
165: #endif
166:
167: // seeds with the time if called with a parameter of 0; returns the seed regardless.
168: // All RNGs are seeded simultaneously and identically.
169: unsigned long seedRandomGenerator(unsigned long seed) {
170: if (seed == 0) {
171: seed = (unsigned long) time(NULL) - 1352700000;
172: }
173: raninit(&(RNGState[RNG_SUBSTANTIVE]), seed);
174: raninit(&(RNGState[RNG_COSMETIC]), seed);
175: return seed;
176: }
177:
178:
179: // Fixed-point arithmetic
180:
181: fixpt fp_round(fixpt x) {
182: long long div = x / FP_FACTOR, rem = x % FP_FACTOR;
183: int sign = (x >= 0) - (x < 0);
184:
185: if (rem >= FP_FACTOR / 2 || rem <= -FP_FACTOR / 2) {
186: return div + sign;
187: } else {
188: return div;
189: }
190: }
191:
192: // Returns the bit position of the most significant bit of x, where the unit
193: // bit has position 1. Returns 0 if x=0.
194: static int msbpos(unsigned long long x) {
195: if (x == 0) return 0;
196: int n = 0;
197: do {
198: n += 1;
199: } while (x >>= 1);
200: return n;
201: }
202:
203: static fixpt fp_exp2(int n) {
204: return (n >= 0 ? FP_FACTOR << n : FP_FACTOR >> -n);
205: }
206:
207: // Calculates sqrt(u) using the bisection method to find the root of
208: // f(x) = x^2 - u.
209: fixpt fp_sqrt(fixpt u) {
210:
211: static const fixpt SQUARE_ROOTS[] = { // values were computed by the code that follows
212: 0, 65536, 92682, 113511, 131073, 146543, 160529, 173392, 185363, 196608, 207243, 217359, 227023, 236293, 245213, 253819,
213: 262145, 270211, 278045, 285665, 293086, 300323, 307391, 314299, 321059, 327680, 334169, 340535, 346784, 352923, 358955, 364889,
214: 370727, 376475, 382137, 387717, 393216, 398640, 403991, 409273, 414487, 419635, 424721, 429749, 434717, 439629, 444487, 449293,
215: 454047, 458752, 463409, 468021, 472587, 477109, 481589, 486028, 490427, 494786, 499107, 503391, 507639, 511853, 516031, 520175,
216: 524289, 528369, 532417, 536435, 540423, 544383, 548313, 552217, 556091, 559939, 563762, 567559, 571329, 575077, 578799, 582497,
217: 586171, 589824, 593453, 597061, 600647, 604213, 607755, 611279, 614783, 618265, 621729, 625173, 628599, 632007, 635395, 638765,
218: 642119, 645455, 648773, 652075, 655360, 658629, 661881, 665117, 668339, 671545, 674735, 677909, 681071, 684215, 687347, 690465,
219: 693567, 696657, 699733, 702795, 705845, 708881, 711903, 714913, 717911, 720896, 723869, 726829, 729779, 732715, 735639, 738553
220: };
221:
222: if (u < 0) return -fp_sqrt(-u);
223:
224: if ((u & (127LL << FP_BASE)) == u) {
225: // u is an integer between 0 and 127
226: return SQUARE_ROOTS[u >> FP_BASE];
227: }
228:
229: // Find the unique k such that 2^(k-1) <= u < 2^k
230: // FP_BASE is the msbpos-1 of FP_FACTOR ("one")
231: int k = msbpos(u) - FP_BASE;
232:
233: fixpt x = 0, fx, upper, lower;
234: // Since 2^(k-1) <= u < 2^k, we have 2^(ceil(k/2)-1) <= sqrt(u) < 2^ceil(k/2).
235: // First ineq. from sqrt(u) >= 2^[(k-1)/2] = 2^[k/2 + 1/2 - 1] >= 2^(ceil(k/2) - 1)
236: // To calculate ceil(k/2), do k/2 but add 1 to k if positive.
237: upper = fp_exp2((k + (k > 0))/2);
238: lower = upper / 2;
239:
240: while (upper != lower + 1) {
241: x = (upper + lower) / 2;
242: fx = FP_MUL(x, x) - u;
243:
244: if (fx == 0) {
245: break;
246: } else if (fx > 0) {
247: upper = x;
248: } else {
249: lower = x;
250: }
251: }
252:
253: return x;
254: }
255:
256: // Returns base to the power of expn
257: fixpt fp_pow(fixpt base, int expn) {
258: if (base == 0) return 0;
259:
260: if (expn < 0) {
261: base = FP_DIV(FP_FACTOR, base);
262: expn = -expn;
263: }
264:
265: fixpt res = FP_FACTOR, err = 0;
266: while (expn--) {
267: res = res * base + (err * base) / FP_FACTOR;
268: err = res % FP_FACTOR;
269: res /= FP_FACTOR;
270: }
271:
272: return res + fp_round(err);
273: }
CVSweb