我想知道在Perl中计算二进制文件中设置位数(1' s)的最快方法是什么 我需要快速,因为我正在阅读10个文件,每个文件大约有5千万位。
我现在这样做的方式太慢了,运行10-15个文件需要几个小时。这就是我现在的工作方式(我知道它的效率很慢,但过去文件要小得多,而且这种方法还不错):
#count number of 1's in binary vector
sub get_DET_fault_count {
my $bin_vec = shift;
my $tmp_vec = generate_tmp_path("bin_vec");
io($tmp_vec)->println( unpack( "B*", $bin_vec ) );
my $fault_count = `grep -o -E '1' $tmp_vec | wc -l`;
chomp $fault_count;
`rm $tmp_vec`;
return $fault_count;
}
答案 0 :(得分:8)
我可以想到两种方式: 1)使用unpack,因为你已经在做,但不要浪费周期做任何IO。 2)使用具有预先计算值的查找表,以查找给定字节中的位数
1)这里的技巧是解包的'%'指令告诉unpack在结果中执行校验和,在二进制数据的情况下对所有的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
2)0 - 255中的值只有一定数量的设置位,永远不会更改,因此您可以预先计算一个数组以保存所有这些位。你浪费了一点内存 - 大约4k或8k,具体取决于构建 - 以防止除查找之外的任何计算。
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
对于我处理的JPEG I样本,这两种方法都给了我7733485。
答案 1 :(得分:2)
你可以做一个循环,不断改变字节(使用>>
运算符)并检查是否设置了最低位。
这样的事情:
do {
$counter++ if $bin_vec & 1;
$bin_vec >> 1;
} while ($bin_vec > 0);