Я искал стандарт C (с 1999 года), и он говорит только, что RAND_MAX
должен быть не менее 32767, но ничего не говорит о том, должен ли этот макрос расширяться до подписанного или беззнакового int. Спецификация Single UNIX ( ссылка 1 , ссылка 2 ) и Linux man ( ссылка ) не добавляют ясности.
Казалось бы, RAND_MAX
должен быть signed int
так как это возвращает rand()
.
Тем не менее, я обнаружил, что некоторые компиляторы определяют его как unsigned:
Это делает, казалось бы, безобидный код, такой как ниже, стать не переносным и взорваться из-за подписания без подписи:
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?
Ответ: этот код делает необоснованное предположение, поэтому его необходимо устранить. То, что должен был сделать этот код, – это RAND_MAX
к (int)
при использовании.
Хотя для компиляторов было бы RAND_MAX
определить их macros RAND_MAX
как подписанные, стандарт тщательно избегает их требовать. Это делает его ошибкой переносимости для любого кода, чтобы слепо предположить, что он будет подписан.
Да, это похоже на дефект в стандарте.
Во-первых, в настоящее время, вероятно, никто не будет определять rand()
чтобы вернуть int
. objective состоит в том, чтобы вернуть положительное число, и нет возврата ошибки, который мог бы использовать отрицательные результаты. Такая функция, если она была введена сегодня, должна быть сконструирована с целым типом без знака в качестве типа возврата. Я предполагаю, что это предшествовало C89 и введение концепции целых чисел без знака в язык.
Тогда, очевидно, следует ожидать, что определение максимального значения, которое возвращает функция, имеет тот же тип, что и функция. В других местах macros хорошо определены как расширяющиеся к выражениям определенного типа, поэтому это было бы возможно и здесь.
Что касается вашей проблемы, я думаю, что проще всего иметь что-то портативное – сначала масштабировать значение до double в [0, 1)
, выполняя что-то вроде rand()/(RAND_MAX+1.0)
и выводить из него все ваши вычисления. В любом случае вы должны использовать rand()
только в крайнем случае, если ваша платформа не имеет лучшего псевдослучайного генератора. Например, в системах POSIX семейство rand48
является удобной заменой хорошо описанных свойств.