ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП |
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы. |
2.13. Вычисление логарифмовПроблемаТребуется вычислить логарифм по различным основаниям.РешениеДля натуральных логарифмов (по основанию е) существует встроенная функция log:$log_e = log(VALUE); Чтобы вычислить логарифм по основанию 10, воспользуйтесь функцией log 10 модуля POSIX: use POSIX qw(log-IO); $log_10 = log10(VALUE); Для других оснований следует использовать соотношение: loge(x) = loge(x)/loge(n) где х - число, логарифм которого вычисляется, n - нужное основание, а е - основание натуральных логарифмов. sub log_base { my ($base, $value) = @_; return log($value)/log($base): } КомментарийФункция log_base позволяет вычислять логарифмы по любому основанию. Если основание заранее известно, намного эффективнее вычислить его натуральный логарифм заранее и сохранить для последующего использования, вместо того чтобы каждый раз пересчитывать его заново. Я Определение log_base см. выше$answer = log_base(10, 10, 10_000); print "log10(10,100) = $answer\n"; log10(10,000) = 4 В модуле Math::Complex для вычисления логарифмов по произвольному основанию существует функция 1одп(), поэтому вы можете написать: use Math;:Complex; printf "lоg2(1024) = %lf\n", 1оgn(1024, 2); # Обратите внимание # на порядок аргументов! 1оg2(1024) = 10,000000 хотя комплексные числа в вычислениях не используются. Функция не очень эффективна, однако в будущем планируется переписать Math::Complex на С для повышения быстроты. > Смотри также -------------------------------
2.14. Умножение матрицПроблемаТребуется перемножить два двумерных массива. Умножение матриц часто используется в математических и инженерных вычислениях.РешениеВоспользуйтесь модулями PDL с CPAN. Модули PDL (Peri Data Language, то есть "язык данных Peri") содержат быстрые и компактные матричные и математические функции:use PDL; # $а и $b - объекты pdl $с = $а * $Ь; Альтернативный вариант - самостоятельно реализовать алгоритм умножения матриц для двумерных массивов: sub mmult { my ($m1,$m2) = @>_; my ($m1rows,$m1cols) = matdim($m1); my ($m2rows,$m2cols) = matdim($m2); unless ($m1cols == $m2rows) { # Инициировать исключение die "IndexError: matrices don't match: $m1cols != $m2rows"; } my $result = []; my ($i, $j, $k); for $i (range($m1rows)) { for $j (range($m2cols)) { for $k (range($m1cols)) { $result->[$i][$j] += $m1->[$i][$k] * $m2->[$k][$j]; } } } return $result; } sub range {0 .. ($_[0] - 1 } sub veclen { o my $ary_ref = $_[0]; my type = ref $ary_ref; if ($type ne "ARRAY") {die "$type is bad array ref for $ary_ref return scalar(@$ary_ref); } sub matdim { my $matrix = $_[0], my o$rows = veclen($matrix); my $cols = veclen($matrix->[0]); return ($rows, $cols): } КомментарийЕсли у вас установлена библиотека PDL, вы можете воспользоваться ее молниеносными числовыми операциями. Они требуют значительно меньше памяти и ресурсов процессора, чем стандартные операции с массивами Peri. При использовании объектов PDL многие числовые операторы (например, + и *) перегружаются и работают с конкретными типами операндов (например, оператор * выполняет так называемое скалярное умножение). Для умножения матриц используется перегруженный оператор х.use PDL; $а = pdl [ [ 3, 2, 3 ], [ 5, 9, 8 ], ]; $b = pdl [ [ 4, 7 ], [ 9, 3 ], [ 8, 1 ], } $c = $a x $b; # Перегруженный оператор х Если библиотека PDL недоступна или вы не хотите привлекать ее для столь тривиальной задачи, матрицы всегда можно перемножить вручную: и mmultO и другие процедуры определены выше $х = [ [ 3, 2, 3 ], [ 5, 9, 8 ], ]; $У = L [ 4, 7 ], [ 9, 3 ], [ 8, 1 ], ]; $z = mult($x, $y): > Смотри также ------------
2.15. Операции с комплексными числамиПроблемаВаша программа должна работать с комплексными числами, часто используемыми в инженерных, научных и математических расчетах.РешениеЛибо самостоятельно организуйте хранение вещественной и мнимой составляющих комплексного числа, либо воспользуйтесь классом Math::Complex (из стандартной поставки Peri). Ручное умножение комплексных чисел# $с = $а * $b - моделирование операции $с_геа1 = ( $а_геа1 " $b_real ) - ($a_imaglnary * $b_imaginary ); $c_imaginary = ( $а_геа1 * $b_lmaginary ) - ($b_real * $a_imaginary ); Math::Complex # Умножение комплексных чисел с помощью Math::Complex use Math::Complex; $с = $а * $b; КомментарийРучное умножение комплексных числа 3+5i и 2-2i выполняется следующим образом:$а_геа1 = 3; $a_imaginary =5; # 3 + 5i; $b_real = 2; $b_lmaginary = -2; # 2 - 2i; $c_real = ($a_real * $b_real ) - ( $a_imaginary * $b_imaginary ); $c_imaginary = ($a_real * $b_imaginary ) - ( $b_real * $a_imaginary ); print "с = ${c_real}+${c_imaginary}i\n"; с = 16+41 То же с применением модуля Math::Complex: use Math::Complex;
О Смотри также --------------------------------
2.16. Преобразования восьмеричных и шестнадцатеричных чиселПроблемаТребуется преобразовать строку с восьмеричным или шестнадцатеричным представлением (например, "0х55" или "0755") в правильное число. Peri воспринимает лишь те восьмеричные и шестнадцатеричные числа, которые встречаются в программе в виде литералов. Если числа были получены при чтении из файла или переданы в качестве аргументов командной строки, автоматическое преобразование не выполняется.РешениеВоспользуйтесь функциями Peri oct и hex:$number = hex($hexadecimal); # Шестнадцатеричное число
КомментарийФункция oct преобразует восьмеричные числа как с начальными нулями, так и без них ("0350" и "350"). Более того, она даже преобразует шестнадцатеричные числа, если у них имеется префикс "Ох". Функция hex преобразует только шестнадцатеричные числа с префиксом "Ох" или без него - например, "0х255", "ЗА", "ff" или "deadbeef" (допускаются символы верхнего и нижнего регистров). Следующий пример получает число в десятичной, восьмеричной или шестна-дцатеричной системе счисления и выводит его во всех трех системах счисления. Для преобразования из восьмеричной системы используется функция oct. Если введенное число начинается с 0, применяется функция hex. Затем функция printf при выводе преобразует число в десятичную, восьмеричную и шестнадцатерич-ную систему:print "Gimme a number in decimal, octal, or hex: ";
Следующий фрагмент преобразует режимы доступа к файлам UNIX. Режим всегда задается в восьмеричном виде, поэтому вместо hex используется функция oct: print "Enter file permission in octal: ";
> Смотри также -------------------------------
2.17. Вывод запятых в числахПроблемаПри выводе числа требуется вывести запятые после соответствующих разрядов. Длинные числа так воспринимаются намного лучше, особенно в отчетах.РешениеОбратите строку, чтобы перебирать символы в обратном порядке, - это позволит избежать подстановок в дробной части числа. Затем воспользуйтесь регулярным выражением, найдите позиции для запятых и вставьте их с помощью подстановки. Наконец, верните строку к исходному порядку символов.sub commify { my $text = reverse $_[0]; $text =~ s/(\d\d\d)(?=\d)(^!\d*\.)/$1./g: return scalar reverse $text; } КомментарийРегулярные выражения намного удобнее использовать в прямом, а не в обратном направлении. Учитывая этот факт, мы меняем порядок символов в строке н;> противоположный и вносим небольшие изменения в алгоритм, который многократно вставляет запятые через каждые три символа от конца. Когда все вставки будут выполнены, порядок символов снова меняется, а строка возвращается из функции. Поскольку функция reverse учитывает косвенный контекст возврата, мы принудительно переводим ее в скалярный контекст. Функцию нетрудно модифицировать так, чтобы вместо запятых разряды разделялись точками, как принято в некоторых странах. Пример использования функции commify выглядит так: и Достоверный счетчик обращений :-)use Math::TrulyRandom;
> Смотри также -------------------------------
2.18. Правильный вывод во множественном числеПроблемаТребуется вывести фразу типа: "It took $time hours" ("Это заняло $time часов"). Однако фраза "It took I hours" ("Это заняло 1 часов") не соответствует правилам грамматики. Необходимо исправить ситуацию'.РешениеВоспользуйтесь printf и тернарным оператором X?Y:Z, чтобы изменить глагол или существительное. К сожалению, для русского языка этот рецепт не подойдет, поскольку множественное число в нем образуется по более сложным правилам с большим количеством исключений. - Примеч. перев.printf "It took %d hour%s\n", $time, $time == 1 9 "" : "s";
Кроме того, можно воспользоваться модулем Lingua::EN::Inflect с CPAN, упоминаемым в комментарии. КомментарийНевразумительные сообщения вроде "1 file(s) updated" встречаются только из-за того, что автору программы лень проверить, равен ли счетчик 1. Если образование множественного числа не сводится к простому добавлению суффикса s, измените функцию printf соответствующим образом:printf "It took %d centur%s", $time, $time == 1 ? "у" : "ies"; В простых ситуациях такой вариант подходит, однако вам быстро надоест писать его снова и снова. Возникает желание написать для него специальную функцию: sub noun_plural {
Однако со временем будут находиться новые исключения и функция будет
становиться все сложнее и сложнее. Если у вас возникнет потребность в подобных
морфологических изменениях, воспользуйтесь универсальным решением, которое
предлагает модуль Lmgua:EN::Inflect от CPAN.
# И еще один вариант
Мы рассмотрели лишь одну из многих возможностей модуля. Кроме того, он обрабатывает склонения и спряжения для других частей речи, содержит функции сравнения без учета регистра, выбирает между использованием а и an и делает многое другое. > Смотри также -------------------------------
|