dwhite20899 has asked for the wisdom of the Perl Monks concerning the following question:

Your esteemed worshipnesses...

I have a 40-char hex string, and 20 40-char hex mask strings, and I need to generate 20 32-bit integer vectors.

e.g. given input

"DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"
and masks 
"FFFF804020100804020100804020100804000102"
"0102FFFF80402010080402010080402010080400"
"04000102FFFF8040201008040201008040201008"
...

I need to & the input and mask_1, like so

DA39A3EE5E6B4B0D3255BFEF95601890AFD80709
FFFF804020100804020100804020100804000102
========================================
DA39804000000804020100800020100004000100

then use only the 32 bits from mask_1 that remain set in the &'ed result to generate a scalar 0<x<2**32. In this case, "DA398040..." = 3661221814.

I can do it, with a boatload of hex, substr, pack, unpack, and & use, but there's got to be a better (faster) way. I do 100 million of these at a time. I've looked at vec, but I can't figure a good way to use it.

Can anyone help me improve on this?

my $in="DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"; my $mask="FFFF804020100804020100804020100804000102"; my $comb=""; for($i=0;$i<20;$i++) { $comb .= sprintf("%02X", ( hex(substr($in,$i*2,2)) & hex(substr($mas +k,$i*2,2))) ); } print "$in\n"; print "$mask\n========================================\n"; print "$comb\n"; my $bits = unpack("B*", pack("H40",$mask)); my $vecbits = unpack("B*", pack("H40",$comb)); my $vecs = ""; for ($i=0;$i<160;$i++) { if (substr($bits,$i,1) eq "1") { $vecs .= substr($vecbits,$i,1); } } my $vextor = hex(unpack("H*", pack("B32",$vecs))); print "$vextor\n";

Replies are listed 'Best First'.
Re: bitmask to vector problem
by BrowserUk (Patriarch) on Jan 06, 2005 at 20:27 UTC

    Does this help?

    my $v = 'DA39A3EE5E6B4B0D3255BFEF95601890AFD80709'; my $m = 'FFFF804020100804020100804020100804000102'; my $vb = unpack 'B*', pack 'H40', $v; my $mb = unpack 'B*', pack 'H40', $m; my $rb = $vb & $mb; print unpack 'H*', pack 'B*', $rb; da39804000000804020100800020100004000100
    Or as a "one-liner":
    perl -le"print unpack'H*', pack'B*', unpack('B*',pack'H*','DA39A3EE5E6B4B0D3255BFEF95601890AFD80709') & unpack('B*',pack'H*','FFFF804020100804020100804020100804000102')" da39804000000804020100800020100004000100

    Examine what is said, not who speaks.
    Silence betokens consent.
    Love the truth but pardon error.
Re: bitmask to vector problem
by sgifford (Prior) on Jan 06, 2005 at 20:25 UTC
    How about this?
    #!/usr/bin/perl my $s = "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"; my $mask1 = "FFFF804020100804020100804020100804000102"; my $result = bin2hex(hex2bin($s) & hex2bin($mask1)); print $result,"\n"; sub hex2bin { my($s)=@_; $s =~ tr/0-9A-F/\x00-\x09\x0A-0x0F/; $s; } sub bin2hex { my($s)=@_; $s =~ tr/\x00-\x09\x0A-0x0F/0-9A-F/; $s; }
Re: bitmask to vector problem
by dwhite20899 (Friar) on Jan 14, 2005 at 03:41 UTC
    I've ended up with this for now.
    cat shafile | perl mkvectors.pl
    set_mask(); while (<STDIN>) { chomp; $in = substr($_, 0, 40); if ($in =~ /^[0-9a-f]/i ) { # check that it's valid hex my $in_bits = unpack("B*", pack("H40",$in)); my %offsets ; for(my $j=0;$j<20;$j++) { # each of 20 bitmasks $offsets{calc_vector($in_bits,$bits[$j])} = 1; } foreach my $k (sort {$a <=> $b} (keys %offsets) ) { print "$k\n"; } } } print "\n"; exit; #-------- sub set_mask { $mask[0]="FFFF804020100804020100804020100804000102"; $mask[10]=reverse($mask[0]); $bits[0] = unpack("B*", pack("H40",$mask[0])); $bits[10] = unpack("B*", pack("H40",$mask[10])); for (my $i=1;$i<10;$i++) { $mask[$i] = substr($mask[$i-1],36,4) . substr($mask[$i-1],0,36 +) ; $mask[10+$i] = substr($mask[10+$i-1],36,4) . substr($mask[10+$ +i-1],0,36) ; $bits[$i] = unpack("B*", pack("H40",$mask[$i])); $bits[10+$i] = unpack("B*", pack("H40",$mask[10+$i])); } return(0); } sub calc_vector { my $input = shift; my $mask = shift; my $vecs = ""; for (my $i=0;$i<160;$i++) { if (substr($mask,$i,1) eq "1") { $vecs .= substr($input,$i,1); } } return(hex(unpack("H*", pack("B32",$vecs)))); }