Perl 计算二进制文件中设置位数的最快方法是什么
我想知道在Perl中计算二进制文件中设置位数(1)的最快方法是什么 我需要加快速度,因为我正在读取10个文件,每个文件大约有5000万位 我现在这样做太慢了,而且运行10-15个文件需要几个小时 我现在就是这样做的(我知道这很慢,效率很低,但在过去,文件要小得多,这种方法已经足够好了):Perl 计算二进制文件中设置位数的最快方法是什么,perl,Perl,我想知道在Perl中计算二进制文件中设置位数(1)的最快方法是什么 我需要加快速度,因为我正在读取10个文件,每个文件大约有5000万位 我现在这样做太慢了,而且运行10-15个文件需要几个小时 我现在就是这样做的(我知道这很慢,效率很低,但在过去,文件要小得多,这种方法已经足够好了): 您可以执行循环,使字节一直向右移动(使用>运算符),并检查是否设置了最低位 大概是这样的: do { $counter++ if $bin_vec & 1; $bin_vec >>
您可以执行循环,使字节一直向右移动(使用
>
运算符),并检查是否设置了最低位
大概是这样的:
do {
$counter++ if $bin_vec & 1;
$bin_vec >> 1;
} while ($bin_vec > 0);
我可以想到两种方法: 1) 使用解包,因为你已经在做,但不要浪费周期做任何IO。 2) 使用具有给定字节中多少位的预计算值的查找表 1) 这里的诀窍是解包的“%”指令,它告诉解包对结果执行校验和,在二进制数据的情况下,它对所有0和1求和
use strict;
use warnings;
my $filename = $ARGV[0];
open(my $fh, '<', $filename) or die "$!";
binmode $fh;
my $count = 0;
my $word = 0;
while ( read $fh, $word, 4 ) {
$count += unpack '%32B*', $word;
}
print "filename contains $count set bits\n";
__END__
7733485
使用严格;
使用警告;
我的$filename=$ARGV[0];
open(我的$fh,'我太好奇了:你需要这些信息做什么?这是一种家庭作业吗?毕竟,我想不出一个更慢的版本来实现这一点:-pYou可以预计算一个哈希,其中包含从字节值(十进制)到设置位数的映射。(例如,5=>3)然后你读到的每个字节只需要执行一个表格查找。不,这不是家庭作业。我知道这是最慢的版本,但在过去,这些文件是20K-30K。所以我没有浪费时间搜索更快的文件:P。现在我需要它。这是否意味着这是一个秘密?我也非常好奇。^看起来像苏ch基本任务“数一数”然而,我无法想象在什么情况下我会需要它,除了一个或两个字节,人们会计算某种标志,但出于某种原因,不关心设置了哪些标志,只是数字……代码中有一个count1
打字错误。还有,为什么要用0
初始化$word
/$byte
速度?谢谢,我在同一个文件中编写了两个解决方案,使用了不同的计数器,忘记了更新那一个。我在这里测试了它们,结果是:--time./binary\u count\u 1.pl dummy\u 85Mbit.bin--Det count 8408334--1.112u 0.004s0:01.11 100.0%0+0k0+0io 0pf+0w--time./binary\u count\u 2.pl dummy\u 85Mbit.bin--Det count 8408334--3.104u 0。008s 0:03.11 99.6%0+0k 0+0io 0pf+0w——这意味着第一个版本更快。是的,可能是因为它一次读取4个字节,而不是1个。您可以将第二个版本修改为一次读取4个字节,然后将每个字节分别传递到查找表,它应该会加快很多可能优化的第二个版本:my$count=0;而(sysread$fh,my$buf,64*1024){$count+=$bitcounts[$\]对于解包'C*',$buf;}
有一个比这个更有效的方法。
use strict;
use warnings;
my $filename = $ARGV[0];
open(my $fh, '<', $filename) or die "$!";
binmode $fh;
my $count = 0;
my $word = 0;
while ( read $fh, $word, 4 ) {
$count += unpack '%32B*', $word;
}
print "filename contains $count set bits\n";
__END__
7733485
use strict;
use warnings;
my $filename = $ARGV[0];
open(my $fh, '<', $filename) or die "$!";
binmode $fh;
my @bitcounts = (
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3,
3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4,
3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2,
2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5,
3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5,
5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3,
2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4,
4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4,
4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6,
5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5,
5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
);
my $count = 0;
my $byte = 0;
while ( read $fh, $byte, 1 ) {
$count += $bitcounts[ord($byte)];
}
print "filename contains $count set bits\n";
__END__
7733485