【问题标题】:How can I generate non-repetitive random 4 bytes hex values in Perl?如何在 Perl 中生成非重复的随机 4 字节十六进制值?
【发布时间】:2009-12-15 07:55:51
【问题描述】:

我想生成随机的十六进制值,这些值不应重复 它应该是 4 个字节(即:0x00000000 到 0xffffffff)和显示输出 应包含前导零。

例如:如果我得到值 1,它不应该表示为 0x1,而是 0x00000001。

我想要至少 100 个随机值。请告诉我:我怎样才能在 Perl 中做到这一点?

【问题讨论】:

  • 告诉我们您最麻烦的部分如何?
  • “不重复”是什么意思?
  • 他的意思是相同的值不应该在生成的列表中重复出现。
  • 您想要真正的随机数、随机序列还是只是分布在该范围内的唯一数?有区别。 :)

标签: perl


【解决方案1】:

获取0 .. (2

my $rand = int(rand(0x100000000));

用前导零以十六进制打印:

printf "%08x", $rand;

请在 Perl 手册页中注意这一点:

注意:如果您的 rand 函数始终返回 太大或太小,那么您的 Perl 版本可能是用错误数量的 RANDBITS 编译的

如果这是一个问题,请改为这样做:

printf "%04x%04x", int(rand(0x10000)), int(rand(0x10000));

另外请注意,这并不能防止重复,尽管老实说,在 100 数字序列中重复 32 位数字的机会非常小。

如果绝对不能重复,请执行以下操作:

my (%a);                       # create a hash table for remembering values
foreach (0 .. 99) {
    my $r;
    do {
        $r = int(rand(0x100000000));
    } until (!exists($a{$r})); # loop until the value is not found
    printf "%08x\n", $r;       # print the value
    $a{$r}++;                  # remember that we saw it!
}

无论如何,如果可能值的范围小于(或什至接近)所需值的数量,则不应使用此算法。这是因为随机数生成器循环只会重复提取已经看到的数字。

但是,在这种情况下,可能的范围如此之高 (2^32) 并且所需的值的数量如此之低,它会完美地工作。事实上,在如此高的范围内,它是唯一实用的算法。

【讨论】:

  • 请注意,如果您的随机数生成器损坏并且总是返回一小组数字,这将产生一个无限循环。如果随机数生成器两次返回相同的值(例如将前两个数字相乘),您可能需要考虑获取新随机数的替代方法。请注意,这可能会导致熵降低,但会解决无限循环的问题。
  • @Nathan Fellman:即使在 Windows 上,rand() 也会返回超过 100 个值; “破碎”是什么意思?
【解决方案2】:
perl -e 'printf "%08X\n", int rand 0xFFFFFFFF for 1 .. 100'

【讨论】:

  • 这并不能避免重复值。
【解决方案3】:

Alnitak explained it,但这里有一个更简单的实现。我不确定每个人是如何开始接触do {} while,因为这是一个非常奇怪的选择:

my $max = 0xFFFF_FFFF;

my( %Seen, @numbers );

foreach ( 1 .. 100 )
    {
    my $rand = int rand( $max + 1 );
    redo if $Seen{$rand}++;
    push @numbers, $rand;
    }

print join "\n", map { sprintf "0x%08x", $_ } @numbers;

另外,正如 Alnitak 指出的那样,如果您生成大量数字,redo 可能会循环很多很多次。

这些只是伪随机数,但无论如何你并不是真正要求真正的随机数。这将涉及可能的重复。 :)

【讨论】:

  • do { } while 并不奇怪,如果你不知道 redo :) 它已经存在了多久?
  • 它已经存在了十多年。
  • 哦,好吧,我想我应该偶尔重读一下联机帮助页(甚至是奇怪的 Perl 书籍);-)
  • 如果我们只使用其他语言有的东西,我们就不需要 Perl。
  • 我发现做 { } 虽然比重做更容易阅读。不同的人不同的笔画,我猜。 耸耸肩
【解决方案4】:
use LWP::Simple "get";
use List::MoreUtils "uniq";
print for uniq map { s/\t//, "0x$_" } split /^/, LWP::Simple::get('http://www.random.org/integers/?num=220&min=0&max=65535&col=2&base=16&format=plain&rnd=date.2009-12-14');

调整 url(参见http://www.random.org/integers/?mode=advanced 上的表格)以不总是返回相同的列表。没有返回至少 100 个结果的可能性很小。

请注意,作为对糟糕问题的评论,此答案故意“糟糕”。这不是一个单独的问题,而是一堆都打包在一起的问题,我敢打赌所有这些问题都已经有了答案(如何在 x 范围内生成随机数,如何将数字格式化为 0x 的十六进制字符串和0-padding,如何仅将唯一值添加到列表中,等等)。这就像问“我如何在 Perl 中编写网络服务器?”在不猜测提问者真正想要答案的部分的情况下,您要么必须写一个大部头来回答,要么说如下:

perl -MIO::All -e 'io(":80")->fork->accept->(sub { $_[0] < io(-x $1 ? "./$1 |" : $1) if /^GET \/(.*) / })'

【讨论】:

  • 我在一段时间内看到的最荒谬的答案加分。
  • 请不要提供这样的答案。不是每个人都会立即意识到这是一个玩笑,并且会实际使用它。
  • 极其糟糕的代码是捕捉作业作弊和无意义的小隔间取暖器的好方法。不幸的是,它可能会伤害一个真正的侍从,他们在新面孔的无知中只接受它的表面价值。某种警告很有味道——也许隐藏在一段日文的代码中。
  • 值得注意的是,这是唯一实际返回随机值的答案。但是,是的,不要使用它。我认为让给定的 url 总是返回相同的值对于粗心大意的人来说是一个很好的障碍。
  • 为什么不做@random_numbers = qw( 1 5 2 3 3 6 3 6 2 ); # random numbers determined by fair dice roll. 之类的事情显然,OP 不能只使用 6 面骰子,但他可以掷出 4D8 来获得八进制值。 ;)
【解决方案5】:

获取随机整数:

int(rand(0x10000000))

将其格式化为 8 个十六进制数字:

printf "%08x", int(rand(0x10000000))

【讨论】:

  • 很抱歉 - 我们的答案非常相似,以至于我不小心编辑了错误的答案...
  • 这并不能避免重复值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-07
  • 1970-01-01
  • 1970-01-01
  • 2010-11-06
  • 2016-02-04
  • 2018-11-27
  • 2011-04-02
相关资源
最近更新 更多