mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-04-27 07:48:01 -07:00
RNG: added additional checks (which forced an interface redesign), updated comments
This commit is contained in:
parent
197dd0f3c8
commit
ccab97ca7d
6 changed files with 65 additions and 26 deletions
|
|
@ -17,6 +17,44 @@ RNG_SFMT::RNG_SFMT(QObject *parent)
|
|||
sfmt_init_gen_rand(&sfmt, QDateTime::currentDateTime().toTime_t());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is the rand() equivalent which calls the cdf with proper bounds.
|
||||
*
|
||||
* It is possible to generate random numbers from [-min, +/-max] though the RNG uses
|
||||
* unsigned numbers only, so this wrapper handles some special cases for min and max.
|
||||
*
|
||||
* It is only necessary that the upper bound is larger or equal to the lower bound - with the exception
|
||||
* that someone wants something like rand() % -foo.
|
||||
*/
|
||||
unsigned int RNG_SFMT::rand(int min, int max) {
|
||||
/* If min is negative, it would be possible to calculate
|
||||
* cdf(0, max - min) + min
|
||||
* There has been no use for negative random numbers with rand() though, so it's treated as error.
|
||||
*/
|
||||
if(min < 0) {
|
||||
throw std::invalid_argument(
|
||||
QString("Invalid bounds for RNG: Got min " +
|
||||
QString::number(min) + " < 0!\n").toStdString());
|
||||
// at this point, the method exits. No return value is needed, because
|
||||
// basically the exception itself is returned.
|
||||
}
|
||||
|
||||
// For complete fairness and equal timing, this should be a roll, but let's skip it anyway
|
||||
if(min == max)
|
||||
return max;
|
||||
|
||||
// This is actually not used in Cockatrice:
|
||||
// Someone wants rand() % -foo, so we compute -rand(0, +foo)
|
||||
// This is the only time where min > max is (sort of) legal.
|
||||
// Not handling this will cause the application to crash.
|
||||
if(min == 0 && max < 0) {
|
||||
return -cdf(0, -max);
|
||||
}
|
||||
|
||||
// No special cases are left, except !(min > max) which is caught in the cdf itself.
|
||||
return cdf(min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Much thought went into this, please read this comment before you modify the code.
|
||||
* Let SFMT() be an alias for sfmt_genrand_uint64() aka SFMT's rand() function.
|
||||
|
|
@ -33,7 +71,7 @@ RNG_SFMT::RNG_SFMT(QObject *parent)
|
|||
*
|
||||
* To get out the random variable, solve for X:
|
||||
* floor(X) = SFMT(X; min, max) * (max - min + 1) + min - 1
|
||||
* So this is, what getNumber(min, max) should look like.
|
||||
* So this is, what rand(min, max) should look like.
|
||||
* Problem: SFMT(X; min, max) * (max - min + 1) could produce an integer overflow,
|
||||
* so it is not safe.
|
||||
*
|
||||
|
|
@ -56,19 +94,17 @@ RNG_SFMT::RNG_SFMT(QObject *parent)
|
|||
* then you _need_ to change the UINT64_MAX constant to the largest possible random
|
||||
* number which can be created by the new rand() function. This value is often defined
|
||||
* in a RAND_MAX constant.
|
||||
* Otherwise you will probably skew the outcome of the getNumber() method or worsen the
|
||||
* Otherwise you will probably skew the outcome of the rand() method or worsen the
|
||||
* performance of the application.
|
||||
*/
|
||||
unsigned int RNG_SFMT::getNumber(unsigned int min, unsigned int max)
|
||||
unsigned int RNG_SFMT::cdf(unsigned int min, unsigned int max)
|
||||
{
|
||||
// This all makes no sense if min > max, which should never happen.
|
||||
if(min > max) {
|
||||
throw std::invalid_argument(
|
||||
QString("Invalid bounds for RNG: min > max! Values were: min = " +
|
||||
QString::number(min) + ", max = " +
|
||||
QString::number(max) +
|
||||
". This is either a bug or something even more serious happened."
|
||||
).toStdString());
|
||||
QString::number(max)).toStdString());
|
||||
// at this point, the method exits. No return value is needed, because
|
||||
// basically the exception itself is returned.
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue