The rand() function returns a pseudo-random number from 0 to 2 ^ 31 -1. It never returns negative numbers, but at the same time "steals" as much as half the range of possible values, because it could give uint32_t, and not the positive half of the int32_t. How to fix it? And how to request just a few pseudo-random bytes, but not "trimmed" in half? I am interested in libraries that could be connected via include and not rewrite the code separately under windows / linux. The following code shows that when using signed variables, the first bit is truncated. Why is that?

 std::random_device RD; std::uniform_int_distribution<int64_t> id; std::uniform_int_distribution<uint64_t> uid; std::cout << id.min() << std::endl; std::cout << id.max() << std::endl; std::cout << uid.min() << std::endl; std::cout << uid.max() << std::endl; 

Exhaust:

 0 9223372036854775807 0 18446744073709551615 

    3 answers 3

    The rand() function returns a pseudo-random number between 0 and RAND_MAX . What is RAND_MAX depends on the implementation. From the fact that in the implementation you use this value is 2 31 -1 it does not mean at all that it is everywhere.

    In other words, the rand() function generates [log 2 (RAND_MAX + 1)] pseudo-random bits. By calling this function several times, you can get as many pseudo-random bits as you like and match these bits to any number of bits.

    For example, on your platform

     uint32_t r = ((uint32_t) RAND_MAX + 1) * rand() + rand(); 

    will give you a pseudo-random number in the uint32_t range.

    This, however, is somewhat wasteful, for we do not use all the generated pseudo-random bits. It will not be difficult to write a more general variant that will use rand() to generate a continuous stream of pseudo-random bits, and then "bite" pieces of the required length — even bytes, even kilobytes.

    In any case, if within your task you are satisfied with the characteristics of pseudo-random numbers generated by the simplest generators, then the implementation of a rand() function takes one or two lines. Implement your own, under the desired range.

    • std::random_device RD; std::uniform_int_distribution<int64_t> uid; std::cout << uid.min() << std::endl; std::cout << uid.max() << std::endl; std::cout << uid(RD) << std::endl; in this case, one bit is also "trimmed". But if you replace int with uint, then the maximum value is 2 times more. - user338470
    • @ user338470: And? What exactly do you mean by that? - AnT
    • What "cutback" by one bit happens. I want to understand why? - user338470
    • @ user338470: Because traditionally, [pseudo] random number generators work only in the non-negative range. - AnT
    • In this case, std :: uniform_int_distribution <int64_t> uid (-10, -5); should have given an error, but it gives random negative numbers. This is in addition to the fact that random bytes, and how to display, with or without a sign, is not a generator issue. Therefore, I cannot understand why for character numbers min () is set to 0, and not to the minimum value of the data type. - user338470

    The rand () function returns a pseudo-random number according to an UNIFORM distribution of random numbers. Uniform distribution than characterized? By the fact that, on average, according to the law of large numbers, these numbers will tend to a certain "average" value. rand () is just an implementation of the distribution law (and then, just a pseudo-random implementation). And could you clarify the question. Because you ask about rand (), but for some reason you do not use this function in the code. Instead, use the uniform_int_distribution class. In this case, for some reason, do not use the opportunity of this class: to set the minimum and maximum values ​​of possible random (!) Numbers. for example

     std::random_device rd; /*используется для получения начального числа для генератора случайных чисел*/ std::mt19937 gen(rd()); //стандартный mersenne_twister_engine с начальным числом rd() std::uniform_int_distribution<> dis(1, 6); /*тут мы устанавливаем минимальное и максимально возможные числа, т.е. диапазон случайных чисел*/ for (int n=0; n<10; ++n) /* можно использовать dis для преобразования случайного unsigned int, сгенерированного с помощью gen в int в диапазоне [1, 6] */ std::cout << dis(gen) << ' '; 

    Actually, the previous answer is practically the same, but as a function.

    "Therefore, I cannot understand why for character numbers min () is set to 0, and not to the minimum value of the data type." - because it is the realization of a uniform distribution law. Look at the standard schedule of such a distribution law - and everything will immediately become clear to you.

    Another example

     #include <iostream> #include <random> #include <ctime> #include <string> int main() { std::mt19937 gen(time(0)); std::uniform_int_distribution<int> uid1(0, 50), uid2(uid1.param()); std::cout << "uid1 max: " << uid1.max() << std::endl << "uid1 min: " << uid1.min() << std::endl << "uid2 max: " << uid2.max() << std::endl << "uid2 min: " << uid2.min() << std::endl; } 

    The screen will display:

     uid1 max: 50 uid1 min: 0 uid2 max: 50 uid2 min: 0 
    • In the end, I decided that it was easier to read the bytes from /dev/urandom , anyway, I’m sitting under Linux almost all the time. "uniform distribution" is my task, from an outside function I need only a stream of pseudo-random bytes, but I would like to be able to transfer the code under Windows. - user338470

    You can try this code only with the types you need.
    It seems that this should solve your problem:

     double random(double from, double to) { std::random_device rd; std::mt19937 mt(rd()); std::uniform_real_distribution<>urd(from, to); return urd(mt); }