HTML page
2.4. Преобразования между двоичной и десятичной системами счисления
Проблема
Имеется десятичное число, которое необходимо вывести в двоичном представлении, или наоборот, двоичная последовательность, которую требуется преобразовать в десятичное число. Такие задачи часто возникают при отображении не-текстовых данных - например, полученных в процессе взаимодействия с некоторыми системными функциями и программами.Решение
Чтобы преобразовать целое число Perl в строку, состоящую из единиц и нулей, сначала упакуйте его в сетевой формат "N" (с начальным старшим байтом), а затем снова распакуйте по одному биту (формат "В32").sub dec2bin {
my $str = unpack("B32", pack("N", shift));
$str =~ s/"0+C7=\d)//; # В противном случае появятся начальные нули
return $str;
}
Чтобы преобразовать строку из единиц и нулей в целое число Perl, допилнип; ее необходимым количеством нулей, а затем выполните описанную выше процедуру в обратном порядке:
sub bin2dec {
return unpack("N", pack("B32", substr("0" x 32 . shift, -32)));
}
Комментарий
Речь идет о преобразовании чисел между строками вида "00100011" и десятичной системой счисления (35). Строка содержит двоичное представление числа. На этот раз функция sprintfue поможет: в ней не предусмотрен формат для вывода чисел в двоичной системе счисления. Следовательно, нам придется прибегнуть к функциям Perl pack и unpack для непосредственных манипуляций со строковыми данными. Функции pack и unpack предназначены для работы со строками. Строки можно интерпретировать как последовательности битов, байты, целые, длинные целые, числа с плавающей запятой в представлении IEEE, контрольные суммы - не говоря уже о многом другом. Обе функции, pack и unpack, по аналогии со spnntf получают форматную строку, которая определяет выполняемые с аргументом операции. Мы используем pack и unpack для интерпретации строк как последовательностей битов и двоичного представления целого числа. Чтобы понять, каким образом строка интерпретируется как последовательность битов, необходимо хорошо разобраться в поведении функции pack. Строка интерпретируется как последо вательность байтов, состоящих из восьми бит. Байты всегда нумеруются слев:1 направо (первые восемь бит образуют первый байт, следующие восемь бит - второй и т. д.), однако внутри каждого байта биты могут нумероваться как слева направо, так и справа налево. Функция pack с шаблоном "В" работает с битами каждого байта, пронумеро ванными слева направо. Именно в этом порядке они должны находиться для при менения формата "N", которым мы воспользуемся для интерпретации последовательности битов как 32-разрядного целого.$num = bin2dec('0110110') # $num = 54
$binstr = dec2bin(54); # $binstr = 110110
2.5. Действия с последовательностями целых чисел
Проблема
Требуется выполнить некоторую операцию со всеми целыми между Х и Y. Подобная задача возникает при работе с непрерывной частью массива или в любой ситуации, когда необходимо обработать все числа' из заданного интервала.Решение
Воспользуйтесь циклом for или . . в сочетании с циклом to reach:foreach ($X .. $Y) {
# $_ принимает все целые значения от Х до Y включительно
}
foreach $i ($X .. $Y) {
# $i принимает все целые значения от Х до Y включительно }
foreach ($i = $X: $i <= $y; $i++) {
# $i принимает все целые значения от X до Y включительно
}
foreach ($1 = $Х; $i <= $y; $i+=7) {
# $i принимает целые значения от Х до Y включительно с шагом 7 }
Комментарий
В первых двух методах используется конструкция $Х. . $Y, которая создает список всех целых чисел между $Х и $Y. Если $Х и $Y расположены далеко друг от друга, это приводит к большим расходам памяти (исправлено в версии 5.005). При организации перебора последовательных целых чисел цикл for из третьего способа расходует память более эффективно. В следующем фрагменте продемонстрированы все три способа. В данном случае мы ограничиваемся выводом сгенерированных чисел:print "Infancy is:";
foreach (0 .. 2) { print "$_ ";
} print "\n";
print "Toddling is: ";
foreach $i (3 .. 4) {
Точнее, все целые числа. Найти все вещественные числа будет нелегко. Не верите - посмотрите у Кантора.
print "$i ";
} print "\n";
print "Childhood is: ":
for ($i = 5; $i <= 12; $i++) { print "$i ";
} print "\n";
Infancy is: 0 1 2
Toddling is: 3 4
Childhood is: 5 6 7 8 9 10 11 12
[> Смотри также -------------------------------
Описание операторов for и foreach в perlsyn(1).
2.6. Работа с числами в римской записи
Проблема
Требуется осуществить преобразование между обычными числами и числами в римской записи. Такая необходимость часто возникает при оформлении сносок и нумерации страниц в предисловиях.Решение
Воспользуйтесь модулем Roman с CPAN:
use Roman;
$roman = roman($arabic); # Преобразование
# в римскую запись $arabic = arabic($roman) if isroman($roman); # Преобразование
# из римской записи
Комментарий
Для преобразования арабских ("обычных") чисел в римские эквиваленты в модуле Roman предусмотрены две функции, Roman и roman. Первая выводит символы в верхнем регистре, а вторая - в нижнем. Модуль работает только с римскими числами от 1 до 3999 включительно. В римской записи пет отрицательных чисел или нуля, а для числа 5000 (с помощью которого представляется 4000) используется символ, не входящий в кодировку ASCII.use Roman;
$roman_fifteen = roman(15); # "xv" print "roman for fifteen is $roman_fifteen\n";
$arabic_fifteen = arabic($roman_fifteen);
print "Converted back, $roman_fifteen is $arabic_fifteen\n";
Roman for fifteen is xv Converted back, xv is 15
> Смотри также -------------------------------
Документация по модулю Roman; рецепт 6.23.
2.7. Генератор случайных чисел
Проблема
Требуется генерировать случайные числа в заданном интервале - например, чтобы выбрать произвольный элемент массива, имитировать бросок кубика в игре или сгенерировать случайный пароль.Решение
Воспользуйтесь функцией Perl rand. $random = int( rand( $y-$x+1 ) ) + $x; o Комментарий Следующий фрагмент генерирует и выводит случайное число в интервале от 25 до 75 включительно:$random = int( rand(51)) + 25;
print "$random\n"; Функция rand возвращает дробное число от 0 (включительно) до заданного аргумента (не включается). Мы вызываем ее с аргументом 51, чтобы случайное число было больше либо равно 0, но никогда не было бы равно 51 и выше. Затем от сгенерированного числа берется целая часть, что дает число от 0 до 50 включительно (функция int превращает 50,9999... в 50). К полученному числу прибавляется 25, что дает в результате число от 25 до 75 включительно. Одно из распространенных применений этой методики - выбор случайного элемента массива:
$elt = $array[ rand @array ];
Также она часто используется для генерации случайного пароля из заданной последовательности символов: @chars = ( "А" .. "z", "а" .. "z", 0 . . 9, qw(% ! 0 $%"&*)): $password = join("", @chars[ map { rand ochars } ( 1 .. 8 ) ]); Мы генерируем восемь случайных индексов @chars с помощью функции тар, извлекаем соответствующие символы в виде среза и объединяем их в случайный пароль. Впрочем, в действительности пароль получается не совсем случайным - безопасность вашей системы зависит от стартового значения (seed) генератора случайных чисел на момент запуска программы. В рецепте 2.8 показано, как "раскрутить" генератор случайных чисел и сделать генерируемые числа более случайными.
> Смотри также
Описание функций int, rand и join Bperlfunc(1). Случайные числа исследуются в рецептах 2.8-2.10, а используются - в рецепте 1.9.
2.8. Раскрутка генератора случайных чисел
Проблема
При каждом запуске программы вы получаете один и тот же набор "случайных" чисел. Требуется "раскрутить" генератор, чтобы Perl каждый раз генерировал разные числа. Это важно практически для любых применений случайных чисел, особенно для игр.Решение
Воспользуйтесь функцией Perl srand:
srand EXPR;
Комментарий
Генерация случайных чисел - непростое дело. Лучшее, на что способен компьютер без специального оборудования, - генерация псевдослучайных чисел, равномерно распределенных в области своих значений. Псевдослучайные числа генерируются по математическим формулам, а это означает, что при одинаковом стартовом значении генератора две программы сгенерируют одни и те же псевдослучайные числа. Функция srand задает новое стартовое значение для генератора псевдослучайных чисел. Если она вызывается с аргументом, то указанное число будет использовано в качестве стартового. При отсутствии аргумента srand использует величину, значение которой трудно предсказать заранее (относится к Perl 5.004 и более поздним версиям; до этого использовалась функция time, значения которой совсем не были случайными). Не вызывайте srand в программе более одного раза. Если вы не вызвали srand сами, Perl версий 5.004 и выше вызывает srand с "хорошим" стартовым значением при первом запуске rand. Предыдущие версии этого не делали, поэтому программы всегда генерировали одну и ту же последовательность чисел. Если вы предпочитаете именно такое поведение, вызывайте srand с конкретным аргументом:srand(
То, что Perl старается выбрать хорошее стартовое значение, еще не гарантирует криптографической безопасности сгенерированных чисел от усердных попыток взлома. Информацию о построении надежных генераторов случайных чисел можно найти в учебниках по криптографии.
> Смотри также --------------------------------
Описание функции srand в perlfunc(1). Примеры ее применения приведены в рецептах 2.7 и 2.9.