diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 4be085397..a1ada179b 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -369,6 +369,7 @@ HEADERS += util/folderiterator.h \ util/rsthreads.h \ util/rsversion.h \ util/rswin.h \ + util/rsrandom.h \ SOURCES += dbase/cachestrapper.cc \ dbase/fimonitor.cc \ @@ -485,4 +486,5 @@ SOURCES += util/folderiterator.cc \ util/rsprint.cc \ util/rsthreads.cc \ util/rsversion.cc \ - util/rswin.cc + util/rswin.cc \ + util/rsrandom.cc diff --git a/libretroshare/src/tests/general/Makefile b/libretroshare/src/tests/general/Makefile index 34380a513..b6abff391 100644 --- a/libretroshare/src/tests/general/Makefile +++ b/libretroshare/src/tests/general/Makefile @@ -7,14 +7,17 @@ RS_TOP_DIR = ../.. include $(RS_TOP_DIR)/tests/scripts/config.mk ############################################################### -TESTOBJ = netsetup_test.o -TESTS = netsetup_test +TESTOBJ = netsetup_test.o random_test.o +TESTS = netsetup_test random_test all: tests netsetup_test: netsetup_test.o $(CC) $(CFLAGS) -o netsetup_test netsetup_test.o $(LIBS) +random_test: random_test.o + $(CC) $(CFLAGS) -o random_test random_test.o $(LIBS) + ############################################################### include $(RS_TOP_DIR)/tests/scripts/rules.mk ############################################################### diff --git a/libretroshare/src/tests/general/random_test.cc b/libretroshare/src/tests/general/random_test.cc new file mode 100644 index 000000000..3edfb6e98 --- /dev/null +++ b/libretroshare/src/tests/general/random_test.cc @@ -0,0 +1,161 @@ +#ifdef LINUX +#include +#endif +#include +#include +#include +#include +#include "util/utest.h" +#include "util/rsrandom.h" + +INITTEST(); +typedef double (* Ifctn)( double t); +/* Numerical integration method */ +double Simpson3_8( Ifctn f, double a, double b, int N) +{ + int j; + double l1; + double h = (b-a)/N; + double h1 = h/3.0; + double sum = f(a) + f(b); + + for (j=3*N-1; j>0; j--) { + l1 = (j%3)? 3.0 : 2.0; + sum += l1*f(a+h1*j) ; + } + return h*sum/8.0; +} + +#define A 12 +double Gamma_Spouge( double z ) +{ + int k; + static double cspace[A]; + static double *coefs = NULL; + double accum; + double a = A; + + if (!coefs) { + double k1_factrl = 1.0; + coefs = cspace; + coefs[0] = sqrt(2.0*M_PI); + for(k=1; k 2.0e-8) && (y < x)) y += .4; + if (y>x) y=x; + + return 1.0 - Simpson3_8( &f0, 0, y, std::max(5,(int)(y/h)))/Gamma_Spouge(a); +} + +double chi2Probability( int dof, double distance) +{ + return GammaIncomplete_Q( 0.5*dof, 0.5*distance); +} + +class myThread: public RsThread +{ + public: + myThread() + { + _finished = false ; + } + virtual void run() + { + // test that random numbers are regularly disposed + // + int N = 500 ; + int B = 8 ; + + std::vector buckets(B,0) ; + + for(int i=0;i significance) + std::cerr << ": passed" << std::endl ; + else + std::cerr << ": failed" << std::endl ; + + _finished = true ; + } + + bool finished() const { return _finished ; } + private: + bool _finished ; +}; + + +int main(int argc, char **argv) +{ +#ifdef LINUX + feenableexcept(FE_INVALID) ; + feenableexcept(FE_DIVBYZERO) ; +#endif + int nt = 10 ; // number of threads. + std::vector threads(nt,(myThread*)NULL) ; + + for(int i=0;istart() ; + } + + while(true) + { + bool finished = true ; + + for(int i=0;ifinished()) + finished = false ; + + if(finished) + break ; + } + for(int i=0;i +#include "rsrandom.h" + +uint32_t RSRandom::index = 0 ; +static bool auto_seed = RSRandom::seed(time(NULL)) ; +std::vector RSRandom::MT(RSRandom::N,0u) ; +RsMutex RSRandom::rndMtx ; + +bool RSRandom::seed(uint32_t s) +{ + RsStackMutex mtx(rndMtx) ; + + MT.resize(N,0) ; // because MT might not be already resized + + uint32_t j ; + MT[0]= s & 0xffffffffUL; + for (j=1; j> 30)) + j) & 0xffffffffUL ; + + return true ; +} + +void RSRandom::locked_next_state() +{ + for(uint32_t i=0;i> 1) ; + + if((y & 1) == 1) + MT[i] = MT[i] ^ 0x9908b0df ; + } + index = 0 ; +} + +uint32_t RSRandom::random_u32() +{ + uint32_t y; + + { + RsStackMutex mtx(rndMtx) ; + + y = MT[index++] ; + + if(index == N) + locked_next_state(); + } + + // Tempering + y ^= (y >> 11); + y ^= (y << 7 ) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + + return y; +} + +uint64_t RSRandom::random_u64() +{ + return ((uint64_t)random_u32() << 32ul) + random_u32() ; +} + +float RSRandom::random_f32() +{ + return random_u32() / (float)(~(uint32_t)0) ; +} + +double RSRandom::random_f64() +{ + return random_u64() / (double)(~(uint64_t)0) ; +} + diff --git a/libretroshare/src/util/rsrandom.h b/libretroshare/src/util/rsrandom.h new file mode 100644 index 000000000..38d405039 --- /dev/null +++ b/libretroshare/src/util/rsrandom.h @@ -0,0 +1,60 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2010 Cyril Soler + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ + +#pragma once + +// RSRandom contains a random number generator that is +// - thread safe +// - system independant +// - fast +// - cryptographically safe +// +// The implementation is adapted from the Mersenne Twister page of Wikipedia. +// +// http://en.wikipedia.org/wiki/Mersenne_twister + +#include +#include + +class RSRandom +{ + public: + static uint32_t random_u32() ; + static uint64_t random_u64() ; + static float random_f32() ; + static double random_f64() ; + + static bool seed(uint32_t s) ; + + private: + static RsMutex rndMtx ; + + static const uint32_t N = 624; + static const uint32_t M = 397; + + static const uint32_t MATRIX_A = 0x9908b0dfUL; + static const uint32_t UMASK = 0x80000000UL; + static const uint32_t LMASK = 0x7fffffffUL; + + static void locked_next_state() ; + static uint32_t index ; + static std::vector MT ; +};