№ 9. Вычисления произвольной точности с вещественными числами
В сценариях часто используется синтаксическая конструкция $(()), позволяющая выполнять вычисления с использованием простейших математических функций. Эта конструкция может очень пригодиться для упрощения таких распространенных операций, как увеличение на единицу переменных-счетчиков. Она поддерживает операции сложения, вычитания, деления, деления по модулю (остаток от деления нацело) и умножения, но только с целыми числами. Другими словами, следующая команда вернет 0, а не 0,5:
echo $((1 / 2))
То есть вычисления с большей точностью превращаются в проблему. Существует не так много хороших программ-калькуляторов, работающих в командной строке. Одна из них — замечательная программа bc, которой владеют очень немногие пользователи Unix. Позиционирующая себя как калькулятор для вычислений с произвольной точностью, bc появилась на заре развития Unix, славится малопонятными сообщениями об ошибках и отсутствием подсказок. Предполагается, что пользователь и так знает, что делает. Но в этом есть свои плюсы. Мы можем написать сценарий-обертку, делающий программу bc более дружественной, как показано в листинге 1.20.
Листинг 1.20.Сценарий scriptbc
··#!/bin/bash
··# scriptbc — обертка для 'bc’, возвращающая результат вычислений
··if ["$1" = "-p"]; then
····precision=$2
····shift 2
··else
····precision=2 # По умолчанию
··fi
··bc −q — l << EOF
····scale=$precision
····$*
··quit
EOF
exit 0
Синтаксис << в строке
позволяет включить в сценарий произвольное содержимое и интерпретировать его как текст, введенный непосредственно в поток ввода, что в данном случае дает простой способ передачи команд программе bc. Такие вставки называют встроенными документами ( here document ). Вслед за парой символов << помещается текстовая метка, которая будет интерпретироваться как признак конца такого потока ввода (при условии, что она находится в отдельной строке). В листинге 1.20 используется метка EOF.
Этот сценарий демонстрирует также, как использовать аргументы для увеличения гибкости команд. В данном случае сценарий можно вызвать с флагом −p
и указать желаемую точность чисел для вывода. Если точность не указана, по умолчанию используется точность scale=2
.
Работая с программой bc, важно понимать разницу между ее параметрами length (длина) и scale (точность). В терминологии bc под длиной (length) понимается общее количество цифр в числе, а под точностью (scale) — количество цифр после десятичной точки. То есть число 10,25 имеет длину 4 и точность 2, а число 3,14159 имеет длину 6 и точность 5.
По умолчанию bc имеет переменное значение для length, но, так как параметр scale по умолчанию получает нулевое значение, без параметров программа bc действует подобно синтаксической конструкции $(()). К счастью, если в вызов bc добавить параметр scale, она продемонстрирует огромную скрытую мощь, как показано в следующем примере, где вычисляется количество недель между 1962 и 2002 годами (исключая високосные дни):
$ bc
bc 1.06.95
Copyright 1991–1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation,
Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type 'warranty’.
scale=10
(2002–1962)*365
14600
14600/7
2085.7142857142
quit
Чтобы получить доступ к возможностям bc из командной строки, сценарий-обертка должен удалить начальную информацию об авторских правах, если она имеется, однако большинство реализаций bc автоматически подавляют вывод начального баннера, если вводом является не терминал (stdin). Кроме того, сценарий-обертка определяет довольно разумное значение для масштаба (scale), передает программе bc фактическое выражение и затем завершает ее командой quit.
Чтобы запустить сценарий, передайте математическое выражение программе в виде аргумента, как показано в листинге 1.21.
Листинг 1.21.Тестирование сценария scriptbc
$ scriptbc 14600/7
2085.71
Читать дальше