Random float number generation

后端 未结 14 1338
孤城傲影
孤城傲影 2020-11-22 05:05

How do I generate random floats in C++?

I thought I could take the integer rand and divide it by something, would that be adequate enough?

相关标签:
14条回答
  • 2020-11-22 05:25

    For C++, it can generate real float numbers within the range specified by dist variable

    #include <random>  //If it doesnt work then use   #include <tr1/random>
    #include <iostream>
    
    using namespace std;
    
    typedef std::tr1::ranlux64_base_01 Myeng; 
    typedef std::tr1::normal_distribution<double> Mydist;
    
    int main() { 
           Myeng eng; 
           eng.seed((unsigned int) time(NULL)); //initializing generator to January 1, 1970);
           Mydist dist(1,10); 
    
           dist.reset(); // discard any cached values 
           for (int i = 0; i < 10; i++)
           {
               std::cout << "a random value == " << (int)dist(eng) << std::endl; 
           }
    
           return (0);
    }
    
    0 讨论(0)
  • 2020-11-22 05:26

    rand() return a int between 0 and RAND_MAX. To get a random number between 0.0 and 1.0, first cast the int return by rand() to a float, then divide by RAND_MAX.

    0 讨论(0)
  • 2020-11-22 05:27

    On some systems (Windows with VC springs to mind, currently), RAND_MAX is ridiculously small, i. e. only 15 bit. When dividing by RAND_MAX you are only generating a mantissa of 15 bit instead of the 23 possible bits. This may or may not be a problem for you, but you're missing out some values in that case.

    Oh, just noticed that there was already a comment for that problem. Anyway, here's some code that might solve this for you:

    float r = (float)((rand() << 15 + rand()) & ((1 << 24) - 1)) / (1 << 24);
    

    Untested, but might work :-)

    0 讨论(0)
  • 2020-11-22 05:30

    Take a look at Boost.Random. You could do something like this:

    float gen_random_float(float min, float max)
    {
        boost::mt19937 rng;
        boost::uniform_real<float> u(min, max);
        boost::variate_generator<boost::mt19937&, boost::uniform_real<float> > gen(rng, u);
        return gen();
    }
    

    Play around, you might do better passing the same mt19937 object around instead of constructing a new one every time, but hopefully you get the idea.

    0 讨论(0)
  • 2020-11-22 05:32

    If you know that your floating point format is IEEE 754 (almost all modern CPUs including Intel and ARM) then you can build a random floating point number from a random integer using bit-wise methods. This should only be considered if you do not have access to C++11's random or Boost.Random which are both much better.

    float rand_float()
    {
        // returns a random value in the range [0.0-1.0)
    
        // start with a bit pattern equating to 1.0
        uint32_t pattern = 0x3f800000;
    
        // get 23 bits of random integer
        uint32_t random23 = 0x7fffff & (rand() << 8 ^ rand());
    
        // replace the mantissa, resulting in a number [1.0-2.0)
        pattern |= random23;
    
        // convert from int to float without undefined behavior
        assert(sizeof(float) == sizeof(uint32_t));
        char buffer[sizeof(float)];
        memcpy(buffer, &pattern, sizeof(float));
        float f;
        memcpy(&f, buffer, sizeof(float));
    
        return f - 1.0;
    }
    

    This will give a better distribution than one using division.

    0 讨论(0)
  • 2020-11-22 05:33

    In my opinion the above answer do give some 'random' float, but none of them is truly a random float (i.e. they miss a part of the float representation). Before I will rush into my implementation lets first have a look at the ANSI/IEEE standard format for floats:

    |sign (1-bit)| e (8-bits) | f (23-bit) |

    the number represented by this word is (-1 * sign) * 2^e * 1.f

    note the the 'e' number is a biased (with a bias of 127) number thus ranging from -127 to 126. The most simple (and actually most random) function is to just write the data of a random int into a float, thus

    int tmp = rand();
    float f = (float)*((float*)&tmp);
    

    note that if you do float f = (float)rand(); it will convert the integer into a float (thus 10 will become 10.0).

    So now if you want to limit the maximum value you can do something like (not sure if this works)

    int tmp = rand();
    float f = *((float*)&tmp);
    tmp = (unsigned int)f       // note float to int conversion!
    tmp %= max_number;
    f -= tmp;
    

    but if you look at the structure of the float you can see that the maximum value of a float is (approx) 2^127 which is way larger as the maximum value of an int (2^32) thus ruling out a significant part of the numbers that can be represented by a float. This is my final implementation:

    /**
     * Function generates a random float using the upper_bound float to determine 
     * the upper bound for the exponent and for the fractional part.
     * @param min_exp sets the minimum number (closest to 0) to 1 * e^min_exp (min -127)
     * @param max_exp sets the maximum number to 2 * e^max_exp (max 126)
     * @param sign_flag if sign_flag = 0 the random number is always positive, if 
     *              sign_flag = 1 then the sign bit is random as well
     * @return a random float
     */
    float randf(int min_exp, int max_exp, char sign_flag) {
        assert(min_exp <= max_exp);
    
        int min_exp_mod = min_exp + 126;
    
        int sign_mod = sign_flag + 1;
        int frac_mod = (1 << 23);
    
        int s = rand() % sign_mod;  // note x % 1 = 0
        int e = (rand() % max_exp) + min_exp_mod;
        int f = rand() % frac_mod;
    
        int tmp = (s << 31) | (e << 23) | f;
    
        float r = (float)*((float*)(&tmp));
    
        /** uncomment if you want to see the structure of the float. */
    //    printf("%x, %x, %x, %x, %f\n", (s << 31), (e << 23), f, tmp, r);
    
        return r;
    }
    

    using this function randf(0, 8, 0) will return a random number between 0.0 and 255.0

    0 讨论(0)
提交回复
热议问题