22 мая 2012 г., 21:06 отAlexey Frunze

Макрос RAND_MAX: подписанный или неподписанный?

Я посмотрел стандарт C (с 1999 года), и это говорит только о том, чтоRAND_MAXначение @ должно быть не менее 32767, но ничего не говорит о том, должен ли этот макрос расширяться до целого числа со знаком или без знака. Единая спецификация UNIX link 1, link 2) и Linux man ссылк) не добавляй ясности.

Один бы подумалRAND_MAX должен бытьsigned int так как это то, чтоrand() возвращается.

Однако я обнаружил, что некоторые компиляторы определяют его как неподписанный:

Древний Turbo C ++ 1.01: #define RAND_MAX 0x7FFFU Не очень древний C ++ Builder 5.5: #define RAND_MAX 0x7FFFU Еще жива Open Watcom C / C ++ 1.9: #define RAND_MAX 32767UDJGPP (gcc 3.3.4 для DOS): #define RAND_MAX 2147483647MinGW (gcc 4.6.2 для Windows): #define RAND_MAX 0x7FFFMS Visual Studio 2010 ссылк):RAND_MAX определяется как значение 0x7fffTiny C Compiler 0.9.25: #define RAND_MAX 0x7FFF lcc-win32 3.8: #define RAND_MAX 0x7fffPelles C 6.50: #define RAND_MAX 0x3fffffffИЛ #define RAND_MAX 0x7fffDigital Mars C / C ++ 8.52: #define RAND_MAX 32767

Это делает на первый взгляд безобидный код, подобный приведенному ниже, непереносимым и взрывается из-за подписанной рекламы без подписи:

cos(w * t) + (rand() - RAND_MAX / 2) * 0.1 / (RAND_MAX / 2);

rand() возвращаетsigned int в диапазоне [0,RAND_MAX].

ЕслиRAND_MAX определяется какunsigned int, значение отrand() получает повышение доunsigned int слишком

А если это так, то разница(rand() - RAND_MAX / 2) становится беззнаковой разностью целых чисел без знака со значением в диапазонах [0,RAND_MAX-RAND_MAX / 2] & UINT_MAX + 1-RAND_MAX / 2,UINT_MAX -1] вместо разницы в знаковых целых числах со значением в диапазоне [-RAND_MAX / 2,RAND_MAX-RAND_MAX / 2].

Похоже,RAND_MAX должен быть подписан, и большинство (?) компиляторов определяют его как таковой, но есть ли авторитетный источник, который говорит, что он должен быть подписан? Старый стандарт? К & R? Еще одна спецификация UNIX?

Ответы на вопрос(2)

24 мая 2012 г., 17:37 отHBB

этот код делает необоснованное предположение, поэтому его необходимо исправить. То, что этот код должен был сделать, приведеноRAND_MAX в(int) при использовании.

Хотя для компиляторов было бы немного больше смысла определять ихRAND_MAX Макросы, как подписано, стандарт тщательно избегает необходимости их делать. Это делает ошибку переносимости для любого кода слепым предположением, что он подписан.

22 мая 2012 г., 18:35 отJens Gustedt

Во-первых, в настоящее время, вероятно, никто не определил быrand() чтобы вернутьint. Намерение явно состоит в том, чтобы вернуть положительное число, и нет возврата ошибки, которая могла бы использовать отрицательные значения. Такая функция, если бы она была представлена сегодня, была бы разработана с целочисленным типом без знака в качестве возвращаемого типа. Я предполагаю, что это предшествует C89 и введению понятия целых чисел без знака в язык.

Тогда, очевидно, следует ожидать, что определение максимального значения, которое возвращает функция, имеет тот же тип, что и определение функции. В других местах макросы хорошо определены как расширения до выражений с определенным типом, поэтому это было бы возможно и здесь.

Что касается вашей проблемы, я думаю, что проще всего иметь что-то переносимое, это сначала масштабировать значение до двойного в[0, 1) делая что-то вродеrand()/(RAND_MAX+1.0) и получить все ваши вычисления оттуда. В любом случае вы должны использоватьrand() только в крайнем случае, если на вашей платформе нет лучшего генератора псевдослучайных данных. Например, в системах POSIXrand48 family - это удобная замена с хорошо описанными свойствами.

ВАШ ОТВЕТ НА ВОПРОС