[BACK]Return to Math.c CVS log [TXT][DIR] Up to [contributed] / brogue-ce / src / brogue

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