Книга: Искусство программирования на языке сценариев командной оболочки
Пример 12-35. Вычисление числа "пи"
Пример 12-35. Вычисление числа "пи"
#!/bin/bash
# cannon.sh: Аппроксимация числа "пи".
# Это очень простой вариант реализации метода "Monte Carlo",
#+ математическое моделирование событий реальной жизни,
#+ для эмуляции случайного события используются псевдослучайные числа.
# Допустим, что мы располагаем картой квадратного участка поверхности со стороной квадрата 10000 единиц.
# На этом участке, в центре, находится совершенно круглое озеро,
#+ с диаметром в 10000 единиц.
# Т.е. озеро покрывает почти всю карту, кроме ее углов.
# (Фактически -- это квадрат со вписанным кругом.)
#
# Пусть по этому участку ведется стрельба железными ядрами из древней пушки
# Все ядра падают где-то в пределах данного участка,
#+ т.е. либо в озеро, либо на сушу, по углам участка.
# Поскольку озеро покрывает большую часть участка,
#+ то большинство ядер будет падать в воду.
# Незначительная часть ядер будет падать на твердую почву.
#
# Если произвести достаточно большое число неприцельных выстрелов по данному участку,
#+ то отношение попаданий в воду к общему числу выстрелов будет примерно равно
#+ значению PI/4.
#
# По той простой причине, что стрельба фактически ведется только
#+ по правому верхнему квадранту карты.
# (Предыдущее описание было несколько упрощено.)
#
# Теоретически, чем больше будет произведено выстрелов, тем точнее будет результат.
# Однако, сценарий на языке командной оболочки, в отличие от других языков программирования,
#+ в которых доступны операции с плавающей запятой, имеет некоторые ограничения.
# К сожалению, это делает вычисления менее точными.
DIMENSION=10000 # Длина стороны квадратного участка поверхности.
# Он же -- верхний предел для генератора случайных чисел.
MAXSHOTS=1000 # Количество выстрелов.
# 10000 выстрелов (или больше) даст лучший результат,
# но потребует значительного количества времени.
PMULTIPLIER=4.0 # Масштабирующий коэффициент.
get_random ()
{
SEED=$(head -1 /dev/urandom | od -N 1 | awk '{ print $2 }')
RANDOM=$SEED # Из примера "seeding-random.sh"
let "rnum = $RANDOM % $DIMENSION" # Число не более чем 10000.
echo $rnum
}
distance= # Объявление глобальной переменной.
hypotenuse () # Расчет гипотенузы прямоугольного треугольника.
{ # Из примера "alt-bc.sh".
distance=$(bc -l << EOF
scale = 0
sqrt ( $1 * $1 + $2 * $2 )
EOF
)
# Установка "scale" в ноль приводит к округлению результата "вниз",
#+ это и есть то самое ограничение, накладываемое командной оболочкой.
# Что, к сожалению, снижает точность аппроксимации.
}
# main() {
# Инициализация переменных.
shots=0
splashes=0
thuds=0
Pi=0
while [ "$shots" -lt "$MAXSHOTS" ] # Главный цикл.
do
xCoord=$(get_random) # Получить случайные координаты X и Y.
yCoord=$(get_random)
hypotenuse $xCoord $yCoord # Гипотенуза = расстоянию.
((shots++))
printf "#%4d " $shots
printf "Xc = %4d " $xCoord
printf "Yc = %4d " $yCoord
printf "Distance = %5d " $distance # Растояние от
#+ центра озера,
#+ с координатами (0,0).
if [ "$distance" -le "$DIMENSION" ]
then
echo -n "ШЛЕП! " # попадание в озеро
((splashes++))
else
echo -n "БУХ! " # попадание на твердую почву
((thuds++))
fi
Pi=$(echo "scale=9; $PMULTIPLIER*$splashes/$shots" | bc)
# Умножение на коэффициент 4.0.
echo -n "PI ~ $Pi"
echo
done
echo
echo "После $shots выстрела, примерное значение числа "пи" равно $Pi."
# Имеет тенденцию к завышению...
# Вероятно из-за ошибок округления и несовершенства генератора случайных чисел.
echo
# }
exit 0
# Самое время задуматься над тем, является ли сценарий удобным средством
#+ для выполнения большого количества столь сложных вычислений.
#
# Тем не менее, этот пример может расцениваться как
# 1) Доказательство возможностей языка командной оболочки.
# 2) Прототип для "обкатки" алгоритма перед тем как перенести
#+ его на высокоуровневые языки программирования компилирующего типа.
dc
Утилита dc(desk calculator) -- это калькулятор, использующий "Обратную Польскую Нотацию", и ориентированный на работу со стеком.
Многие стараются избегать испоьзования dc, из-за непривычной формы записи операндов и операций. Однако, dc имеет и своих сторонников.
- Пример 12-32. Ежемесячные выплаты по займу
- Пример 12-33. Перевод чисел из одной системы счисления в другую
- Пример 12-34. Пример взаимодействия bc со "встроенным документом"
- Пример 12-35. Вычисление числа "пи"
- Пример 12-36. Преобразование чисел из десятичной в шестнадцатиричную систему счисления
- Пример 12-37. Разложение числа на простые множители
- Пример 12-38. Расчет гипотенузы прямоугольного треугольника
- Пример 12-34. Пример взаимодействия bc со "встроенным документом"
- Пример установочного скрипта
- Пример из практики
- Восстановление "безнадежных" баз данных. InterBase Surgeon
- Основные "рычаги" управления производительностью
- ПРИМЕР ПРОСТОЙ ПРОГРАММЫ НА ЯЗЫКЕ СИ
- Примеры получения статистики
- Пример применения метода «пять почему»
- Пример 12-8. Частота встречаемости отдельных слов
- 1.2.5. Пример программы
- Числа с плавающей точкой
- 6. Совершенные числа