Кроссплатформенность и bc
Как мы все знаем, в мире существует две версии bc — более скромная по возможностям версия GNU, которая используется в Линуксе, и более развитая, которая, например, используется в командной строке МакОСи.
Они довольно серьёзно различаются — когда я писал игру «Виселица» на этом языке, мне пришлось сделать две версии для разных синтаксисов.
В принципе, можно писать кроссплатформенно, если использовать подмножество, которое поддерживают обе версии, но есть одна неприятность — функция получения случайного числа в гну-версии называется random(), а в более продвинутой — rand() (точнее там их целое семейство, но функции random() там нет).
Поскольку в языке нет способа узнать определена функция или нет, нужно каким-то образом отличать одну версию от другой и вызывать, в зависимости от результата, ту или другую функцию.
Каким же образом мы можем это сделать?
Вначале я возлагал надежду на переменную seed. В GNU её нету, то есть она содержит ноль, а в продвинутой версии она содержит инициализирующее значение. Как будто этого вполне достаточно, но, во-первых, никто не обещает, что она по какой-то случайности не получит нулевое значение, а во-вторых, её вполне могут реализовать в версии GNU. Нужно что-то принципиально другое, что в будущем не будет работать иначе, правка или реализация которого сломала бы обратную совместимость.
Такую особенность я нашёл — она заключается в приоритете обработки операции отрицания, которая записывается как восклицательный знак.
Из-за этой разницы две версии по-разному вычисляют конструкцию !1+1. В продвинутой версии порядок выполнения следующий: (!1)+1, что даёт нам единицу, а в гнушной приоритет другой и конструкция выполнится так: !(1+1), что даёт нам ноль.
Основываясь на этом, мы можем написать универсальную функцию для получения случайного числа:
define rnd() {
/* Checking the bc version */
if (!1+1) {
return rand()
} else {
return random() * random()
}
}
P. S. Надо помнить, что в гну-версии функция получения случайного числа сломана, но есть надежда, что скоро её починят и ей можно будет пользоваться.
P. P. S. Я умножаю random() на random(), чтобы хоть немного выровнять по диапазону значений rand() и random(), правда распределение, конечно, изменится.
Перемножение равномерно распределеных случайных чисел сдвигает выборку к нормальному распределению. Не знаю на сколько это важно в Вашей программе, но в общем случае это может быть проблемой.
Так и есть, в телеграме обсудили уже. Я так и не определился пока — проблема это или нет. Наверное стоит убрать перемножение, раз это столько вопросов вызывает.