My randomizer faster than yours :)

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
Starterz
Posts: 27
Joined: Thu Apr 02, 2009 2:45 am

My randomizer faster than yours :)

Post by Starterz »

Hi, friends!
The subject is:

Code: Select all

  //!========XORSHIFT RANDOMIZER========
  //! A class using George Marsaglia's "Xorshift-128" algorithm.
  //! Provides very fast and quality sequence
  //! of 2^{128}-1 32-bit random numbers.
  class htRandomizer
  {
      unsigned long seed,x,y,z,w;
    public:
      htRandomizer(unsigned long state=GetTickCount()) {RndSet(state);}

      //! Randomization.
      void RndSet(unsigned long state=123456789)
      {seed=x=state,y=362436069,z=521288629,w=88675123;}

      //! More randomization.
      void RndShift() {RndSet(Rnd());}

      //! For farther restore a sequence we need to know a seed.
      unsigned long RndSeed(void) {return seed;}

      //! Returns unsigned long in [0..ULONG_MAX].
      unsigned long Rnd()
      {
        unsigned long t=(x^(x<<11)); x=y;y=z;z=w;
        return(w=(w^(w>>19))^(t^(t>>8)));
      }

      //! Returns float in [0,1)
      float Rndf()
      {
        unsigned long f=Rnd();
        f=0x3f800000U|(0x007fffffU&f);
        float val=*(float*)&f-1.f;
        return val;
      }

      //! Returns double in [0,1].
      double Rndd()
      {
        return Rnd()/(double)0xffffffffUL; //! ULONG_MAX.
      }

      //! Returns unsigned long in [num1..num2].
      unsigned long Rnd(unsigned long num1,unsigned long num2)
      {
        if(num1==num2) return num1;
        float rnd=Rndf();
        if(num2>num1)
          return num1+(unsigned long)(rnd*(num2-num1+1));
        else
          return num2+(unsigned long)(rnd*(num1-num2+1));
      }

      //! Returns int in [num1..num2].
      int Rndi(int num1,int num2)
      {
        if(num1==num2) return num1;
        float rnd=Rndf();
        if(num2>num1)
          return num1+(int)(rnd*(num2-num1+1));
        else
          return num2+(int)(rnd*(num1-num2+1));
      }

      //! Returns float in [num1..num2).
      float Rndf(float num1,float num2)
      {
        if(num1==num2) return num1;
        float rnd=Rndf();
        if(num2>num1)
          return (num2-num1)*rnd+num1;
        else
          return (num1-num2)*rnd+num2;
      }

      //! Returns double in [num1..num2].
      double Rndd(double num1,double num2)
      {
        if(num1==num2) return num1;
        double rnd=Rndd();
        if(num2>num1)
          return (num2-num1)*rnd+num1;
        else
          return (num1-num2)*rnd+num2;
      }

      //! Returns random boolean.
      bool Rndb() {return Rnd()%2;}

      //! Returns random sign.
      int  Rnds() {return Rndb()? 1:-1;}
  };

Using:

htRandomizer htr;

int main()
{
  for(int i=0;i<50;i++) cout<<htr.Rnd()<<endl;
  getchar();
  return 0;
}
This much faster (5 times) than rand(). Enjoy! :)
shadowslair
Posts: 758
Joined: Mon Mar 31, 2008 3:32 pm
Location: Bulgaria

Post by shadowslair »

Looks good. Will give it a try soon or later. Thanks for sharing. :wink:
"Although we walk on the ground and step in the mud... our dreams and endeavors reach the immense skies..."
randomMesh
Posts: 1186
Joined: Fri Dec 29, 2006 12:04 am

Re: My randomizer faster than yours :)

Post by randomMesh »

Make it const-correct and it would be even faster!
"Whoops..."
Murloc992
Posts: 272
Joined: Mon Apr 13, 2009 2:45 pm
Location: Utena,Lithuania

Re: My randomizer faster than yours :)

Post by Murloc992 »

randomMesh wrote:Make it const-correct and it would be even faster!
Image

:lol:
randomMesh
Posts: 1186
Joined: Fri Dec 29, 2006 12:04 am

Re: My randomizer faster than yours :)

Post by randomMesh »

Murloc992 wrote:Image
Preaching const-correctness (writing clean code in general) is one of my favorite hobbies. :P

And an RNG which is not const-correct is like a racing car with wheel locks. (Besides Xorshift is one of the fastest RNGs i know of)
"Whoops..."
Starterz
Posts: 27
Joined: Thu Apr 02, 2009 2:45 am

Well

Post by Starterz »

randomMesh wrote:
Make it const-correct and it would be even faster!
Nothing. But if I wrong. Show us Your wonderful fast code. I take my words back then and sorry.
ChaiRuiPeng
Posts: 363
Joined: Thu Dec 16, 2010 8:50 pm
Location: Somewhere in the clouds.. drinking pink lemonade and sunshine..

Re: My randomizer faster than yours :)

Post by ChaiRuiPeng »

Murloc992 wrote:
randomMesh wrote:Make it const-correct and it would be even faster!
Image

:lol:
i really have to side with randomMesh on this. you would not guess how many problems incorrect const usage can cause until it happens to you.

it is also important because say you have a passable param by reference that you know wont change. if you make that const param reference then compiler knows it doesn not need to include whatever low level assembly stuff it needs to put in for it to change. thus faster more efficient programs***

i wish i had learned this stuff from the onset... would have made my programming lifes progression easier :)
ent1ty wrote: success is a matter of concentration and desire
Butler Lampson wrote: all problems in Computer Science can be solved by another level of indirection
at a cost measure in computer resources ;)
Starterz
Posts: 27
Joined: Thu Apr 02, 2009 2:45 am

:\

Post by Starterz »

O'k people thanks for preaching. Just show your faster code.
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Post by REDDemon »

I have faster code for random floating point numbers, but your code is faster for integers than mine (not too much). good work ;-)

EDIT: i have tested it with my random number test suit.

there are at least 100. 000 .000 of numbers that are never generated (this is really good indeed!) of course finding all numbers that are not generated is not possible on my machine (i need more computing power for that).

Distribution is not the best i ever seen but is good too! :) I've used chi-quadro test and noised images (using the standard randomizer of windows gives strange artifacts on noise images, such as lines of 6 or more pixels with the same color.

very very good:)

Are you going to release it under zlib license ?
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
Starterz
Posts: 27
Joined: Thu Apr 02, 2009 2:45 am

Post by Starterz »

REDDemon wrote:
Are you going to release it under zlib license ?
Sure ;)
bitplane
Admin
Posts: 3204
Joined: Mon Mar 28, 2005 3:45 am
Location: England
Contact:

Post by bitplane »

Is this faster than Irrlicht's built-in randomizer? Anyone got test cases?
Submit bugs/patches to the tracker!
Need help right now? Visit the chat room
Lonesome Ducky
Competition winner
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Post by Lonesome Ducky »

5 times faster than rand it may be, but a simple (and common) lcg method outperforms it easily. Basic code:

Code: Select all

unsigned int rSeed;

inline void seedRand(int seed) { 
	rSeed = seed;
} 

inline int genRand() { 
	rSeed = (214013*rSeed+2531011); 
	return (rSeed>>16)&0x7FFF; 
} 
Since you asked for someone to show something faster, I threw your generator and the lcg into a little test. The generator is seeded 1000 times, and each time generates 1000000 random numbers.

The results end up being your method taking 2995ms, while the lcg takes 1514ms. That's a decrease of 1481, nearly half. Here's the code I put together for the test:

Code: Select all

#include <iostream>
#include <stdlib.h>
#include <windows.h>
using namespace std;


 
 

class htRandomizer
{
  unsigned long seed,x,y,z,w;
public:
  htRandomizer(unsigned long state=GetTickCount()) {RndSet(state);}

  //! Randomization.
  void RndSet(unsigned long state=123456789)
  {seed=x=state,y=362436069,z=521288629,w=88675123;}

