Problem getting random floats from ints in CRandom::Random()

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

    • Problem getting random floats from ints in CRandom::Random()

      Hey Mike,

      I am eating through your book, enjoying every minute of it. Seriously, thanks for putting it together.

      Having my first post in this forum point out a "problem" strikes me as a bit rude, but I trust you'll get that it's just my way of trying to give something back.

      Anyhow, let's get to the meat of things... in the online source code you define CRandom::Random() as follows:

      Source Code

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


      In Linux, using gcc, the integer overflow in the first line of this method does not behave in the way the method is hoping. Instead of having its value roll around, it just sticks the max negative int value into r (which results in the whole method returning zero every time it wants to give back something less than 0.5). I was also having trouble convincing myself that limiting the floats that we could return to ones obtained by fractions of 0xffffffff was sufficient... anyone have a quick explanation why it's sufficient? Or is my spidey-sense right this time?

      There! That's all the negative stuff out of the way. Wasn't so bad, was it? Like I said, I'm posting primarily to give something back, so here's a stab at a rewrite:

      Source Code

      1. // Returns a random float between 0.0f and 1.0f.
      2. // Relies on an IEEE representation of floating point numbers
      3. float CRandom::Random(){
      4. // use our random integer generator to grab a random set of mantissa bits
      5. unsigned int random_bits = Random(0x00800000);
      6. // set the exponent bits to result in an exponent of 1
      7. random_bits |= 0x3f800000;
      8. // look at the bit pattern we just constructed as a float
      9. float* random_float_ptr = reinterpret_cast<float*>(&random_bits);
      10. // IEEE normalized storage means our custom mantissa has an implied leading "1."
      11. // (i.e. it's not stored in the bits). We subtract it off to get just the
      12. // fractional part we constructed.
      13. *random_float_ptr -= 1.0f;
      14. return *random_float_ptr;
      15. }
      Display All


      As noted in the comment, we've traded our assumption about how integer overflow works for assuming that our system is using IEEE floating point representation (there's a pretty concise description of it here: msdn.microsoft.com/en-us/library/0b34tf65(VS.80).aspx), but it's at least more portable than relying on overflow (and can be ported to other reps... if you ever encounter any). I acknowledge that the bit manipulations might seem a bit exotic at first, but I like that once it's clear how the float representation works, it's totally clear that the resulting float generator is exactly as random as the random integer generator used to construct it.

      Confession time: I have only tested this in Linux using gcc, and I don't have any bright programmers at my house this weekend to run it by, so there might be some classic (embarrassing) guy-codes-alone-misses-the-obvious type problems in my solution. Please be gentle when pointing them out.

      The post was edited 3 times, last by eulerCircuit ().