Вопрос:

Generating random numbers without using cstdlib?

c++

363 просмотра

2 ответа

163 Репутация автора

This is a homework question, but it's a small part of a much bigger project. One of the constraints is that we are not allowed to use STL for any reason.

I've attempted to roll up my own rand() function using ctime and an incrementing modifier. I figured that even though this doesn't have a consistent seed, the function should output semi-random numbers so long as it's not fed the same modifier more than once per second.

//notcstdlib.cpp
//<ctime> <cmath>
int rand(int mod)
{
    time_t seed;
    return std::abs(seed * mod);
}

but this sample code

//main.cpp
#include "notcstdlib.h"
#include <iostream>

int main(int argc, char** argv)
{
    int f;
    for(int i = 1; i <= 10; i++)
    {
        f = rand(i);
        std::cout << "random num= " << f << "\n";
        std::cout << "rand % 10 = " << f%10 << "\n";
    }
    return 0;
}

Always returns 7 as the first value and only even numbers between 0 and 8 for every other number.

//Output 1              //Output 2              //Output 3
random num= 134514987 | random num= 134514987 | random num= 134514987
rand % 10 = 7         | rand % 10 = 7         | rand % 10 = 7
random num= 13261304  | random num= 24238584  | random num= 27941368
rand % 10 = 4         | rand % 10 = 4         | rand % 10 = 8
random num= 19891956  | random num= 36357876  | random num= 41912052
rand % 10 = 6         | rand % 10 = 6         | rand % 10 = 2
random num= 26522608  | random num= 48477168  | random num= 55882736
rand % 10 = 8         | rand % 10 = 8         | rand % 10 = 6
random num= 33153260  | random num= 60596460  | random num= 69853420
rand % 10 = 0         | rand % 10 = 0         | rand % 10 = 0
random num= 39783912  | random num= 72715752  | random num= 83824104
rand % 10 = 2         | rand % 10 = 2         | rand % 10 = 4
random num= 46414564  | random num= 84835044  | random num= 97794788
rand % 10 = 4         | rand % 10 = 4         | rand % 10 = 8
random num= 53045216  | random num= 96954336  | random num= 111765472
rand % 10 = 6         | rand % 10 = 6         | rand % 10 = 2
random num= 59675868  | random num= 109073628 | random num= 125736156
rand % 10 = 8         | rand % 10 = 8         | rand % 10 = 6
random num= 66306520  | random num= 121192920 | random num= 139706840
rand % 10 = 0         | rand % 10 = 0         | rand % 10 = 0

Obviously I'm missing some important aspect of rand() and I'm not implementing it. Is there a better way to tackle this issue?

Автор: anthony Источник Размещён: 08.11.2017 11:56

Ответы (2)


2 плюса

3414 Репутация автора

You never initialize your seed, try

//notcstdlib.cpp
<ctime>
int rand(int mod)
{
    static time_t seed = time(NULL);
    return std::abs(seed * mod);
}
Автор: xvan Размещён: 09.11.2017 12:06

2 плюса

41872 Репутация автора

Решение

You should probably ask your teacher whether std::rand() is also excluded and whether you really need to implement your own pseudo-random number generator. Or better, ask if you're allowed to use <random> so that you can use the Mercene Twister engine of C++, which is a very good pseudo-random number generator.

If you really need to roll your own, the simplest replacement for std::rand() is an LCG (Linear Congruential Generator):

#define MY_RAND_MAX = 2147483647
static unsigned long my_rand_state = 1;

void my_srand(unsigned long seed)
{
    my_rand_state = seed;
}

long my_rand()
{
    my_rand_state = (my_rand_state * 1103515245 + 12345) % 2147483648;
    return my_rand_state;
}

You can then use my_srand(), my_rand() and MY_RAND_MAX like you would std::srand(), std::rand() and RAND_MAX respectively:

// Seed it with the current time.
my_srand(std::time(nullptr));

// Print 1000 random numbers between 0 and MY_RAND_MAX.
for (int i = 0; i < 1000; ++i) {
    std::cout << my_rand() << ' ';
}
std::cout << '\n';

This generates low quality random numbers (they have bad distribution.) Note that std::rand() also has bad distribution. If you would like high quality random numbers (meaning good distribution), you should be using the C++ <random> algorithms, using the std::mt19937 engine (which is the Mercene Twister algorithm, which has very good distribution and a huge period.)

In general, just avoid rand(). See Stephan T. Lavavej's 30min talk "rand() Considered Harmful", a must-watch for anyone who still uses rand() in their code.

Автор: Nikos C. Размещён: 09.11.2017 12:52
Вопросы из категории :
32x32