Skip to content

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
  • 10 commits
  • 25 files changed
  • 0 commit comments
  • 2 contributors
View
2 CMakeLists.txt
@@ -152,6 +152,8 @@ IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
if (NOT APPLE AND NOT UNSAFE_PLUGIN)
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined")
endif (NOT APPLE AND NOT UNSAFE_PLUGIN)
+ # GNU systems need to define the Mersenne exponent for the RNG to compile w/o warning
+ ADD_DEFINITIONS("-DSFMT_MEXP=19937")
ENDIF()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/")
View
3 gemrb/core/Animation.cpp
@@ -27,6 +27,7 @@
#include "Map.h"
#include "Sprite2D.h"
#include "Video.h"
+#include "RNG/RNG_SFMT.h"
namespace GemRB {
@@ -35,7 +36,7 @@ Animation::Animation(int count)
frames = (Sprite2D **) calloc(count, sizeof(Sprite2D *));
indicesCount = count;
if (count) {
- pos = rand() % count;
+ pos = RAND(0, count-1);
}
else {
pos = 0;
View
2 gemrb/core/CMakeLists.txt
@@ -118,6 +118,8 @@ FILE(GLOB gemrb_core_LIB_SRCS
GUI/TextEdit.cpp
GUI/Window.cpp
GUI/WorldMapControl.cpp
+ RNG/RNG_SFMT.cpp
+ RNG/sfmt/SFMT.c
Scriptable/Actor.cpp
Scriptable/CombatInfo.cpp
Scriptable/Container.cpp
View
5 gemrb/core/CharAnimations.cpp
@@ -30,6 +30,7 @@
#include "Interface.h"
#include "Map.h"
#include "Palette.h"
+#include "RNG/RNG_SFMT.h"
namespace GemRB {
@@ -1406,7 +1407,7 @@ void CharAnimations::AddPSTSuffix(char* ResRef, unsigned char StanceID,
Prefix="wlk"; break;
case IE_ANI_HEAD_TURN:
Cycle=SixteenToFive[Orient];
- if (rand()&1) {
+ if (RAND(0,1)) {
Prefix="sf2";
sprintf(ResRef,"%c%3s%4s",this->ResRef[0], Prefix, this->ResRef+1);
if (gamedata->Exists(ResRef, IE_BAM_CLASS_ID) ) {
@@ -1792,7 +1793,7 @@ void CharAnimations::AddVHRSuffix(char* ResRef, unsigned char StanceID,
break;
case IE_ANI_HEAD_TURN:
- if (rand()&1) {
+ if (RAND(0,1)) {
strcat( ResRef, "g12" );
Cycle += 18;
} else {
View
8 gemrb/core/ControlAnimation.cpp
@@ -27,6 +27,7 @@
#include "GlobalTimer.h"
#include "Interface.h"
#include "GUI/Button.h"
+#include "RNG/RNG_SFMT.h"
namespace GemRB {
@@ -88,11 +89,14 @@ void ControlAnimation::UpdateAnimation(bool paused)
if (anim_phase == 0) {
frame = 0;
anim_phase = 1;
- time = 500 + 500 * (rand() % 20);
+ // note: the granularity of time should be
+ // one of twenty values from [500, 10000]
+ // but not the full range.
+ time = 500 + 500 * RAND(0, 19);
cycle&=~1;
Cycle=cycle;
} else if (anim_phase == 1) {
- if (rand() % 30 == 0) {
+ if (!RAND(0,29)) {
cycle|=1;
Cycle=cycle;
}
View
3 gemrb/core/Dialog.cpp
@@ -23,6 +23,7 @@
#include "win32def.h"
#include "GameScript/GameScript.h"
+#include "RNG/RNG_SFMT.h"
namespace GemRB {
@@ -85,7 +86,7 @@ int Dialog::FindRandomState(Scriptable* target)
unsigned int i;
unsigned int max = TopLevelCount;
if (!max) return -1;
- unsigned int pick = rand()%max;
+ unsigned int pick = RAND(0, max-1);
for (i=pick; i < max; i++) {
Condition *cond = GetState(i)->condition;
if (cond && cond->Evaluate(target)) {
View
5 gemrb/core/GUI/GameControl.cpp
@@ -41,6 +41,7 @@
#include "GUI/EventMgr.h"
#include "GUI/TextArea.h"
#include "GUI/Window.h"
+#include "RNG/RNG_SFMT.h"
#include "Scriptable/Container.h"
#include "Scriptable/Door.h"
#include "Scriptable/InfoPoint.h"
@@ -839,7 +840,7 @@ bool GameControl::OnKeyRelease(unsigned char Key, unsigned short Mod)
Actor *target;
int i = game->GetPartySize(true);
if(i<2) break;
- i=rand()%i;
+ i=RAND(0, i-1);
do
{
target = game->GetPC(i, true);
@@ -972,7 +973,7 @@ bool GameControl::OnKeyRelease(unsigned char Key, unsigned short Mod)
core->GetDictionary()->DebugDump();
break;
case 'v': //marks some of the map visited (random vision distance)
- area->ExploreMapChunk( p, rand()%30, 1 );
+ area->ExploreMapChunk( p, RAND(0,29), 1 );
break;
case 'w': // consolidates found ground piles under the pointed pc
area->MoveVisibleGroundPiles(p);
View
13 gemrb/core/GameScript/Actions.cpp
@@ -44,6 +44,7 @@
#include "WorldMap.h"
#include "GUI/GameControl.h"
#include "GUI/EventMgr.h"
+#include "RNG/RNG_SFMT.h"
#include "Scriptable/Container.h"
#include "Scriptable/Door.h"
#include "Scriptable/InfoPoint.h"
@@ -988,7 +989,7 @@ void GameScript::WaitRandom(Scriptable* Sender, Action* parameters)
if (width<2) {
width = parameters->int0Parameter;
} else {
- width = rand() % width + parameters->int0Parameter;
+ width = RAND(0, width-1) + parameters->int0Parameter;
}
Sender->CurrentActionState = width * AI_UPDATE_TIME;
} else {
@@ -1041,7 +1042,7 @@ void GameScript::SmallWaitRandom(Scriptable* Sender, Action* parameters)
if (random<1) {
random = 1;
}
- Sender->CurrentActionState = rand() % random + parameters->int0Parameter;
+ Sender->CurrentActionState = RAND(0, random-1) + parameters->int0Parameter;
} else {
Sender->CurrentActionState--;
}
@@ -1679,7 +1680,7 @@ void GameScript::FloatMessageFixedRnd(Scriptable* Sender, Action* parameters)
Log(ERROR, "GameScript", "Cannot display resource!");
return;
}
- DisplayStringCore(target, rndstr->at(rand()%rndstr->size()), DS_CONSOLE|DS_HEAD);
+ DisplayStringCore(target, rndstr->at(RAND(0, rndstr->size()-1)), DS_CONSOLE|DS_HEAD);
FreeSrc(rndstr, parameters->string0Parameter);
}
@@ -1696,7 +1697,7 @@ void GameScript::FloatMessageRnd(Scriptable* Sender, Action* parameters)
Log(ERROR, "GameScript", "Cannot display resource!");
return;
}
- DisplayStringCore(target, rndstr->at(rand()%rndstr->size()), DS_CONSOLE|DS_HEAD);
+ DisplayStringCore(target, rndstr->at(RAND(0, rndstr->size()-1)), DS_CONSOLE|DS_HEAD);
FreeSrc(rndstr, parameters->string0Parameter);
}
@@ -5395,7 +5396,7 @@ void GameScript::RandomFly(Scriptable* Sender, Action* /*parameters*/)
return;
}
Actor* actor = ( Actor* ) Sender;
- int x = rand()&31;
+ int x = RAND(0,31);
if (x<10) {
actor->SetOrientation(actor->GetOrientation()-1, false);
} else if (x>20) {
@@ -5646,7 +5647,7 @@ void GameScript::RandomTurn(Scriptable* Sender, Action* /*parameters*/)
return;
}
Actor *actor = (Actor *) Sender;
- actor->SetOrientation(rand() % MAX_ORIENT, true);
+ actor->SetOrientation(RAND(0, MAX_ORIENT-1), true);
actor->SetWait( 1 );
Sender->ReleaseCurrentAction(); // todo, blocking?
}
View
3 gemrb/core/GameScript/GSUtils.cpp
@@ -44,6 +44,7 @@
#include "Video.h"
#include "WorldMap.h"
#include "GUI/GameControl.h"
+#include "RNG/RNG_SFMT.h"
#include "Scriptable/Container.h"
#include "Scriptable/Door.h"
#include "Scriptable/InfoPoint.h"
@@ -2479,7 +2480,7 @@ void SetupWishCore(Scriptable *Sender, int column, int picks)
}
} else {
for(i=0;i<picks;i++) {
- selects[i]=rand()%count;
+ selects[i]=RAND(0, count-1);
retry:
for(j=0;j<i;j++) {
if(selects[i]==selects[j]) {
View
5 gemrb/core/GameScript/GameScript.cpp
@@ -30,6 +30,7 @@
#include "Interface.h"
#include "PluginMgr.h"
#include "TableMgr.h"
+#include "RNG/RNG_SFMT.h"
#include "System/StringBuffer.h"
namespace GemRB {
@@ -1952,7 +1953,7 @@ bool GameScript::Update(bool *continuing, bool *done)
bool continueExecution = false;
if (continuing) continueExecution = *continuing;
- RandomNumValue=rand();
+ RandomNumValue=RNG_SFMT::getInstance()->rand();
for (size_t a = 0; a < script->responseBlocks.size(); a++) {
ResponseBlock* rB = script->responseBlocks[a];
if (rB->condition->Evaluate(MySelf)) {
@@ -2258,7 +2259,7 @@ int ResponseSet::Execute(Scriptable* Sender)
maxWeight += responses[i]->weight;
}
if (maxWeight) {
- randWeight = rand() % maxWeight;
+ randWeight = RAND(0, maxWeight-1);
}
else {
randWeight = 0;
View
5 gemrb/core/GlobalTimer.cpp
@@ -25,6 +25,7 @@
#include "Interface.h"
#include "Video.h"
#include "GUI/GameControl.h"
+#include "RNG/RNG_SFMT.h"
namespace GemRB {
@@ -139,10 +140,10 @@ void GlobalTimer::DoStep(int count)
}
if (shakeCounter) {
if (shakeX) {
- x += rand()%shakeX;
+ x += RAND(0, shakeX-1);
}
if (shakeY) {
- y += rand()%shakeY;
+ y += RAND(0, shakeY-1);
}
}
}
View
9 gemrb/core/Interface.cpp
@@ -81,6 +81,7 @@
#include "GUI/TextArea.h"
#include "GUI/Window.h"
#include "GUI/WorldMapControl.h"
+#include "RNG/RNG_SFMT.h"
#include "Scriptable/Container.h"
#include "System/FileStream.h"
#include "System/VFS.h"
@@ -90,8 +91,6 @@
#include <unistd.h>
#endif
-#include <cstdlib>
-#include <time.h>
#include <vector>
namespace GemRB {
@@ -1658,10 +1657,6 @@ int Interface::Init(InterfaceConfig* config)
}
plugin->RunInitializers();
- time_t t;
- t = time( NULL );
- srand( ( unsigned int ) t );
-
Log(MESSAGE, "Core", "GemRB Core Initialization...");
Log(MESSAGE, "Core", "Initializing Video Driver...");
video = ( Video * ) PluginMgr::Get()->GetDriver(&Video::ID, VideoDriverName.c_str());
@@ -3678,7 +3673,7 @@ int Interface::Roll(int dice, int size, int add) const
return add + dice * size / 2;
}
for (int i = 0; i < dice; i++) {
- add += rand() % size + 1;
+ add += RAND(1, size);
}
return add;
}
View
11 gemrb/core/Map.cpp
@@ -51,6 +51,7 @@
#include "GameScript/GSUtils.h"
#include "GUI/GameControl.h"
#include "GUI/Window.h"
+#include "RNG/RNG_SFMT.h"
#include "Scriptable/Container.h"
#include "Scriptable/Door.h"
#include "Scriptable/InfoPoint.h"
@@ -2411,7 +2412,7 @@ void Map::AdjustPosition(Point &goal, unsigned int radiusx, unsigned int radiusy
while(radiusx<Width || radiusy<Height) {
//lets make it slightly random where the actor will appear
- if (rand()&1) {
+ if (RAND(0,1)) {
if (AdjustPositionX(goal, radiusx, radiusy)) {
return;
}
@@ -3126,7 +3127,7 @@ void Map::TriggerSpawn(Spawn *spawn)
//check day or night chance
bool day = core->GetGame()->IsDay();
- int chance = rand() % 100;
+ int chance = RAND(0, 99);
if ((day && chance > spawn->DayChance) ||
(!day && chance > spawn->NightChance)) {
spawn->NextSpawn = time + spawn->Frequency * AI_UPDATE_TIME * 60;
@@ -3135,7 +3136,7 @@ void Map::TriggerSpawn(Spawn *spawn)
}
//create spawns
int difficulty = spawn->Difficulty * core->GetGame()->GetPartyLevel(true);
- unsigned int spawncount = 0, i = rand() % spawn->Count;
+ unsigned int spawncount = 0, i = RAND(0, spawn->Count-1);
while (difficulty >= 0 && spawncount < spawn->Maximum) {
if (!SpawnCreature(spawn->Pos, spawn->Creatures[i], 0, 0, &difficulty, &spawncount)) {
break;
@@ -3192,13 +3193,13 @@ int Map::CheckRestInterruptsAndPassTime(const Point &pos, int hours, int day)
//based on ingame timer
int chance=day?RestHeader.DayChance:RestHeader.NightChance;
- bool interrupt = rand()%100 < chance;
+ bool interrupt = (int) RAND(0, 99) < chance;
unsigned int spawncount = 0;
int spawnamount = core->GetGame()->GetPartyLevel(true) * RestHeader.Difficulty;
if (spawnamount < 1) spawnamount = 1;
for (int i=0;i<hours;i++) {
if (interrupt) {
- int idx = rand()%RestHeader.CreatureNum;
+ int idx = RAND(0, RestHeader.CreatureNum-1);
Actor *creature = gamedata->GetCreature(RestHeader.CreResRef[idx]);
if (!creature) {
core->GetGame()->AdvanceTime(300*AI_UPDATE_TIME);
View
9 gemrb/core/Projectile.cpp
@@ -33,6 +33,7 @@
#include "Sprite2D.h"
#include "VEFObject.h"
#include "Video.h"
+#include "RNG/RNG_SFMT.h"
#include "Scriptable/Actor.h"
#include <cmath>
@@ -140,7 +141,7 @@ void Projectile::CreateAnimations(Animation **anims, const ieResRef bamres, int
}
if((ExtFlags&PEF_CYCLE) && !Seq) {
- Seq=rand()%Max;
+ Seq=RAND(0, Max-1);
}
//this hack is needed because bioware .pro files are sometimes
@@ -1478,7 +1479,7 @@ void Projectile::DrawExplosion(const Region &screen)
if (children[i])
continue;
if(apflags&APF_BOTH) {
- if(rand()&1) {
+ if(RAND(0,1)) {
tmp = Extension->Secondary;
} else {
tmp = Extension->Spread;
@@ -1522,12 +1523,12 @@ void Projectile::DrawExplosion(const Region &screen)
//a bit of difference in case crowding is needed
//make this a separate flag if speed difference
//is not always wanted
- pro->Speed-=rand()&7;
+ pro->Speed-=RAND(0,7);
delay = Extension->Delay*extension_explosioncount;
if(apflags&APF_BOTH) {
if (delay) {
- delay = rand()%delay;
+ delay = RAND(0, delay-1);
}
}
//this needs to be commented out for ToB horrid wilting
View
168 gemrb/core/RNG/RNG_SFMT.cpp
@@ -0,0 +1,168 @@
+#include "RNG_SFMT.h"
+#include <climits>
+#include "System/Logging.h"
+
+// This is from gcc sources, namely from fixincludes/inclhack.def
+// On C++11 systems, <cstdint> could be included instead.
+#ifndef UINT64_MAX
+#define UINT64_MAX (~(uint64_t)0)
+#endif
+
+/**
+ * The constructor initializes the random number generator with a 32bit integer seed
+ * based on a hashed value of the current timestamp.
+ * The singleton implementation guarantees that the constructor is called only once,
+ * which means that the RNG is seeded only once which means that it is ok to use the
+ * timestamp for seeding (because it can only be used once per second).
+ */
+RNG_SFMT::RNG_SFMT() {
+ time_t now = time(NULL); // current time
+ unsigned char *ptr = (unsigned char *) &now; // type-punned pointer into now variable
+ uint32_t seed = 0;
+
+ for (size_t i = 0; i < sizeof(now); ++i ) {
+ /* The actual value of a time_t may not be portable, so we compute a “hash” of the
+ * bytes in it using a multiply-and-add technique. The factor used for
+ * multiplication normally comes out as 257, a prime and therefore a good candidate.
+ * According to Knuth the seed can be chosen arbitrarily, so whatever makes the
+ * time_t value into a compatible integer, will work.
+ */
+ seed = seed * (UCHAR_MAX + 2u) + ptr[i];
+ }
+
+ sfmt_init_gen_rand(&sfmt, seed);
+}
+
+/**
+ * This creates an instance of the singleton class RNG_SFMT. Call this instead of the
+ * constructor.
+ */
+RNG_SFMT* RNG_SFMT::getInstance() {
+ // This is the variable that makes the class singleton. So you better not change it ;-)
+ static RNG_SFMT theInstance;
+ return &theInstance;
+}
+
+/**
+ * This method is the rand() equivalent which calls the cdf with proper bounds.
+ *
+ * It is possible to generate random numbers from [-min, +/-max] though the RNG uses
+ * unsigned numbers only, so this wrapper handles some special cases for min and max.
+ *
+ * It is only necessary that the upper bound is larger or equal to the lower bound - with the exception
+ * that someone wants something like rand() % -foo.
+ */
+unsigned int RNG_SFMT::rand(int min, int max) {
+ /* If min is negative, it would be possible to calculate
+ * cdf(0, max - min) + min
+ * There has been no use for negative random numbers with rand() though, so it's treated as error.
+ */
+ if(min < 0) {
+ GemRB::error("RNG", "Invalid bounds for RNG! Got min %d < 0!\n", min);
+ }
+
+ // For complete fairness and equal timing, this should be a roll, but let's skip it anyway
+ if(min == max)
+ return max;
+
+ // Someone wants rand() % -foo, so we compute -rand(0, +foo)
+ // This is the only time where min > max is (sort of) legal.
+ // Not handling this will cause the application to crash.
+ if(min == 0 && max < 0) {
+ return -cdf(0, -max);
+ }
+
+ // No special cases are left, except !(min > max) which is caught in the cdf itself.
+ return cdf(min, max);
+}
+
+/**
+ * Much thought went into this, please read this comment before you modify the
+ * code.
+ * Let SFMT() be an alias for sfmt_genrand_uint64() aka SFMT's rand() function.
+ *
+ * SMFT() returns a uniformly distributed pseudorandom number 0 - UINT64_MAX.
+ * As SFMT() operates on a limited integer range, it is a _discrete_ function.
+ *
+ * We want a random number from a given interval [min, max] though, so we need
+ * to implement the (discrete) cumulative distribution function SFMT(min, max),
+ * which returns a random number X from [min, max].
+ *
+ * This CDF is by formal definition:
+ * SFMT(X; min, max) = (floor(X) - min + 1) / (max - min + 1)
+ *
+ * To get out the random variable, solve for X:
+ * floor(X) = SFMT(X; min, max) * (max - min + 1) + min - 1
+ * So this is, what random(min, max) should look like.
+ * Problem: SFMT(X; min, max) * (max - min + 1) could produce an integer
+ * overflow, so it is not safe.
+ *
+ * One solution is to divide the universe into buckets of equal size depending
+ * on the range [min, max] and assign X to the bucket that contains the number
+ * generated by SFMT(). This equals to modulo computation and is not satisfying:
+ * If the buckets don't divide the universe equally, because the bucket size is
+ * not a divisor of 2, there will be a range in the universe that is biased because
+ * one bucket is too small thus will be chosen less equally!
+ *
+ * This is solved by selection sampling:
+ * As SFMT() is assumed to be unbiased, we are allowed to ignore those random
+ * numbers from SFMT() that would force us to have an unequal bucket and generate new
+ * random numbers until one number fits into one of the other buckets.
+ * This can be compared to an ideal six sided die that is rolled until only
+ * sides 1-5 show up, while 6 represents something that you don't want. So you
+ * basically roll a five sided die.
+ *
+ * Note: If you replace the SFMT RNG with some other rand() function in the
+ * future, then you _need_ to change the UINT64_MAX constant to the largest possible
+ * random number which can be created by the new rand() function. This value is often
+ * defined in a RAND_MAX constant.
+ * Otherwise you will probably skew the outcome of the rand() method or worsen
+ * the performance of the application.
+ *
+ * In threaded environments check the method's code for information on mutexes!
+ */
+unsigned int RNG_SFMT::cdf(unsigned int min, unsigned int max) {
+ // This all makes no sense if min > max, which should never happen.
+ if (min > max) {
+ GemRB::error("RNG", "Invalid bounds for RNG! Got min %d, max %d\n", min, max);
+ // at this point, the method exits. No return value is needed, because
+ // basically the exception itself is returned.
+ }
+
+ // First compute the diameter (aka size, length) of the [min, max] interval
+ const unsigned int diameter = max - min + 1;
+
+ // Compute how many buckets (each in size of the diameter) will fit into the
+ // universe.
+ // If the division has a remainder, the result is floored automatically.
+ const uint64_t buckets = UINT64_MAX / diameter;
+
+ // Compute the last valid random number. All numbers beyond have to be
+ // ignored.
+ // If there was no remainder in the previous step, limit is equal to
+ // UINT64_MAX.
+ const uint64_t limit = diameter * buckets;
+
+ uint64_t rand;
+
+ /**
+ * To make the random number generation thread-safe, a mutex should be created
+ * around the number generation. Outside of the loop of course, to avoid locking
+ * overhead.
+ * In this case replace the lock/unlock comment and you probably also want to use
+ * the vectorized functions from SFMT to generate many random numbers at once.
+ */
+
+ /**** call mutex.lock() here ****/
+
+ do {
+ rand = sfmt_genrand_uint64(&sfmt);
+ } while (rand >= limit);
+
+ /**** call mutex.unlock() here ****/
+
+ // Now determine the bucket containing the SFMT() random number and after
+ // adding the lower bound, a random number from [min, max] can be returned.
+ return (unsigned int)(rand / buckets + min);
+}
+
View
58 gemrb/core/RNG/RNG_SFMT.h
@@ -0,0 +1,58 @@
+#ifndef RNG_SFMT_H
+#define RNG_SFMT_H
+
+#include <climits>
+#include "sfmt/SFMT.h"
+
+#define RAND(min, max) RNG_SFMT::getInstance()->rand(min, max)
+
+/**
+ * This class encapsulates a state of the art PRNG in a singleton class and can be used
+ * to return uniformly distributed integer random numbers from a range [min, max].
+ * Though technically possible, min must be >= 0 and max should always be > 0.
+ * If max < 0 and min == 0 it is assumed that rand() % -max is wanted and the result will
+ * be -rand(0, -max).
+ * This is the only exception to the rule that !(min > max) and is used as a workaround
+ * for some parts of the code where negative modulo could occur.
+ *
+ * As the class is a singleton, only one instance exists. Access it by using the
+ * getInstance() method, e.g. by writing
+ * RNG_SFMT::getInstance()->rand(1,6);
+ * which may be abbreviated by
+ * RAND(1,6);
+ *
+ * Technical details:
+ * The RNG uses the SIMD-oriented Fast Mersenne Twister code v1.4.1 from
+ * http://www.math.sci.hiroshima-u.ac.jp/~%20m-mat/MT/SFMT/index.html
+ * The SFMT RNG creates unsigned int 64bit pseudo random numbers.
+ *
+ * These are mapped to values from the interval [min, max] without bias by using Knuth's
+ * "Algorithm S (Selection sampling technique)" from "The Art of Computer Programming 3rd
+ * Edition Volume 2 / Seminumerical Algorithms".
+ *
+ * In a threaded environment you probably must use mutexes to make this class thread-safe.
+ * There are comments in the cdf-method's code about that.
+ */
+
+class RNG_SFMT {
+private:
+ // only one instance will be allowed, use getInstance
+ RNG_SFMT();
+
+ // The discrete cumulative distribution function for the RNG
+ unsigned int cdf(unsigned int min, unsigned int max);
+
+ // SFMT's internal state
+ sfmt_t sfmt;
+
+public:
+ /* The RNG function to use via
+ * RNG_SFMT::getInstance()->rand(min, max);
+ * or
+ * RAND(min, max);
+ */
+ unsigned int rand(int min = 0, int max = INT_MAX-1);
+ static RNG_SFMT* getInstance();
+};
+
+#endif
View
32 gemrb/core/RNG/sfmt/LICENSE.txt
@@ -0,0 +1,32 @@
+Copyright (c) 2006,2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima
+University.
+Copyright (c) 2012 Mutsuo Saito, Makoto Matsumoto, Hiroshima University
+and The University of Tokyo.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the names of Hiroshima University, The University of
+ Tokyo nor the names of its contributors may be used to endorse
+ or promote products derived from this software without specific
+ prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
View
164 gemrb/core/RNG/sfmt/SFMT-common.h
@@ -0,0 +1,164 @@
+#pragma once
+/**
+ * @file SFMT-common.h
+ *
+ * @brief SIMD oriented Fast Mersenne Twister(SFMT) pseudorandom
+ * number generator with jump function. This file includes common functions
+ * used in random number generation and jump.
+ *
+ * @author Mutsuo Saito (Hiroshima University)
+ * @author Makoto Matsumoto (The University of Tokyo)
+ *
+ * Copyright (C) 2006, 2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima
+ * University.
+ * Copyright (C) 2012 Mutsuo Saito, Makoto Matsumoto, Hiroshima
+ * University and The University of Tokyo.
+ * All rights reserved.
+ *
+ * The 3-clause BSD License is applied to this software, see
+ * LICENSE.txt
+ */
+#ifndef SFMT_COMMON_H
+#define SFMT_COMMON_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include "SFMT.h"
+
+inline static void do_recursion(w128_t * r, w128_t * a, w128_t * b,
+ w128_t * c, w128_t * d);
+
+inline static void rshift128(w128_t *out, w128_t const *in, int shift);
+inline static void lshift128(w128_t *out, w128_t const *in, int shift);
+
+/**
+ * This function simulates SIMD 128-bit right shift by the standard C.
+ * The 128-bit integer given in in is shifted by (shift * 8) bits.
+ * This function simulates the LITTLE ENDIAN SIMD.
+ * @param out the output of this function
+ * @param in the 128-bit data to be shifted
+ * @param shift the shift value
+ */
+#ifdef ONLY64
+inline static void rshift128(w128_t *out, w128_t const *in, int shift) {
+ uint64_t th, tl, oh, ol;
+
+ th = ((uint64_t)in->u[2] << 32) | ((uint64_t)in->u[3]);
+ tl = ((uint64_t)in->u[0] << 32) | ((uint64_t)in->u[1]);
+
+ oh = th >> (shift * 8);
+ ol = tl >> (shift * 8);
+ ol |= th << (64 - shift * 8);
+ out->u[0] = (uint32_t)(ol >> 32);
+ out->u[1] = (uint32_t)ol;
+ out->u[2] = (uint32_t)(oh >> 32);
+ out->u[3] = (uint32_t)oh;
+}
+#else
+inline static void rshift128(w128_t *out, w128_t const *in, int shift)
+{
+ uint64_t th, tl, oh, ol;
+
+ th = ((uint64_t)in->u[3] << 32) | ((uint64_t)in->u[2]);
+ tl = ((uint64_t)in->u[1] << 32) | ((uint64_t)in->u[0]);
+
+ oh = th >> (shift * 8);
+ ol = tl >> (shift * 8);
+ ol |= th << (64 - shift * 8);
+ out->u[1] = (uint32_t)(ol >> 32);
+ out->u[0] = (uint32_t)ol;
+ out->u[3] = (uint32_t)(oh >> 32);
+ out->u[2] = (uint32_t)oh;
+}
+#endif
+/**
+ * This function simulates SIMD 128-bit left shift by the standard C.
+ * The 128-bit integer given in in is shifted by (shift * 8) bits.
+ * This function simulates the LITTLE ENDIAN SIMD.
+ * @param out the output of this function
+ * @param in the 128-bit data to be shifted
+ * @param shift the shift value
+ */
+#ifdef ONLY64
+inline static void lshift128(w128_t *out, w128_t const *in, int shift) {
+ uint64_t th, tl, oh, ol;
+
+ th = ((uint64_t)in->u[2] << 32) | ((uint64_t)in->u[3]);
+ tl = ((uint64_t)in->u[0] << 32) | ((uint64_t)in->u[1]);
+
+ oh = th << (shift * 8);
+ ol = tl << (shift * 8);
+ oh |= tl >> (64 - shift * 8);
+ out->u[0] = (uint32_t)(ol >> 32);
+ out->u[1] = (uint32_t)ol;
+ out->u[2] = (uint32_t)(oh >> 32);
+ out->u[3] = (uint32_t)oh;
+}
+#else
+inline static void lshift128(w128_t *out, w128_t const *in, int shift)
+{
+ uint64_t th, tl, oh, ol;
+
+ th = ((uint64_t)in->u[3] << 32) | ((uint64_t)in->u[2]);
+ tl = ((uint64_t)in->u[1] << 32) | ((uint64_t)in->u[0]);
+
+ oh = th << (shift * 8);
+ ol = tl << (shift * 8);
+ oh |= tl >> (64 - shift * 8);
+ out->u[1] = (uint32_t)(ol >> 32);
+ out->u[0] = (uint32_t)ol;
+ out->u[3] = (uint32_t)(oh >> 32);
+ out->u[2] = (uint32_t)oh;
+}
+#endif
+/**
+ * This function represents the recursion formula.
+ * @param r output
+ * @param a a 128-bit part of the internal state array
+ * @param b a 128-bit part of the internal state array
+ * @param c a 128-bit part of the internal state array
+ * @param d a 128-bit part of the internal state array
+ */
+#ifdef ONLY64
+inline static void do_recursion(w128_t *r, w128_t *a, w128_t *b, w128_t *c,
+ w128_t *d) {
+ w128_t x;
+ w128_t y;
+
+ lshift128(&x, a, SFMT_SL2);
+ rshift128(&y, c, SFMT_SR2);
+ r->u[0] = a->u[0] ^ x.u[0] ^ ((b->u[0] >> SFMT_SR1) & SFMT_MSK2) ^ y.u[0]
+ ^ (d->u[0] << SFMT_SL1);
+ r->u[1] = a->u[1] ^ x.u[1] ^ ((b->u[1] >> SFMT_SR1) & SFMT_MSK1) ^ y.u[1]
+ ^ (d->u[1] << SFMT_SL1);
+ r->u[2] = a->u[2] ^ x.u[2] ^ ((b->u[2] >> SFMT_SR1) & SFMT_MSK4) ^ y.u[2]
+ ^ (d->u[2] << SFMT_SL1);
+ r->u[3] = a->u[3] ^ x.u[3] ^ ((b->u[3] >> SFMT_SR1) & SFMT_MSK3) ^ y.u[3]
+ ^ (d->u[3] << SFMT_SL1);
+}
+#else
+inline static void do_recursion(w128_t *r, w128_t *a, w128_t *b,
+ w128_t *c, w128_t *d)
+{
+ w128_t x;
+ w128_t y;
+
+ lshift128(&x, a, SFMT_SL2);
+ rshift128(&y, c, SFMT_SR2);
+ r->u[0] = a->u[0] ^ x.u[0] ^ ((b->u[0] >> SFMT_SR1) & SFMT_MSK1)
+ ^ y.u[0] ^ (d->u[0] << SFMT_SL1);
+ r->u[1] = a->u[1] ^ x.u[1] ^ ((b->u[1] >> SFMT_SR1) & SFMT_MSK2)
+ ^ y.u[1] ^ (d->u[1] << SFMT_SL1);
+ r->u[2] = a->u[2] ^ x.u[2] ^ ((b->u[2] >> SFMT_SR1) & SFMT_MSK3)
+ ^ y.u[2] ^ (d->u[2] << SFMT_SL1);
+ r->u[3] = a->u[3] ^ x.u[3] ^ ((b->u[3] >> SFMT_SR1) & SFMT_MSK4)
+ ^ y.u[3] ^ (d->u[3] << SFMT_SL1);
+}
+#endif
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
View
98 gemrb/core/RNG/sfmt/SFMT-params.h
@@ -0,0 +1,98 @@
+#pragma once
+#ifndef SFMT_PARAMS_H
+#define SFMT_PARAMS_H
+
+#if !defined(SFMT_MEXP)
+#if defined(__GNUC__) && !defined(__ICC)
+ #warning "SFMT_MEXP is not defined. I assume MEXP is 19937."
+#endif
+ #define SFMT_MEXP 19937
+#endif
+/*-----------------
+ BASIC DEFINITIONS
+ -----------------*/
+/** Mersenne Exponent. The period of the sequence
+ * is a multiple of 2^MEXP-1.
+ * #define SFMT_MEXP 19937 */
+/** SFMT generator has an internal state array of 128-bit integers,
+ * and N is its size. */
+#define SFMT_N (SFMT_MEXP / 128 + 1)
+/** N32 is the size of internal state array when regarded as an array
+ * of 32-bit integers.*/
+#define SFMT_N32 (SFMT_N * 4)
+/** N64 is the size of internal state array when regarded as an array
+ * of 64-bit integers.*/
+#define SFMT_N64 (SFMT_N * 2)
+
+/*----------------------
+ the parameters of SFMT
+ following definitions are in paramsXXXX.h file.
+ ----------------------*/
+/** the pick up position of the array.
+#define SFMT_POS1 122
+*/
+
+/** the parameter of shift left as four 32-bit registers.
+#define SFMT_SL1 18
+ */
+
+/** the parameter of shift left as one 128-bit register.
+ * The 128-bit integer is shifted by (SFMT_SL2 * 8) bits.
+#define SFMT_SL2 1
+*/
+
+/** the parameter of shift right as four 32-bit registers.
+#define SFMT_SR1 11
+*/
+
+/** the parameter of shift right as one 128-bit register.
+ * The 128-bit integer is shifted by (SFMT_SL2 * 8) bits.
+#define SFMT_SR21 1
+*/
+
+/** A bitmask, used in the recursion. These parameters are introduced
+ * to break symmetry of SIMD.
+#define SFMT_MSK1 0xdfffffefU
+#define SFMT_MSK2 0xddfecb7fU
+#define SFMT_MSK3 0xbffaffffU
+#define SFMT_MSK4 0xbffffff6U
+*/
+
+/** These definitions are part of a 128-bit period certification vector.
+#define SFMT_PARITY1 0x00000001U
+#define SFMT_PARITY2 0x00000000U
+#define SFMT_PARITY3 0x00000000U
+#define SFMT_PARITY4 0xc98e126aU
+*/
+
+#if SFMT_MEXP == 607
+ #include "SFMT-params607.h"
+#elif SFMT_MEXP == 1279
+ #include "SFMT-params1279.h"
+#elif SFMT_MEXP == 2281
+ #include "SFMT-params2281.h"
+#elif SFMT_MEXP == 4253
+ #include "SFMT-params4253.h"
+#elif SFMT_MEXP == 11213
+ #include "SFMT-params11213.h"
+#elif SFMT_MEXP == 19937
+ #include "SFMT-params19937.h"
+#elif SFMT_MEXP == 44497
+ #include "SFMT-params44497.h"
+#elif SFMT_MEXP == 86243
+ #include "SFMT-params86243.h"
+#elif SFMT_MEXP == 132049
+ #include "SFMT-params132049.h"
+#elif SFMT_MEXP == 216091
+ #include "SFMT-params216091.h"
+#else
+#if defined(__GNUC__) && !defined(__ICC)
+ #error "SFMT_MEXP is not valid."
+ #undef SFMT_MEXP
+#else
+ #undef SFMT_MEXP
+#endif
+
+#endif
+
+#endif /* SFMT_PARAMS_H */
View
50 gemrb/core/RNG/sfmt/SFMT-params19937.h
@@ -0,0 +1,50 @@
+#pragma once
+#ifndef SFMT_PARAMS19937_H
+#define SFMT_PARAMS19937_H
+
+#define SFMT_POS1 122
+#define SFMT_SL1 18
+#define SFMT_SL2 1
+#define SFMT_SR1 11
+#define SFMT_SR2 1
+#define SFMT_MSK1 0xdfffffefU
+#define SFMT_MSK2 0xddfecb7fU
+#define SFMT_MSK3 0xbffaffffU
+#define SFMT_MSK4 0xbffffff6U
+#define SFMT_PARITY1 0x00000001U
+#define SFMT_PARITY2 0x00000000U
+#define SFMT_PARITY3 0x00000000U
+#define SFMT_PARITY4 0x13c9e684U
+
+
+/* PARAMETERS FOR ALTIVEC */
+#if defined(__APPLE__) /* For OSX */
+ #define SFMT_ALTI_SL1 \
+ (vector unsigned int)(SFMT_SL1, SFMT_SL1, SFMT_SL1, SFMT_SL1)
+ #define SFMT_ALTI_SR1 \
+ (vector unsigned int)(SFMT_SR1, SFMT_SR1, SFMT_SR1, SFMT_SR1)
+ #define SFMT_ALTI_MSK \
+ (vector unsigned int)(SFMT_MSK1, SFMT_MSK2, SFMT_MSK3, SFMT_MSK4)
+ #define SFMT_ALTI_MSK64 \
+ (vector unsigned int)(SFMT_MSK2, SFMT_MSK1, SFMT_MSK4, SFMT_MSK3)
+ #define SFMT_ALTI_SL2_PERM \
+ (vector unsigned char)(1,2,3,23,5,6,7,0,9,10,11,4,13,14,15,8)
+ #define SFMT_ALTI_SL2_PERM64 \
+ (vector unsigned char)(1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0)
+ #define SFMT_ALTI_SR2_PERM \
+ (vector unsigned char)(7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14)
+ #define SFMT_ALTI_SR2_PERM64 \
+ (vector unsigned char)(15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14)
+#else /* For OTHER OSs(Linux?) */
+ #define SFMT_ALTI_SL1 {SFMT_SL1, SFMT_SL1, SFMT_SL1, SFMT_SL1}
+ #define SFMT_ALTI_SR1 {SFMT_SR1, SFMT_SR1, SFMT_SR1, SFMT_SR1}
+ #define SFMT_ALTI_MSK {SFMT_MSK1, SFMT_MSK2, SFMT_MSK3, SFMT_MSK4}
+ #define SFMT_ALTI_MSK64 {SFMT_MSK2, SFMT_MSK1, SFMT_MSK4, SFMT_MSK3}
+ #define SFMT_ALTI_SL2_PERM {1,2,3,23,5,6,7,0,9,10,11,4,13,14,15,8}
+ #define SFMT_ALTI_SL2_PERM64 {1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0}
+ #define SFMT_ALTI_SR2_PERM {7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14}
+ #define SFMT_ALTI_SR2_PERM64 {15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14}
+#endif /* For OSX */
+#define SFMT_IDSTR "SFMT-19937:122-18-1-11-1:dfffffef-ddfecb7f-bffaffff-bffffff6"
+
+#endif /* SFMT_PARAMS19937_H */
View
433 gemrb/core/RNG/sfmt/SFMT.c
@@ -0,0 +1,433 @@
+/**
+ * @file SFMT.c
+ * @brief SIMD oriented Fast Mersenne Twister(SFMT)
+ *
+ * @author Mutsuo Saito (Hiroshima University)
+ * @author Makoto Matsumoto (Hiroshima University)
+ *
+ * Copyright (C) 2006, 2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima
+ * University.
+ * Copyright (C) 2012 Mutsuo Saito, Makoto Matsumoto, Hiroshima
+ * University and The University of Tokyo.
+ * Copyright (C) 2013 Mutsuo Saito, Makoto Matsumoto and Hiroshima
+ * University.
+ * All rights reserved.
+ *
+ * The 3-clause BSD License is applied to this software, see
+ * LICENSE.txt
+ */
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include <string.h>
+#include <assert.h>
+#include "SFMT.h"
+#include "SFMT-params.h"
+#include "SFMT-common.h"
+
+#if defined(__BIG_ENDIAN__) && !defined(__amd64) && !defined(BIG_ENDIAN64)
+#define BIG_ENDIAN64 1
+#endif
+#if defined(HAVE_ALTIVEC) && !defined(BIG_ENDIAN64)
+#define BIG_ENDIAN64 1
+#endif
+#if defined(ONLY64) && !defined(BIG_ENDIAN64)
+ #if defined(__GNUC__)
+ #error "-DONLY64 must be specified with -DBIG_ENDIAN64"
+ #endif
+#undef ONLY64
+#endif
+
+/**
+ * parameters used by sse2.
+ */
+static const w128_t sse2_param_mask = {{SFMT_MSK1, SFMT_MSK2,
+ SFMT_MSK3, SFMT_MSK4}};
+/*----------------
+ STATIC FUNCTIONS
+ ----------------*/
+inline static int idxof(int i);
+inline static void gen_rand_array(sfmt_t * sfmt, w128_t *array, int size);
+inline static uint32_t func1(uint32_t x);
+inline static uint32_t func2(uint32_t x);
+static void period_certification(sfmt_t * sfmt);
+#if defined(BIG_ENDIAN64) && !defined(ONLY64)
+inline static void swap(w128_t *array, int size);
+#endif
+
+#if defined(HAVE_ALTIVEC)
+ #include "SFMT-alti.h"
+#elif defined(HAVE_SSE2)
+ #if defined(_MSC_VER)
+ #include "SFMT-sse2-msc.h"
+ #else
+ #include "SFMT-sse2.h"
+ #endif
+#endif
+
+/**
+ * This function simulate a 64-bit index of LITTLE ENDIAN
+ * in BIG ENDIAN machine.
+ */
+#ifdef ONLY64
+inline static int idxof(int i) {
+ return i ^ 1;
+}
+#else
+inline static int idxof(int i) {
+ return i;
+}
+#endif
+
+#if (!defined(HAVE_ALTIVEC)) && (!defined(HAVE_SSE2))
+/**
+ * This function fills the user-specified array with pseudorandom
+ * integers.
+ *
+ * @param sfmt SFMT internal state
+ * @param array an 128-bit array to be filled by pseudorandom numbers.
+ * @param size number of 128-bit pseudorandom numbers to be generated.
+ */
+inline static void gen_rand_array(sfmt_t * sfmt, w128_t *array, int size) {
+ int i, j;
+ w128_t *r1, *r2;
+
+ r1 = &sfmt->state[SFMT_N - 2];
+ r2 = &sfmt->state[SFMT_N - 1];
+ for (i = 0; i < SFMT_N - SFMT_POS1; i++) {
+ do_recursion(&array[i], &sfmt->state[i], &sfmt->state[i + SFMT_POS1], r1, r2);
+ r1 = r2;
+ r2 = &array[i];
+ }
+ for (; i < SFMT_N; i++) {
+ do_recursion(&array[i], &sfmt->state[i],
+ &array[i + SFMT_POS1 - SFMT_N], r1, r2);
+ r1 = r2;
+ r2 = &array[i];
+ }
+ for (; i < size - SFMT_N; i++) {
+ do_recursion(&array[i], &array[i - SFMT_N],
+ &array[i + SFMT_POS1 - SFMT_N], r1, r2);
+ r1 = r2;
+ r2 = &array[i];
+ }
+ for (j = 0; j < 2 * SFMT_N - size; j++) {
+ sfmt->state[j] = array[j + size - SFMT_N];
+ }
+ for (; i < size; i++, j++) {
+ do_recursion(&array[i], &array[i - SFMT_N],
+ &array[i + SFMT_POS1 - SFMT_N], r1, r2);
+ r1 = r2;
+ r2 = &array[i];
+ sfmt->state[j] = array[i];
+ }
+}
+#endif
+
+#if defined(BIG_ENDIAN64) && !defined(ONLY64) && !defined(HAVE_ALTIVEC)
+inline static void swap(w128_t *array, int size) {
+ int i;
+ uint32_t x, y;
+
+ for (i = 0; i < size; i++) {
+ x = array[i].u[0];
+ y = array[i].u[2];
+ array[i].u[0] = array[i].u[1];
+ array[i].u[2] = array[i].u[3];
+ array[i].u[1] = x;
+ array[i].u[3] = y;
+ }
+}
+#endif
+/**
+ * This function represents a function used in the initialization
+ * by init_by_array
+ * @param x 32-bit integer
+ * @return 32-bit integer
+ */
+static uint32_t func1(uint32_t x) {
+ return (x ^ (x >> 27)) * (uint32_t)1664525UL;
+}
+
+/**
+ * This function represents a function used in the initialization
+ * by init_by_array
+ * @param x 32-bit integer
+ * @return 32-bit integer
+ */
+static uint32_t func2(uint32_t x) {
+ return (x ^ (x >> 27)) * (uint32_t)1566083941UL;
+}
+
+/**
+ * This function certificate the period of 2^{MEXP}
+ * @param sfmt SFMT internal state
+ */
+static void period_certification(sfmt_t * sfmt) {
+ int inner = 0;
+ int i, j;
+ uint32_t work;
+ uint32_t *psfmt32 = &sfmt->state[0].u[0];
+ const uint32_t parity[4] = {SFMT_PARITY1, SFMT_PARITY2,
+ SFMT_PARITY3, SFMT_PARITY4};
+
+ for (i = 0; i < 4; i++)
+ inner ^= psfmt32[idxof(i)] & parity[i];
+ for (i = 16; i > 0; i >>= 1)
+ inner ^= inner >> i;
+ inner &= 1;
+ /* check OK */
+ if (inner == 1) {
+ return;
+ }
+ /* check NG, and modification */
+ for (i = 0; i < 4; i++) {
+ work = 1;
+ for (j = 0; j < 32; j++) {
+ if ((work & parity[i]) != 0) {
+ psfmt32[idxof(i)] ^= work;
+ return;
+ }
+ work = work << 1;
+ }
+ }
+}
+
+/*----------------
+ PUBLIC FUNCTIONS
+ ----------------*/
+#define UNUSED_VARIABLE(x) (void)(x)
+/**
+ * This function returns the identification string.
+ * The string shows the word size, the Mersenne exponent,
+ * and all parameters of this generator.
+ * @param sfmt SFMT internal state
+ */
+const char *sfmt_get_idstring(sfmt_t * sfmt) {
+ UNUSED_VARIABLE(sfmt);
+ return SFMT_IDSTR;
+}
+
+/**
+ * This function returns the minimum size of array used for \b
+ * fill_array32() function.
+ * @param sfmt SFMT internal state
+ * @return minimum size of array used for fill_array32() function.
+ */
+int sfmt_get_min_array_size32(sfmt_t * sfmt) {
+ UNUSED_VARIABLE(sfmt);
+ return SFMT_N32;
+}
+
+/**
+ * This function returns the minimum size of array used for \b
+ * fill_array64() function.
+ * @param sfmt SFMT internal state
+ * @return minimum size of array used for fill_array64() function.
+ */
+int sfmt_get_min_array_size64(sfmt_t * sfmt) {
+ UNUSED_VARIABLE(sfmt);
+ return SFMT_N64;
+}
+
+#if !defined(HAVE_SSE2) && !defined(HAVE_ALTIVEC)
+/**
+ * This function fills the internal state array with pseudorandom
+ * integers.
+ * @param sfmt SFMT internal state
+ */
+void sfmt_gen_rand_all(sfmt_t * sfmt) {
+ int i;
+ w128_t *r1, *r2;
+
+ r1 = &sfmt->state[SFMT_N - 2];
+ r2 = &sfmt->state[SFMT_N - 1];
+ for (i = 0; i < SFMT_N - SFMT_POS1; i++) {
+ do_recursion(&sfmt->state[i], &sfmt->state[i],
+ &sfmt->state[i + SFMT_POS1], r1, r2);
+ r1 = r2;
+ r2 = &sfmt->state[i];
+ }
+ for (; i < SFMT_N; i++) {
+ do_recursion(&sfmt->state[i], &sfmt->state[i],
+ &sfmt->state[i + SFMT_POS1 - SFMT_N], r1, r2);
+ r1 = r2;
+ r2 = &sfmt->state[i];
+ }
+}
+#endif
+
+#ifndef ONLY64
+/**
+ * This function generates pseudorandom 32-bit integers in the
+ * specified array[] by one call. The number of pseudorandom integers
+ * is specified by the argument size, which must be at least 624 and a
+ * multiple of four. The generation by this function is much faster
+ * than the following gen_rand function.
+ *
+ * For initialization, init_gen_rand or init_by_array must be called
+ * before the first call of this function. This function can not be
+ * used after calling gen_rand function, without initialization.
+ *
+ * @param sfmt SFMT internal state
+ * @param array an array where pseudorandom 32-bit integers are filled
+ * by this function. The pointer to the array must be \b "aligned"
+ * (namely, must be a multiple of 16) in the SIMD version, since it
+ * refers to the address of a 128-bit integer. In the standard C
+ * version, the pointer is arbitrary.
+ *
+ * @param size the number of 32-bit pseudorandom integers to be
+ * generated. size must be a multiple of 4, and greater than or equal
+ * to (MEXP / 128 + 1) * 4.
+ *
+ * @note \b memalign or \b posix_memalign is available to get aligned
+ * memory. Mac OSX doesn't have these functions, but \b malloc of OSX
+ * returns the pointer to the aligned memory block.
+ */
+void sfmt_fill_array32(sfmt_t * sfmt, uint32_t *array, int size) {
+ assert(sfmt->idx == SFMT_N32);
+ assert(size % 4 == 0);
+ assert(size >= SFMT_N32);
+
+ gen_rand_array(sfmt, (w128_t *)array, size / 4);
+ sfmt->idx = SFMT_N32;
+}
+#endif
+
+/**
+ * This function generates pseudorandom 64-bit integers in the
+ * specified array[] by one call. The number of pseudorandom integers
+ * is specified by the argument size, which must be at least 312 and a
+ * multiple of two. The generation by this function is much faster
+ * than the following gen_rand function.
+ *
+ * @param sfmt SFMT internal state
+ * For initialization, init_gen_rand or init_by_array must be called
+ * before the first call of this function. This function can not be
+ * used after calling gen_rand function, without initialization.
+ *
+ * @param array an array where pseudorandom 64-bit integers are filled
+ * by this function. The pointer to the array must be "aligned"
+ * (namely, must be a multiple of 16) in the SIMD version, since it
+ * refers to the address of a 128-bit integer. In the standard C
+ * version, the pointer is arbitrary.
+ *
+ * @param size the number of 64-bit pseudorandom integers to be
+ * generated. size must be a multiple of 2, and greater than or equal
+ * to (MEXP / 128 + 1) * 2
+ *
+ * @note \b memalign or \b posix_memalign is available to get aligned
+ * memory. Mac OSX doesn't have these functions, but \b malloc of OSX
+ * returns the pointer to the aligned memory block.
+ */
+void sfmt_fill_array64(sfmt_t * sfmt, uint64_t *array, int size) {
+ assert(sfmt->idx == SFMT_N32);
+ assert(size % 2 == 0);
+ assert(size >= SFMT_N64);
+
+ gen_rand_array(sfmt, (w128_t *)array, size / 2);
+ sfmt->idx = SFMT_N32;
+
+#if defined(BIG_ENDIAN64) && !defined(ONLY64)
+ swap((w128_t *)array, size /2);
+#endif
+}
+
+/**
+ * This function initializes the internal state array with a 32-bit
+ * integer seed.
+ *
+ * @param sfmt SFMT internal state
+ * @param seed a 32-bit integer used as the seed.
+ */
+void sfmt_init_gen_rand(sfmt_t * sfmt, uint32_t seed) {
+ int i;
+
+ uint32_t *psfmt32 = &sfmt->state[0].u[0];
+
+ psfmt32[idxof(0)] = seed;
+ for (i = 1; i < SFMT_N32; i++) {
+ psfmt32[idxof(i)] = 1812433253UL * (psfmt32[idxof(i - 1)]
+ ^ (psfmt32[idxof(i - 1)] >> 30))
+ + i;
+ }
+ sfmt->idx = SFMT_N32;
+ period_certification(sfmt);
+}
+
+/**
+ * This function initializes the internal state array,
+ * with an array of 32-bit integers used as the seeds
+ * @param sfmt SFMT internal state
+ * @param init_key the array of 32-bit integers, used as a seed.
+ * @param key_length the length of init_key.
+ */
+void sfmt_init_by_array(sfmt_t * sfmt, uint32_t *init_key, int key_length) {
+ int i, j, count;
+ uint32_t r;
+ int lag;
+ int mid;
+ int size = SFMT_N * 4;
+ uint32_t *psfmt32 = &sfmt->state[0].u[0];
+
+ if (size >= 623) {
+ lag = 11;
+ } else if (size >= 68) {
+ lag = 7;
+ } else if (size >= 39) {
+ lag = 5;
+ } else {
+ lag = 3;
+ }
+ mid = (size - lag) / 2;
+
+ memset(sfmt, 0x8b, sizeof(sfmt_t));
+ if (key_length + 1 > SFMT_N32) {
+ count = key_length + 1;
+ } else {
+ count = SFMT_N32;
+ }
+ r = func1(psfmt32[idxof(0)] ^ psfmt32[idxof(mid)]
+ ^ psfmt32[idxof(SFMT_N32 - 1)]);
+ psfmt32[idxof(mid)] += r;
+ r += key_length;
+ psfmt32[idxof(mid + lag)] += r;
+ psfmt32[idxof(0)] = r;
+
+ count--;
+ for (i = 1, j = 0; (j < count) && (j < key_length); j++) {
+ r = func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % SFMT_N32)]
+ ^ psfmt32[idxof((i + SFMT_N32 - 1) % SFMT_N32)]);
+ psfmt32[idxof((i + mid) % SFMT_N32)] += r;
+ r += init_key[j] + i;
+ psfmt32[idxof((i + mid + lag) % SFMT_N32)] += r;
+ psfmt32[idxof(i)] = r;
+ i = (i + 1) % SFMT_N32;
+ }
+ for (; j < count; j++) {
+ r = func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % SFMT_N32)]
+ ^ psfmt32[idxof((i + SFMT_N32 - 1) % SFMT_N32)]);
+ psfmt32[idxof((i + mid) % SFMT_N32)] += r;
+ r += i;
+ psfmt32[idxof((i + mid + lag) % SFMT_N32)] += r;
+ psfmt32[idxof(i)] = r;
+ i = (i + 1) % SFMT_N32;
+ }
+ for (j = 0; j < SFMT_N32; j++) {
+ r = func2(psfmt32[idxof(i)] + psfmt32[idxof((i + mid) % SFMT_N32)]
+ + psfmt32[idxof((i + SFMT_N32 - 1) % SFMT_N32)]);
+ psfmt32[idxof((i + mid) % SFMT_N32)] ^= r;
+ r -= i;
+ psfmt32[idxof((i + mid + lag) % SFMT_N32)] ^= r;
+ psfmt32[idxof(i)] = r;
+ i = (i + 1) % SFMT_N32;
+ }
+
+ sfmt->idx = SFMT_N32;
+ period_certification(sfmt);
+}
+#if defined(__cplusplus)
+}
+#endif
View
295 gemrb/core/RNG/sfmt/SFMT.h
@@ -0,0 +1,295 @@
+#pragma once
+/**
+ * @file SFMT.h
+ *
+ * @brief SIMD oriented Fast Mersenne Twister(SFMT) pseudorandom
+ * number generator using C structure.
+ *
+ * @author Mutsuo Saito (Hiroshima University)
+ * @author Makoto Matsumoto (The University of Tokyo)
+ *
+ * Copyright (C) 2006, 2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima
+ * University.
+ * Copyright (C) 2012 Mutsuo Saito, Makoto Matsumoto, Hiroshima
+ * University and The University of Tokyo.
+ * All rights reserved.
+ *
+ * The 3-clause BSD License is applied to this software, see
+ * LICENSE.txt
+ *
+ * @note We assume that your system has inttypes.h. If your system
+ * doesn't have inttypes.h, you have to typedef uint32_t and uint64_t,
+ * and you have to define PRIu64 and PRIx64 in this file as follows:
+ * @verbatim
+ typedef unsigned int uint32_t
+ typedef unsigned long long uint64_t
+ #define PRIu64 "llu"
+ #define PRIx64 "llx"
+@endverbatim
+ * uint32_t must be exactly 32-bit unsigned integer type (no more, no
+ * less), and uint64_t must be exactly 64-bit unsigned integer type.
+ * PRIu64 and PRIx64 are used for printf function to print 64-bit
+ * unsigned int and 64-bit unsigned int in hexadecimal format.
+ */
+
+#ifndef SFMTST_H
+#define SFMTST_H
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <assert.h>
+
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+ #include <inttypes.h>
+#elif defined(_MSC_VER) || defined(__BORLANDC__)
+ typedef unsigned int uint32_t;
+ typedef unsigned __int64 uint64_t;
+ #define inline __inline
+#else
+ #include <inttypes.h>
+ #if defined(__GNUC__)
+ #define inline __inline__
+ #endif
+#endif
+
+#ifndef PRIu64
+ #if defined(_MSC_VER) || defined(__BORLANDC__)
+ #define PRIu64 "I64u"
+ #define PRIx64 "I64x"
+ #else
+ #define PRIu64 "llu"
+ #define PRIx64 "llx"
+ #endif
+#endif
+
+#include "SFMT-params.h"
+
+/*------------------------------------------
+ 128-bit SIMD like data type for standard C
+ ------------------------------------------*/
+#if defined(HAVE_ALTIVEC)
+ #if !defined(__APPLE__)
+ #include <altivec.h>
+ #endif
+/** 128-bit data structure */
+union W128_T {
+ vector unsigned int s;
+ uint32_t u[4];
+ uint64_t u64[2];
+};
+#elif defined(HAVE_SSE2)
+ #include <emmintrin.h>
+
+/** 128-bit data structure */
+union W128_T {
+ uint32_t u[4];
+ uint64_t u64[2];
+ __m128i si;
+};
+#else
+/** 128-bit data structure */
+union W128_T {
+ uint32_t u[4];
+ uint64_t u64[2];
+};
+#endif
+
+/** 128-bit data type */
+typedef union W128_T w128_t;
+
+/**
+ * SFMT internal state
+ */
+struct SFMT_T {
+ /** the 128-bit internal state array */
+ w128_t state[SFMT_N];
+ /** index counter to the 32-bit internal state array */
+ int idx;
+};
+
+typedef struct SFMT_T sfmt_t;
+
+void sfmt_fill_array32(sfmt_t * sfmt, uint32_t * array, int size);
+void sfmt_fill_array64(sfmt_t * sfmt, uint64_t * array, int size);
+void sfmt_init_gen_rand(sfmt_t * sfmt, uint32_t seed);
+void sfmt_init_by_array(sfmt_t * sfmt, uint32_t * init_key, int key_length);
+const char * sfmt_get_idstring(sfmt_t * sfmt);
+int sfmt_get_min_array_size32(sfmt_t * sfmt);
+int sfmt_get_min_array_size64(sfmt_t * sfmt);
+void sfmt_gen_rand_all(sfmt_t * sfmt);
+
+#ifndef ONLY64
+/**
+ * This function generates and returns 32-bit pseudorandom number.
+ * init_gen_rand or init_by_array must be called before this function.
+ * @param sfmt SFMT internal state
+ * @return 32-bit pseudorandom number
+ */
+inline static uint32_t sfmt_genrand_uint32(sfmt_t * sfmt) {
+ uint32_t r;
+ uint32_t * psfmt32 = &sfmt->state[0].u[0];
+
+ if (sfmt->idx >= SFMT_N32) {
+ sfmt_gen_rand_all(sfmt);
+ sfmt->idx = 0;
+ }
+ r = psfmt32[sfmt->idx++];
+ return r;
+}
+#endif
+/**
+ * This function generates and returns 64-bit pseudorandom number.
+ * init_gen_rand or init_by_array must be called before this function.
+ * The function gen_rand64 should not be called after gen_rand32,
+ * unless an initialization is again executed.
+ * @param sfmt SFMT internal state
+ * @return 64-bit pseudorandom number
+ */
+inline static uint64_t sfmt_genrand_uint64(sfmt_t * sfmt) {
+#if defined(BIG_ENDIAN64) && !defined(ONLY64)
+ uint32_t * psfmt32 = &sfmt->state[0].u[0];
+ uint32_t r1, r2;
+#else
+ uint64_t r;
+#endif
+ uint64_t * psfmt64 = &sfmt->state[0].u64[0];
+ assert(sfmt->idx % 2 == 0);
+
+ if (sfmt->idx >= SFMT_N32) {
+ sfmt_gen_rand_all(sfmt);
+ sfmt->idx = 0;
+ }
+#if defined(BIG_ENDIAN64) && !defined(ONLY64)
+ r1 = psfmt32[sfmt->idx];
+ r2 = psfmt32[sfmt->idx + 1];
+ sfmt->idx += 2;
+ return ((uint64_t)r2 << 32) | r1;
+#else
+ r = psfmt64[sfmt->idx / 2];
+ sfmt->idx += 2;
+ return r;
+#endif
+}
+
+/* =================================================
+ The following real versions are due to Isaku Wada
+ ================================================= */
+/**
+ * converts an unsigned 32-bit number to a double on [0,1]-real-interval.
+ * @param v 32-bit unsigned integer
+ * @return double on [0,1]-real-interval
+ */
+inline static double sfmt_to_real1(uint32_t v)
+{
+ return v * (1.0/4294967295.0);
+ /* divided by 2^32-1 */
+}
+
+/**
+ * generates a random number on [0,1]-real-interval
+ * @param sfmt SFMT internal state
+ * @return double on [0,1]-real-interval
+ */
+inline static double sfmt_genrand_real1(sfmt_t * sfmt)
+{
+ return sfmt_to_real1(sfmt_genrand_uint32(sfmt));
+}
+
+/**
+ * converts an unsigned 32-bit integer to a double on [0,1)-real-interval.
+ * @param v 32-bit unsigned integer
+ * @return double on [0,1)-real-interval
+ */
+inline static double sfmt_to_real2(uint32_t v)
+{
+ return v * (1.0/4294967296.0);
+ /* divided by 2^32 */
+}
+
+/**
+ * generates a random number on [0,1)-real-interval
+ * @param sfmt SFMT internal state
+ * @return double on [0,1)-real-interval
+ */
+inline static double sfmt_genrand_real2(sfmt_t * sfmt)
+{
+ return sfmt_to_real2(sfmt_genrand_uint32(sfmt));
+}
+
+/**
+ * converts an unsigned 32-bit integer to a double on (0,1)-real-interval.
+ * @param v 32-bit unsigned integer
+ * @return double on (0,1)-real-interval
+ */
+inline static double sfmt_to_real3(uint32_t v)
+{
+ return (((double)v) + 0.5)*(1.0/4294967296.0);
+ /* divided by 2^32 */
+}
+
+/**
+ * generates a random number on (0,1)-real-interval
+ * @param sfmt SFMT internal state
+ * @return double on (0,1)-real-interval
+ */
+inline static double sfmt_genrand_real3(sfmt_t * sfmt)
+{
+ return sfmt_to_real3(sfmt_genrand_uint32(sfmt));
+}
+
+/**
+ * converts an unsigned 32-bit integer to double on [0,1)
+ * with 53-bit resolution.
+ * @param v 32-bit unsigned integer
+ * @return double on [0,1)-real-interval with 53-bit resolution.
+ */
+inline static double sfmt_to_res53(uint64_t v)
+{
+ return v * (1.0/18446744073709551616.0);
+}
+
+/**
+ * generates a random number on [0,1) with 53-bit resolution
+ * @param sfmt SFMT internal state
+ * @return double on [0,1) with 53-bit resolution
+ */
+inline static double sfmt_genrand_res53(sfmt_t * sfmt)
+{
+ return sfmt_to_res53(sfmt_genrand_uint64(sfmt));
+}
+
+
+/* =================================================
+ The following function are added by Saito.
+ ================================================= */
+/**
+ * generates a random number on [0,1) with 53-bit resolution from two
+ * 32 bit integers
+ */
+inline static double sfmt_to_res53_mix(uint32_t x, uint32_t y)
+{
+ return sfmt_to_res53(x | ((uint64_t)y << 32));
+}
+
+/**
+ * generates a random number on [0,1) with 53-bit resolution
+ * using two 32bit integers.
+ * @param sfmt SFMT internal state
+ * @return double on [0,1) with 53-bit resolution
+ */
+inline static double sfmt_genrand_res53_mix(sfmt_t * sfmt)
+{
+ uint32_t x, y;
+
+ x = sfmt_genrand_uint32(sfmt);
+ y = sfmt_genrand_uint32(sfmt);
+ return sfmt_to_res53_mix(x, y);
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
View
7 gemrb/core/Scriptable/Actor.cpp
@@ -51,6 +51,7 @@
#include "GameScript/GSUtils.h" //needed for DisplayStringCore
#include "GameScript/GameScript.h"
#include "GUI/GameControl.h"
+#include "RNG/RNG_SFMT.h"
#include "System/StringBuffer.h"
namespace GemRB {
@@ -3368,14 +3369,14 @@ void Actor::VerbalConstant(int start, int count) const
ResolveStringConstant(soundref, start+count-1);
}
if (count > 0){
- DisplayStringCore((Scriptable *const) this, start + rand()%count, DS_CONSOLE|DS_CONST|DS_SPEECH);
+ DisplayStringCore((Scriptable *const) this, start + RAND(0, count-1), DS_CONSOLE|DS_CONST|DS_SPEECH);
}
} else { //If we are anyone else we have to check there is a corresponding strref
while(count > 0 && GetVerbalConstant(start+count-1) == (ieStrRef) -1 ) {
count--;
}
if(count > 0) {
- DisplayStringCore((Scriptable *const) this, GetVerbalConstant(start+rand()%count), DS_CONSOLE|DS_SPEECH);
+ DisplayStringCore((Scriptable *const) this, GetVerbalConstant(start+RAND(0, count-1)), DS_CONSOLE|DS_SPEECH);
}
}
}
@@ -7565,7 +7566,7 @@ bool Actor::HandleActorStance()
ca->autoSwitchOnEnd = false;
return true;
}
- int x = rand()%1000;
+ int x = RAND(0, 999);
if ((StanceID==IE_ANI_AWAKE) && !x ) {
SetStance( IE_ANI_HEAD_TURN );
return true;
View
7 gemrb/core/Scriptable/Scriptable.cpp
@@ -34,6 +34,7 @@
#include "GameScript/GSUtils.h"
#include "GameScript/Matching.h" // MatchActor
#include "GUI/GameControl.h"
+#include "RNG/RNG_SFMT.h"
#include "Scriptable/InfoPoint.h"
namespace GemRB {
@@ -1987,7 +1988,7 @@ void Movable::SetStance(unsigned int arg)
if (StanceID == IE_ANI_ATTACK) {
// Set stance to a random attack animation
- int random = rand()%100;
+ int random = RAND(0, 99);
if (random < AttackMovements[0]) {
StanceID = IE_ANI_ATTACK_BACKSLASH;
} else if (random < AttackMovements[0] + AttackMovements[1]) {
@@ -2222,8 +2223,8 @@ void Movable::RandomWalk(bool can_stop, bool run)
return;
}
//if not continous random walk, then stops for a while
- if (can_stop && (rand()&3) ) {
- SetWait((rand()&7)+7);
+ if (can_stop && RAND(0,3)) {
+ SetWait(RAND(7,14));
return;
}
if (run) {
View
3 gemrb/core/WorldMap.cpp
@@ -26,6 +26,7 @@
#include "Interface.h"
#include "TableMgr.h"
#include "Video.h"
+#include "RNG/RNG_SFMT.h"
#include <list>
@@ -463,7 +464,7 @@ WMPAreaLink *WorldMap::GetEncounterLink(const ieResRef AreaName, bool &encounter
encounter=false;
do {
lastpath = *p;
- if (lastpath->EncounterChance > (unsigned int) (rand()%100)) {
+ if (lastpath->EncounterChance > (unsigned int) RAND(0, 99)) {
encounter=true;
break;
}

No commit comments for this range

Something went wrong with that request. Please try again.