Требуется генерировать случайные числа, которые были бы "более случайными", чем выдаваемые генератором Peri. Иногда возникают проблемы, связанные с ограниченным выбором стартовых значений в библиотеках С. В некоторых приложениях последовательность псевдос
Решение
Воспользуйтесь другими генераторами случайных чисел - например, теми, которые присутствуют в модулях Math::Random и Math::TrulyRandom с CPAN:
use Math::TrulyRandom;
$random = truly_random_value();
use Math_Random;
$random = random_uniforni();
Комментарий
Для генерации случайных чисел в Peri используется стандартная библиотечная функция С rand(3) (впрочем, на стадии компоновки это можно изменить). Некоторые реализации функции rand возвращают только 16-разрядные случайные числа или используют слабые алгорит
Модуль Math::TrulyRandom генерирует случайные числа, используя погрешности системного таймера. Процесс занимает некоторое время, поэтому им не стоит пользоваться для генерации большого количества случайных чисел.
Модуль Math::Random генерирует случайные числа с помощью библиотеки randlib. Кроме того, он содержит многочисленные вспомогательные функции.
Смотри также -------------------------------
Описание функций srand и rand в perlfunc(1); рецепты 2.7-2.8; документация по модулям Math::Random и Math::TrulyRandom с CPAN.
Требуется генерировать случайные числа в ситуации, когда одни значения появляются с большей вероятностью, чем другие (неравномерное распределение). Допустим, вы отображаете на своей Web-странице случайный баннер и у вас имеется набор весовых коэффициентов
иного баннера. А может быть, вы имитируете нормальное распределение (закон распределения Гаусса).
Решение
Если вам потребовались случайные величины, распределенные по конкретному закону (допустим, по закону Гаусса), загляните в учебник по статистике и найдите в нем нужную функцию или алгоритм. Следующая функция генерирует случайные числа с нормальным распреде
sub gaussian_rand {
my ($u1, $u2); # Случайные числа с однородным распределением
my $w; #Отклонение, затем весовой коэффициент
my ($g1, $д2); # Числа с гауссовским распределением
do {
$u1 = 2 * rand() - 1;
$u2 = 2 * rand() - 1;
$w = $u1*$u1 + $u2*u2 } while ($w >= 1);
$w = sqrt( (-2 * log($w)) / $w);
$g2 = $u1 * $w;
$.g1 = $u2 * $w;
# Возвратить оба числа или только одно return wantarray ? ($g1, $g2) : $g1;
}
Если у вас есть список весовых коэффициентов и значений и вы хотите выбирать элементы списка случайным образом, выполните два последовательных шага. Сначала превратите весовые коэффициенты в вероятностное распределение с помощью приведенной ниже функции w
# weight_to_dist: получает хэш весовых коэффициентов
# и возвращает хэш вероятностей
sub weight_to_dist {
my %weights = @_;
my %dist =();
my $total = 0;
my ($key, $weight);
local $_;
foreach (values %weights) { $total += $ ;
while ( ($key, $weight) = each %weights ) { $dist{$key} = $weight/$total;
}
return %dist;
}
# weighted_ran: получает хэш вероятностей
# и возвращает случайный элемент хэша
sub weighted_rand {
my %dist = @_;
my ($key, $wp1rihn'
while (1) { # Чтобы избежать погрешностей вычислений
# с плавающей запятой (см. ниже). my $rand = rand;
while ( ($key, $weight) = each %dist ) { return $key if ($rand -= $weight) <0;
}
}
}
Комментарий
Функция gaussian_rand реализует полярный метод Бокса-Мюллера для преобразования двух независимых случайных чисел с однородным распределением, лежащих в интервале от 0 до 1 в два числа с математическим ожиданием 0 и стандартным отклонением 1 (то есть распр
# gaussian_rand - см. выше $mean = 25;
$sdev = 2;
$salary - gaussian_rand() * $sdev + $mean;
printf("You have been hired at \$%.2f\n", $salary);
Функция weighted_rand получает случайное число из интервала от 0 до 1. Затем она использует вероятности, сгенерированные weight_to_dist, и определяет, какому элементу соответствует это случайное число. Из-за погрешностей представления с плавающей запятой
>Кроме того, модуль Math::Random с CPAN содержит функции, генерирующие случайные числа для многих распределений.
> Смотри также --------------------------------
Описание функции rand в perlfunc(1); рецепт 2.7; документация по модулю Math::Random с CPAN.
Требуется, чтобы в тригонометрических функциях использовались градусы вместо стандартных для Peri радианов.
Решение
Создайте функции для преобразований между градусами и радианами (2л радиан соответствуют 360 градусам).
BEGIN {
use constant PI => 3.14159265358979;
sub deg2rad {
my $degrees = shift;
return ($degrees / 180) * PI;
}
sub rad2deg {
my $radians = shift;
return ($radians / PI) * 180;
}
}
Также можно воспользоваться модулем Math::Trig:
use Math::Trig;
$raaians = deg2raa(,iioegreesJ;
$degrees = rad2deg($radians);
Комментарий
Если вам приходится выполнять большое количество тригонометрических вычислений, подумайте об использовании стандартных модулей Math::Trig или POSIX. В них присутствуют дополнительные тригонометрические функции, которых нет в стандартном Peri. Другой выход
# Функции deg2rad и rad2def приведены выше или взяты из Math::Trig sub degree_sine {
my $degrees = shift;
my $radians = deg2rad($degrees);
my $result= sin($radians);
return $result;
}
> Смотри также ------------------------------
Описание функций sin, cos и atan2 в perlfunc(1); стандартная документация по модулям POSIX и Math::Trig.
Требуется вычислить значения различных тригонометрических функций - таких как синус, тангенс или арккосинус.
Решение
В Peri существуют лишь стандартные тригонометрические функции sin, cos и atan2. С их помощью можно вычислить тангенс (tan) и другие тригонометрические функции:
sub tan {
my $theta = shift;
return sin($theta)/cos($theta^:
}
В модуле POSIX представлен расширенный набор тригонометрических функций:
use POSIX;
$у = acos(3.7); Модуль Math::Trig содержит полный набор тригонометрических функций, а также позволяет выполнять операции с комплексными аргументами (или дающие комплексный результат):
use Math::Trig;
$у = acos(3.7):
Комментарий
Если значение $theta равно я/2, Зл/2 и т. д., в функции tan возникает исключительная ситуация деления на ноль, поскольку для этих углов косинус равен нулю. Аналогичные ошибки возникают и во многих функциях модуля Math::Trig. Чтобы перехватить их, воспольз
eval {
$y = tan($pi/2);
} or return undef;
> Смотри также -------------------------------
Описание функций sin, cos и atan2 в perlfunc(i). Тригонометрия в контексте комплексных чисел рассматривается в рецепте 2.15, а использование eval для перехвата исключений - в рецепте 10.12.