Ответ 1
Math:: Random:: Auto - это модуль CPAN, реализующий хорошо известный Mersenne twister PRNG.
Я пишу функцию kid sister encryption, и мне нужен PRNG, который дает согласованные результаты по всем операционным системам (так что нет математики с плавающей запятой, используя оборудования или программного обеспечения на уровне системы). Было бы неплохо, но не обязательно, потому что PRNG имел период дольше, чем 2 30.
В настоящее время я использую 32-битный Xorshift:
#!/usr/bin/perl
use strict;
use warnings;
{
use integer; #use integer math
my $x = 123456789;
my $y = 362436069;
my $w = 88675123;
my $z = 521288629;
sub set_random_seed {
$w = shift;
}
sub random {
my $t = $x ^ ($x << 11);
$x = $y;
$y = $z;
$z = $w;
my $rand = $w = ($w ^ ($w >> 19)) ^ ($t ^ ($t >> 8));
return $rand % 256; #scale it back to a byte at a time
}
}
set_random_seed(5);
print map { random(), "\n" } 1 .. 10;
Но я беспокоюсь, потому что я действительно не понимаю, как это работает. Например, исходный источник не смог установить семя, поэтому я добавил его, но не знаю, выбрал ли я правильную переменную для семени.
Итак, все это сводится к
Math:: Random:: Auto - это модуль CPAN, реализующий хорошо известный Mersenne twister PRNG.
Попробуйте использовать LFSR - Линейный регистр сдвига обратной связи.. T В первой ссылке на внешних ссылках есть все необходимое для создания любого количества бит случайности. Самое приятное в этом состоит в том, что его легко реализовать и может быть выполнено с использованием целочисленной математики.
Я использовал его с успехом в проекте 8051. С perl это будет легко.
Update:
Вот быстрая реализация perl из 8-битного LFSR:
use strict;
use warnings;
use List::Util qw(reduce);
use vars qw($a $b);
print 'Taps: ', set_taps( 8, 7, 2, 1 ), "\n";
print 'Seed: ', seed_lfsr( 1 ), "\n";
print read_lfsr(), "\n" for 1..10;
BEGIN {
my $tap_mask;
my $lfsr = 0;
sub read_lfsr {
$lfsr = ($lfsr >> 1) ^ (-($lfsr & 1) & $tap_mask );
return $lfsr;
}
sub seed_lfsr {
$lfsr = shift || 0;
$lfsr &= 0xFF;
}
sub set_taps {
my @taps = @_;
$tap_mask = reduce { $a + 2**$b } 0, @taps;
$tap_mask >>= 1;
$tap_mask &= 0xFF;
return $tap_mask;
}
}
Этот код является всего лишь прототипом. Если бы я хотел использовать его в процессе производства, я бы, вероятно, обернул его в объект и сделал размер регистра настраиваемым. Тогда мы избавимся от этих досадных общих переменных.