Это действительно может привести к целочисленному переполнению, если (max - min + 1) * RAND_MAX > INT_MAX
.У вас есть несколько способов избежать этого:
- приведите промежуточные значения к типу, который может хранить их без переполнения, например
uint64_t
или double
, или - используйте вместо этого оператор модуля
%
, например:
int rng ( int min, int max ) {
return min + rand() % (max - min + 1);
}
Обратите внимание, что использование %
имеет несколько недостатков: если max - min + 1
не является степенью двойки, он будетслегка сместить результаты в сторону нижнего предела диапазона (потому что он не разделит RAND_MAX+1
равномерно);и если оно равно степени двух, это может уменьшить период и качество потока случайных чисел (поскольку младшие биты LCRNG менее случайны, чем старшие биты).
Существуют способы избежать этих проблем путем тщательного кодирования.Для примера посмотрите стандартную реализацию Random.nextInt()
в Java, которая может быть довольно просто переведена на C:
int rng (int min, int max) {
int n = max - min + 1;
int bits, val;
if ((n & -n) == n) // i.e., n is a power of 2
return min + (int)((n * (uint64_t)rand()) / ((uint64_t)RAND_MAX + 1));
do {
bits = rand();
val = bits % n;
} while(bits - val > RAND_MAX - (n-1));
return min + val;
}
(я думаю этот перевод долженработать как задумано. Это оказалось немного хитрее, чем я, хотя, поскольку исходный код Java опирается, в сущности, на допущение, что INT_MAX = RAND_MAX = (1<<31)-1
, что может не выполняться в C.)