  //! More randomization.
  void RndShift() {RndSet(Rnd());}

  //! For farther restore a sequence we need to know a seed.
  unsigned long RndSeed(void) {return seed;}

  //! Returns unsigned long in [0..ULONG_MAX].
  unsigned long Rnd()
  {
    unsigned long t=(x^(x<<11)); x=y;y=z;z=w;
    return(w=(w^(w>>19))^(t^(t>>8)));
  }

  //! Returns float in [0,1)
  float Rndf()
  {
    unsigned long f=Rnd();
    f=0x3f800000U|(0x007fffffU&f);
    float val=*(float*)&f-1.f;
    return val;
  }

  //! Returns double in [0,1].
  double Rndd()
  {
    return Rnd()/(double)0xffffffffUL; //! ULONG_MAX.
  }

  //! Returns unsigned long in [num1..num2].
  unsigned long Rnd(unsigned long num1,unsigned long num2)
  {
    if(num1==num2) return num1;
    float rnd=Rndf();
    if(num2>num1)
      return num1+(unsigned long)(rnd*(num2-num1+1));
    else
      return num2+(unsigned long)(rnd*(num1-num2+1));
  }

  //! Returns int in [num1..num2].
  int Rndi(int num1,int num2)
  {
    if(num1==num2) return num1;
    float rnd=Rndf();
    if(num2>num1)
      return num1+(int)(rnd*(num2-num1+1));
    else
      return num2+(int)(rnd*(num1-num2+1));
  }

  //! Returns float in [num1..num2).
  float Rndf(float num1,float num2)
  {
    if(num1==num2) return num1;
    float rnd=Rndf();
    if(num2>num1)
      return (num2-num1)*rnd+num1;
    else
      return (num1-num2)*rnd+num2;
  }

  //! Returns double in [num1..num2].
  double Rndd(double num1,double num2)
  {
    if(num1==num2) return num1;
    double rnd=Rndd();
    if(num2>num1)
      return (num2-num1)*rnd+num1;
    else
      return (num1-num2)*rnd+num2;
  }

  //! Returns random boolean.
  bool Rndb() {return Rnd()%2;}

  //! Returns random sign.
  int  Rnds() {return Rndb()? 1:-1;}
}; 

unsigned int rSeed;

inline void seedRand(int seed) { 
	rSeed = seed;
} 

inline int genRand() { 
	rSeed = (214013*rSeed+2531011); 
	return (rSeed>>16)&0x7FFF; 
} 
  

int main() {

	int startTime = GetTickCount();

	htRandomizer htr;
	for (int y = 0; y < 1000; y++) {
		htr.RndSet(y);
		for (int x = 0; x < 1000000; x++) {
			int r = htr.Rnd();
		}
	}

	int endTime = GetTickCount();

	cout << "1st test completed in: " << endTime-startTime << "ms" << endl;

	int startTime2 = GetTickCount();

	for (int y = 0; y < 1000; y++) {
		seedRand(y);
		for (int x = 0; x < 1000000; x++) {
			int r = genRand();
		}
	}

	int endTime2 = GetTickCount();

	cout << "2nd test completed in: " << endTime2-startTime2 << "ms" << endl;

	if (endTime2-startTime2 < endTime-startTime)
		cout << "2nd ";
	else
		cout << "1st ";

	cout << "test completed " << abs((endTime2-startTime2)-(endTime-startTime)) << "ms faster." << endl;

	return 0;
};

Also, I don't know why you ask if he's releasing it under a certain license. It clearly states it's based off xorshift, which is very easy to implement yourself. And good practice too! :lol:

And to bitplane: the irrlicht method took 5351ms in the same test (Normal C-library rand took ~18000).
Starterz
Posts: 27
Joined: Thu Apr 02, 2009 2:45 am

Post by Starterz »

Hm.. interesting mutation hint

Code: Select all

