There are two ways I can think of:
1) use unpack as you are already doing, but don't waste cycles doing any IO.
2) use a lookup table with precomputed values for how many bits are in a given byte
1) The trick here is the '%' directive to unpack which tells unpack to perform a checksum across the result, which sums all of the 0s and 1s in the case of binary data
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) The values from 0 - 255 only have a certain number of set bits, which will never change, so you can precompute an array to hold all of them. You waste a little memory -- around 4k or 8k depending on the build -- to prevent any computation except for lookups.
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
Both of these approaches give me 7733485 for a sample JPEG I processed.