简体   繁体   中英

Equivalent of this Python random number generator in C++?

Just switch from Python to C++ and I begin to re-write my Python tools in C++ for better understanding, but can't solve this one...

This function will generate range of random numbers, for example "randomRange(12)" may return range of 12 numbers like "823547896545"

Python:

  def randomRange(n):
        range_start = 10**(n-1)
        range_end = (10**n)-1
        return randint(range_start, range_end)

  number = randomRange(12)

C++:

  int n;
  int randomRange(n){
        int range_start = ?
        int range_end = ?
        int result = ?(range_start, range_end);
        return (result);
  };

  int number = randomRange(12);

I can't find equivalent for question marks " ? "

You'll have trouble getting good randomness with high values of n, but:

#include <math.h>         // for pow()
#include <stdlib.h>       // for drand48()

long randomRange(int n)
{
    // our method needs start and size of the range rather 
    // than start and end.
    long range_start = pow(10,n-1);
    long range_size = pow(10,n)-range_start;
    // we expect the rand48 functions to offer more randomness
    // than the more-well-known rand() function. drand48()
    // gives you a double-precision float in 0.0-1.0, so we 
    // scale up by range_size and and to the start of the range.
    return range_start + long(drand48() * range_size);
};

Here's another approach. On 32-bit platforms, you can only do 9 digits in an int, so we'll make the function return a double, and generate a string of ASCII digits then convert:

#include <math.h>         // for pow()
#include <stdlib.h>       // for atof()

// arbitrary limit
const int MAX_DIGITS = 24;

double randomRange(int n)
{
    char bigNumString[ MAX_DIGITS+1 ];
    if (n > MAX_DIGITS)
    {
        return 0;
    }
    // first digit is 1-9
    bigNumString[0] = "123456789"[rand()%9];
    for (int i = 1; i < n; i++)
    {
        // subsequent digits can be zero
        bigNumString[i] = "0123456789"[rand()%10];
    }
    // terminate the string
    bigNumString[i] = 0;
    // convert it to float
    return atof(bigNumString);
};

You should have a look at the facilities in boost:

http://www.boost.org/doc/libs/1_47_0/doc/html/boost_random/tutorial.html#boost_random.tutorial.generating_integers_in_a_range

There are also similar features in C++11:

http://en.cppreference.com/w/cpp/numeric/random

int randomRange(n)
{
    int range_start = (int)pow(10, n-1);
    int range_end = (int)pow(10, n) - 1;
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dist(range_start, range_end);
    return dist(gen);
}

Note that you can get much better performance by moving all but the dist(gen) into an initialization function which is only called once.

You basically have just rand which you can bend to your will:

int result = (rand() % (range_end - range_start)) + range_start;

To explain, rand() generates a random number across a subset of the integer values. You can use modulo lo limit the range of the numbers, then use your start value to provide an offset.

(Also be sure to seed the random number generator )

Note Rand apparently is a pretty lousy random number generator (I had no idea). See the comments.

Truly i don't know what is the algorithm to generate random numbers in python but in C++ isn't good because the frequency of repetition is too much. I recommend to you use mersenne twister algorithm you can download library and you will see more things about in this page .

I would use something like:

#include <ctime>
#include <cmath>
unsigned long long randomRange(unsigned int n){
    static bool first = true;
    if (first)
         srand((unsigned int)time(nullptr)); //seed the generator the first time
    //as others say, std::pow to get the range
    double range_start = std::pow(10.0, n-1.0);
    double range_end = std::pow(10.0, double(n))-1.0;
    unsigned long long range = range_end-range_start;
    //generate a random number between 0 and 2^64 (minimum)
    unsigned long long result 
        = rand()*RAND_MAX*RAND_MAX*RAND_MAX
        + rand()*RAND_MAX*RAND_MAX
        + rand()*RAND_MAX
        + rand();
    //force it into range.
    return unsigned long long(result % range + range_start);
};

unsigned long long number = randomRange(12);

This is simple, (and I use something like this all the time), but rand() is not the most even distribution, and the use of modulo in the last step skews results even more toward lower numbers. Also, since it calls rand() four times, it might be slower than many solutions, and since I make minimal assumptions about RAND_MAX, it might not be optimal (though. However, this is a simple solution that is portable. (works on windows/linux/whatever), and will work as long as n is between 1 and ~17. Above ~17, it will only pick numbers in the bottom of the range, but since 64-bit long long only holds ~19.26 digits anyway, I don't think it'll be an issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM