CRandom::Random() returns negetive number

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • CRandom::Random() returns negetive number

      If anyone get's any free time see if you can get the following function ( part of the CRandom class ) to return a negetive number ( specifically -0.5000 it seems ). It seems to do it rather often, maybe 1 out of 10 times. I haven't figured out why and I've set the seed both on my own and through ::Randomize().

      Let me know if you find the same result.

      // Returns a random float between 0.0f-1.0f
      // NEW for Game Code Complete 2nd Edition!

      Source Code

      1. float CRandom::Random( )
      2. {
      3. int r = (float)Random(0xffffffff);
      4. float divisor = (float)0xffffffff;
      5. return r / divisor;
      6. }


      EDIT: After doing some research it seems as though r comes up as -2147483648 for some reason... and it actually seems to do it more then I originally thought. So it seems as though the problem is with the CRandom::Random( unsigned int ) not the above one. ( Both are located in the CMath_Random.cpp )

      Below is this function.

      Source Code

      1. // Returns a number from 0 to n (excluding n)
      2. unsigned int CRandom::Random( unsigned int n )
      3. {
      4. unsigned long y;
      5. static unsigned long mag01[2]={0x0, CMATH_MATRIX_A};
      6. if(n==0)
      7. return(0);
      8. /* mag01[x] = x * MATRIX_A for x=0,1 */
      9. if (mti >= CMATH_N) { /* generate N words at one time */
      10. int kk;
      11. if (mti == CMATH_N+1) /* if sgenrand() has not been called, */
      12. SetRandomSeed(4357); /* a default initial seed is used */
      13. for (kk=0;kk<CMATH_N-CMATH_M;kk++) {
      14. y = (mt[kk]&CMATH_UPPER_MASK)|(mt[kk+1]&CMATH_LOWER_MASK);
      15. mt[kk] = mt[kk+CMATH_M] ^ (y >> 1) ^ mag01[y & 0x1];
      16. }
      17. for (;kk<CMATH_N-1;kk++) {
      18. y = (mt[kk]&CMATH_UPPER_MASK)|(mt[kk+1]&CMATH_LOWER_MASK);
      19. mt[kk] = mt[kk+(CMATH_M-CMATH_N)] ^ (y >> 1) ^ mag01[y & 0x1];
      20. }
      21. y = (mt[CMATH_N-1]&CMATH_UPPER_MASK)|(mt[0]&CMATH_LOWER_MASK);
      22. mt[CMATH_N-1] = mt[CMATH_M-1] ^ (y >> 1) ^ mag01[y & 0x1];
      23. mti = 0;
      24. }
      25. y = mt[mti++];
      26. y ^= CMATH_TEMPERING_SHIFT_U(y);
      27. y ^= CMATH_TEMPERING_SHIFT_S(y) & CMATH_TEMPERING_MASK_B;
      28. y ^= CMATH_TEMPERING_SHIFT_T(y) & CMATH_TEMPERING_MASK_C;
      29. y ^= CMATH_TEMPERING_SHIFT_L(y);
      30. // ET - old engine added one to the result.
      31. // We almost NEVER wanted to use this function
      32. // like this. So, removed the +1 to return a
      33. // range from 0 to n (not including n).
      34. return (y%n);
      35. }
      Display All

      The post was edited 2 times, last by Alien_Attack ().

    • RE: CRandom::Random() returns negetive number

      Is it the same number or diffrent negetive numbers?

      Remeber there is a difference between signed and unsigned numbers. It may be that your casting the return (unsigned) to an integer (signed) and it's turning yoru very large number into a negetive number. The reason this happens is because a negetive in binary is any number with the first bit being 1. So 10000001 (0x81) or is actually -1 signed but 257 unsigned.
      .Code
      push you ; haha!
    • Well it's the same negetive number ( -0.50000 ) that is returned from CRandom::Random() which is out of the range 0.0 - 1.0 unless I'm missing something.

      However, the reason CRandom::Random() puts out a negetive is because the variable r (inside of CRandom::Random() ) which is the return variable for CRandom::Random(unsigned int) ret that function is negetive ( -2147483648 ). I hope that makes any sense...

      Source Code

      1. float CRandom::Random( )
      2. {
      3. int r = (float)Random(0xffffffff);
      4. float divisor = (float)0xffffffff;
      5. return r / divisor;
      6. }


      int r = (float)Random(0xffffffff); // <--- this function sometimes returns -2147483648

      When it returns this, it cuases CRandom::Random() to return a negitive number (when it returns a negetive it's always -0.50000 )
    • Maybe an example program and output will help:

      Source Code

      1. #include <stdio.h>
      2. int main()
      3. {
      4. int r = -2147483648;
      5. printf(" r(%11d, 0x%x, %f)\n", r, r, r);
      6. float divisor = (float) 0xffffffff;
      7. printf("divisor(%11d, 0x%x, %f)\n", divisor, divisor, divisor);
      8. float result = r / divisor;
      9. printf(" result(%11d, 0x%x, %f)\n", result, result, result);
      10. printf("\n%d / %f = %f\n", r, divisor, result);
      11. }
      Display All


      Output (g++ (GCC) 3.4.4 20050721 (Red Hat 3.4.4-2)):

      > ./a.out
      r(-2147483648, 0x80000000, 0.000000)
      divisor( 0, 0x41f00000, 4294967296.000000)
      result( 0, 0xbfe00000, -0.500000)

      -2147483648 / 4294967296.000000 = -0.500000


      -0.5 makes sense to me when I look at the data and types used.

      BTW, in case you were wondering, 0x80000000 is the floating point value of negative zero. Isn't floating point fun?
    • This RNG is pretty common - and it was used in a very demanding enterprize level system that requires truly excellent random numbers.

      I googled the problem but only found a posting about the book, and some forum talking about the RNG in a language that I'm guessing is common in Indonesia....very odd...

      The return value of 0x80000000 is possible, of course - but shouldn't happen very often.

      I wrote a bit of code to investigate:


      CRandom random;
      int negatives = 0;
      int positives = 0;
      int hits = 0;
      int ones = 0;
      int zeros = 0;
      while (1)
      {
      float f = random.Random();
      if (f < 0.0f)
      negatives++;
      else if (f == 0.0f)
      zeros++;
      else if (f == 1.0f)
      ones++;
      else if (f > 1.0f)
      positives++;
      }


      It seems that the floating point value returned from float CRandom::Random() was actually between -0.5f and 0.5f.

      Good catch finding that problem - but it still shouldn't have happened with the frequency you report...
      Mr.Mike
      Author, Programmer, Brewer, Patriot
    • If the output of that function was between -0.5f and 0.5f then it makes sense as to why we thought we had more. We thought the function returned between 0.0f and 1.0f and that the -5 was a random (pun intended) event, not happening very frequently. So when we started ending up with numbers like 1.5, -0.5, 0.5 we figured it was due to the Random() function returning -0.5. However with our algorithm to determin those numbers (Taking the output of Random(unsined int ) and adding the output of Random() to it, it could have been a 0.5 that helped add to those outputs. So that's why we thought it was happening frequently.

      So then I'm guessing it's range is actually suppose to be from 0.0f and 1.0f, and not -0.5f and 0.5f. If this is the case what needs to be changed to fix it?
    • I fixed it by adding 0.5f before returning the value r / divisor in the ::Random method.
      Mr.Mike
      Author, Programmer, Brewer, Patriot
    • Cop out? You come up with a more 'correct' fix and I'll buy you lunch.
      Mr.Mike
      Author, Programmer, Brewer, Patriot
    • Hi all,

      I'm digging up an old thread here about CRandom just to report that on the latest code from GCC third edition.

      I am using the float CRandom::Random() that is to return a random value between 0.0 and 1.0. I was using it to generate random points for a particle system I am working on. I found that 3D points are grouped together into certain bunches.

      On investigation, I found that 0.0f is returned quite frequenly. I don't have exact numbers but it would happen 3-4 times out of 10 (I can write a little test program tomorrow to get a more exact count of this if anybody wants...).

      Also when i use rand() i got more random results for my particle system. The RNG generator algorithm here is good as its repeatable with a known seed but is there a drawback that its results are not as 'random' as using rand() and srand()?

      Thanks for reading and hope you can help!