(rSeed>>16)&0x7FFF 
can You explain this?
About licensing :) I do understand it as a REDDemon's joke, don't You..
And ofcourse LCG haven't be more quality rng than xorshift (see wiki).
May be faster. May be.. But too simple for some applications, you know it.
Well as I tested this lcg it's not so fast as You say...
By the way, if You'll change "1st test" and "2nd test" by it's places you'll be surprised of results (can depends of compiler and hardware).
I get my randomizer is 10% faster!
Lonesome Ducky
Competition winner
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Post by Lonesome Ducky »

The shift reduces correlation, and the 0x7FFF removes the sign. LCG has a period of 2^32, which is far more than enough for most applications for games. Using it in particle generators, etc., the smaller period is not even noticeable. After 4 billion generated numbers, LCG starts to repeat. If the user can somehow keep track of where these 4 billion numbers are going, and the repeat happens to end up exactly on the same place it started, then they might have a tiny chance of noticing. That's not gonna happen, "you know it". And if you're arguing for quality, most people would say that Mersenne Twister is the best combination of quality and speed. Switching the order of the tests made a difference of a few ms on my machine, which is enough to attribute to random circumstances. LCG is still nearly twice as fast. I invite anyone on this forum to test it and post their results.
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Post by REDDemon »

lol. maybe i don't have to move from black humor to avoid that in future :)

Code: Select all

  #include <iostream>
  #include <cstdlib>
  #include <ctime>
  #include "irrTypes.h"

#include "xorshift.h" //xorshift library
#include "irrrnd.h"  //irrlicht randomizer


htRandomizer htr;

using namespace std;

int main()
{
    unsigned int startTick = clock();
    for(int i=0;i<500000000;i++)
    {
        htr.Rnd();
    }

    unsigned int endTick = clock();
    cout<<"time: "<<endTick-startTick<<endl;


    startTick = clock();
    for(int i=0;i<500000000;i++)
    {
        Rnd::rand();
    }
    endTick = clock();
    cout<<"time: "<<endTick-startTick<<endl;
}
enabling all needed compiler optimizations that's the console output:

Code: Select all

time: 1950
time: 12137

Process returned 0 (0x0)   execution time : 17.566 s
Press any key to continue.
of course i have tested only the function that generates the signed/unsigned number used for example for generating a floating point
in the range X,Y.

Now the test with range values.

Code: Select all

#include <iostream>
  #include <cstdlib>
  #include <ctime>
  #include "irrTypes.h"

#include "xorshift.h" //xorshift library
#include "irrrnd.h"  //irrlicht randomizer


htRandomizer htr;

using namespace std;

int main()
{
    unsigned int startTick = clock();
    for(int i=0;i<500000000;i++)
    {
        htr.Rndf(1234.0f, 9876.54321f);
    }

    unsigned int endTick = clock();
    cout<<"time: "<<endTick-startTick<<endl;


    startTick = clock();
    for(int i=0;i<500000000;i++)
    {
        Rnd::getRandomFloat(1234.0f,9876.54321f);
    }
    endTick = clock();
    cout<<"time: "<<endTick-startTick<<endl;
}

the output:

Code: Select all

time: 1981
time: 11263

Process returned 0 (0x0)   execution time : 17.020 s
Press any key to continue.

the function "getRandomFloat" is found in irrsolid randomizer, it uses the irrlicht randomizer but is different from irrlicht "randf()" (more faster).

anyway the comparison is univoque.

The Xorshift algorithm is 10 time faster than irrlicht randomizer,
Irrlicht randomizer is 2/3 time faster than <stdlib> randomizer.

now i will use the chi-quadro test and monte carlo simulation. I'll examine now distribution propierties:
(code omitted, was a bit longer for this topic :) )

Outputs:

Code: Select all

check value: 3.5000000
htr : 3.50014
irrlicht: 3.0002

check value: 10.5000000
htr: 10.5004
irrlicht: 9.99967

Process returned 0 (0x0)   execution time : 7.285 s
Press any key to continue.
chi-quadro (95%)

Code: Select all

htr: pass
irrlicht: fail

Process returned 0 (0x0)   execution time : 18.455 s
Press any key to continue.

Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
Post Reply