ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП |
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы. |
2.9. Повышение фактора случайностиПроблемаТребуется генерировать случайные числа, которые были бы "более случайными", чем выдаваемые генератором 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. Кроме того, он содержит многочисленные вспомогательные функции.Смотри также -------------------------------
2.10. Генерация случайных чисел с неравномерным распределениемПроблемаТребуется генерировать случайные числа в ситуации, когда одни значения появляются с большей вероятностью, чем другие (неравномерное распределение). Допустим, вы отображаете на своей Web-странице случайный баннер и у вас имеется набор весовых коэффициентов, определяющих частоту появления того или иного баннера. А может быть, вы имитируете нормальное распределение (закон распределения Гаусса).РешениеЕсли вам потребовались случайные величины, распределенные по конкретному закону (допустим, по закону Гаусса), загляните в учебник по статистике и найдите в нем нужную функцию или алгоритм. Следующая функция генерирует случайные числа с нормальным распределением, со стандартным отклонением 1 и нулевым математическим ожиданием.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; } Если у вас есть список весовых коэффициентов и значений и вы хотите выбирать элементы списка случайным образом, выполните два последовательных шага. Сначала превратите весовые коэффициенты в вероятностное распределение с помощью приведенной ниже функции weight_to_dist, а затем воспользуйтесь функцией weighted_rand для случайного выбора чисел. # 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 {
КомментарийФункция gaussian_rand реализует полярный метод Бокса-Мюллера для преобразования двух независимых случайных чисел с однородным распределением, лежащих в интервале от 0 до 1 в два числа с математическим ожиданием 0 и стандартным отклонением 1 (то есть распределенных по закону Гаусса). Чтобы сгенерировать числа с другим математическим ожиданием и стандартным отклонением, умножьте выходные данные gaussian_rand на нужное стандартное отклонение и прибавьте математическое ожидание:# 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, и определяет, какому элементу соответствует это случайное число. Из-за погрешностей представления с плавающей запятой накопленные ошибки могут привести к тому, что возвращаемый элемент не будет найден. Поэтому код размещается в цикле while, который в случае неудачи выбирает новое случайное число и делает очередную попытку. >Кроме того, модуль Math::Random с CPAN содержит функции, генерирующие случайные числа для многих распределений. > Смотри также --------------------------------
2.11. Выполнение тригонометрических вычислений в градусахПроблемаТребуется, чтобы в тригонометрических функциях использовались градусы вместо стандартных для 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. Другой выход заключается в определении приведенных выше функций rad2deg и deg2rad. В Peri нет встроенной константы я, однако при необходимости ее можно вычислить настолько точно, насколько позволит ваше оборудование для вычислений с плавающей запятой. В приведенном выше решении л является константой, определяемой командой use constant. Синус угла, заданного в градусах, вычисляется следующим образом: # Функции deg2rad и rad2def приведены выше или взяты из Math::Trig sub degree_sine {my $degrees = shift; my $radians = deg2rad($degrees); my $result= sin($radians); return $result; } > Смотри также ------------------------------
2.12. Тригонометрические функцииПроблемаТребуется вычислить значения различных тригонометрических функций - таких как синус, тангенс или арккосинус.РешениеВ 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:eval { $y = tan($pi/2); } or return undef; > Смотри также -------------------------------
|