Line data Source code
1 0 : /* 2 : 3 : legacy_random.c 4 : 5 : 6 : Oolite 7 : Copyright (C) 2004-2008 Giles C Williams and contributors 8 : 9 : This program is free software; you can redistribute it and/or 10 : modify it under the terms of the GNU General Public License 11 : as published by the Free Software Foundation; either version 2 12 : of the License, or (at your option) any later version. 13 : 14 : This program is distributed in the hope that it will be useful, 15 : but WITHOUT ANY WARRANTY; without even the implied warranty of 16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 : GNU General Public License for more details. 18 : 19 : You should have received a copy of the GNU General Public License 20 : along with this program; if not, write to the Free Software 21 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 22 : MA 02110-1301, USA. 23 : 24 : */ 25 : 26 : #include <stdio.h> 27 : #include <math.h> 28 : #include <stdint.h> 29 : #include <stdbool.h> 30 : #include <assert.h> 31 : #include "legacy_random.h" 32 : 33 : 34 0 : const Random_Seed kNilRandomSeed = {0}; 35 : 36 : 37 0 : static RNG_Seed rnd_seed; 38 : 39 : 40 : // TODO: Why is this based on a static? Should change to OOMungeCheckSum(&checkSum, value); 41 0 : static int32_t checksum; 42 0 : void clear_checksum() 43 : { 44 : checksum = 0; 45 : } 46 : 47 : 48 0 : int16_t munge_checksum(long long value_) 49 : { 50 : uint32_t value = (uint32_t)value_; 51 : int32_t mult1 = (value & 15) + 8; 52 : checksum += value; 53 : checksum *= mult1; 54 : checksum += mult1; 55 : checksum &= 0xffff; 56 : return checksum; 57 : } 58 : 59 : 60 : // cunning price rounding routine: 61 : // 62 0 : double cunningFee(double value, double precision) 63 : { 64 : double fee = value; 65 : double superfee = 100000.0; 66 : double max = 1 + precision; 67 : double min = 1 - precision; 68 : unsigned long long rounded_fee = superfee * floor(0.5 + fee / superfee); 69 : if (rounded_fee == 0) rounded_fee = 1; 70 : double ratio = fee / (double)rounded_fee; 71 : 72 : while ((ratio < min || ratio > max) && superfee > 1) 73 : { 74 : rounded_fee = superfee * floor(0.5 + fee / superfee); 75 : if (rounded_fee == 0) rounded_fee = 1; 76 : ratio = fee / (double)rounded_fee; 77 : superfee /= 10.0; 78 : } 79 : 80 : if (ratio > min && ratio < max) 81 : fee = rounded_fee; 82 : 83 : return fee; 84 : } 85 : 86 : 87 : // an implementation of RANROT 88 : // pseudo random number generator 89 : // 90 0 : static RANROTSeed sRANROT; 91 : 92 : 93 0 : unsigned Ranrot(void) 94 : { 95 : sRANROT.high = (sRANROT.high << 16) + (sRANROT.high >> 16); 96 : sRANROT.high += sRANROT.low; 97 : sRANROT.low += sRANROT.high; 98 : return sRANROT.high & 0x7FFFFFFF; 99 : } 100 : 101 : 102 0 : unsigned RanrotWithSeed(RANROTSeed *ioSeed) 103 : { 104 : assert(ioSeed != NULL); 105 : 106 : ioSeed->high = (ioSeed->high << 16) + (ioSeed->high >> 16); 107 : ioSeed->high += ioSeed->low; 108 : ioSeed->low += ioSeed->high; 109 : return ioSeed->high & 0x7FFFFFFF; 110 : } 111 : 112 : 113 0 : RANROTSeed MakeRanrotSeed(uint32_t seed) 114 : { 115 : RANROTSeed result = 116 : { 117 : .low = seed, 118 : .high = ~seed 119 : }; 120 : 121 : // Mix it up a bit. 122 : RanrotWithSeed(&result); 123 : RanrotWithSeed(&result); 124 : RanrotWithSeed(&result); 125 : 126 : return result; 127 : } 128 : 129 : 130 0 : RANROTSeed RanrotSeedFromRNGSeed(RNG_Seed seed) 131 : { 132 : return MakeRanrotSeed(seed.a * 0x1000000 + seed.b * 0x10000 + seed.c * 0x100 + seed.d); 133 : } 134 : 135 : 136 0 : RANROTSeed RanrotSeedFromRandomSeed(Random_Seed seed) 137 : { 138 : // Same pattern as seed_for_planet_description(). 139 : RNG_Seed s = 140 : { 141 : .a = seed.c, 142 : .b = seed.d, 143 : .c = seed.e, 144 : .d = seed.f 145 : }; 146 : return RanrotSeedFromRNGSeed(s); 147 : } 148 : 149 : 150 0 : void ranrot_srand(uint32_t seed) 151 : { 152 : sRANROT = MakeRanrotSeed(seed); 153 : } 154 : 155 : 156 0 : float randf (void) 157 : { 158 : return (Ranrot() & 0xffff) * (1.0f / 65536.0f); 159 : } 160 : 161 : 162 0 : float randfWithSeed(RANROTSeed *ioSeed) 163 : { 164 : return (RanrotWithSeed(ioSeed) & 0xffff) * (1.0f / 65536.0f); 165 : } 166 : 167 : 168 0 : float bellf (int n) 169 : { 170 : int i = n; 171 : float total = 0; 172 : 173 : if (EXPECT_NOT(i <= 0)) 174 : { 175 : printf("***** ERROR - attempt to generate bellf(%d)\n", n); 176 : return 0.0f; // catch possible div-by-zero problem 177 : } 178 : 179 : while (i-- > 0) 180 : total += (Ranrot() & 1023); 181 : return total / (1024.0f * n); 182 : } 183 : 184 : 185 0 : RANROTSeed RANROTGetFullSeed(void) 186 : { 187 : return sRANROT; 188 : } 189 : 190 : 191 0 : void RANROTSetFullSeed(RANROTSeed seed) 192 : { 193 : sRANROT = seed; 194 : } 195 : 196 : 197 0 : void seed_RNG_only_for_planet_description (Random_Seed s_seed) 198 : { 199 : rnd_seed.a = s_seed.c; 200 : rnd_seed.b = s_seed.d; 201 : rnd_seed.c = s_seed.e; 202 : rnd_seed.d = s_seed.f; 203 : } 204 : 205 : 206 0 : void seed_for_planet_description (Random_Seed s_seed) 207 : { 208 : seed_RNG_only_for_planet_description(s_seed); 209 : sRANROT = RanrotSeedFromRNGSeed(rnd_seed); 210 : } 211 : 212 : 213 0 : RNG_Seed currentRandomSeed (void) 214 : { 215 : return rnd_seed; 216 : } 217 : 218 : 219 0 : void setRandomSeed (RNG_Seed a_seed) 220 : { 221 : rnd_seed = a_seed; 222 : } 223 : 224 : 225 0 : int gen_rnd_number (void) 226 : { 227 : int a,x; 228 : 229 : x = (rnd_seed.a * 2) & 0xFF; 230 : a = x + rnd_seed.c; 231 : if (rnd_seed.a > 127) 232 : a++; 233 : rnd_seed.a = a & 0xFF; 234 : rnd_seed.c = x; 235 : 236 : a = a / 256; /* a = any carry left from above */ 237 : x = rnd_seed.b; 238 : a = (a + x + rnd_seed.d) & 0xFF; 239 : rnd_seed.b = a; 240 : rnd_seed.d = x; 241 : return a; 242 : } 243 : 244 : 245 0 : static bool sReallyRandomInited = false; 246 0 : static RANROTSeed sReallyRandomSeed; 247 : 248 : 249 0 : uint32_t OOReallyRandom(void) 250 : { 251 : assert(sReallyRandomInited); 252 : return RanrotWithSeed(&sReallyRandomSeed); 253 : } 254 : 255 : 256 0 : void OOInitReallyRandom(uint64_t seed) 257 : { 258 : assert(!sReallyRandomInited); 259 : seed ^= 0xA471D52AEF3B6322ULL; 260 : sReallyRandomSeed.high = (seed >> 32) & 0xFFFFFFFF; 261 : sReallyRandomSeed.low = seed & 0xFFFFFFFF; 262 : sReallyRandomInited = true; 263 : OOReallyRandom(); 264 : } 265 : 266 : 267 0 : void OOSetReallyRandomRANROTSeed(void) 268 : { 269 : assert(sReallyRandomInited); 270 : sRANROT = sReallyRandomSeed; 271 : OOReallyRandom(); // Don't go reusing it. 272 : } 273 : 274 : 275 0 : void OOSetReallyRandomRndSeed(void) 276 : { 277 : uint32_t val = OOReallyRandom(); 278 : rnd_seed.a = (val >> 24) & 0xFF; 279 : rnd_seed.b = (val >> 16) & 0xFF; 280 : rnd_seed.c = (val >> 8) & 0xFF; 281 : rnd_seed.d = val & 0xFF; 282 : } 283 : 284 : 285 0 : void OOSetReallyRandomRANROTAndRndSeeds(void) 286 : { 287 : OOSetReallyRandomRANROTSeed(); 288 : OOSetReallyRandomRndSeed(); 289 : } 290 : 291 : 292 0 : OORandomState OOSaveRandomState(void) 293 : { 294 : return (OORandomState) 295 : { 296 : .ranrot = sRANROT, 297 : .rnd = rnd_seed 298 : }; 299 : } 300 : 301 : 302 0 : void OORestoreRandomState(OORandomState state) 303 : { 304 : sRANROT = state.ranrot; 305 : rnd_seed = state.rnd; 306 : } 307 : 308 : 309 0 : void make_pseudo_random_seed (Random_Seed *seed_ptr) 310 : { 311 : seed_ptr->a = gen_rnd_number(); 312 : seed_ptr->b = gen_rnd_number(); 313 : seed_ptr->c = gen_rnd_number(); 314 : seed_ptr->d = gen_rnd_number(); 315 : seed_ptr->e = gen_rnd_number(); 316 : seed_ptr->f = gen_rnd_number(); 317 : } 318 : 319 : 320 0 : void rotate_seed (Random_Seed *seed_ptr) 321 : { 322 : uint_fast16_t x; 323 : uint_fast16_t y; 324 : 325 : /* Note: this is equivalent to adding three (little-endian) 16-bit values 326 : together, rotating the three numbers and replacing one of them with 327 : the sum. The byte-oriented approach is presumably because it was 328 : reverse-engineered from eight-bit machine code. Switching to a plain 329 : sixteen-bit representation is more trouble than it's worth since so 330 : much code uses byte values from the seed struct directly. 331 : */ 332 : x = seed_ptr->a + seed_ptr->c + seed_ptr->e; 333 : y = seed_ptr->b + seed_ptr->d + seed_ptr->f; 334 : 335 : seed_ptr->a = seed_ptr->c; 336 : seed_ptr->b = seed_ptr->d; 337 : 338 : seed_ptr->c = seed_ptr->e; 339 : seed_ptr->d = seed_ptr->f; 340 : 341 : seed_ptr->e = x; 342 : seed_ptr->f = y + (x >> 8); 343 : }