2017-01-13 9 views
1

私はそれがPerlのDo not careシンボル(X)であるかどうか疑問です。Do not care symbol in Perl

私は50ビットのバイナリ入力を持っています(実際にはBigIntを使用しました)。入力がデータベース内のデータと一致する場合、私はあらかじめ定義された値を返します。

データベース内のデータが11001100100010110111110110101001000010110101111101であるとします。

入力がX1001100100010110111110110101001000010110101111101の場合、Xは1または0になる可能性があるため、大文字と小文字を区別して扱いたいと思います。50ビットを50ビットに分割して例外を作成する方法はわかっていますが、 50ビットを一緒に扱うことを好みます。

test.pl(主コード、乱雑に見えるが、操作が簡単で、データベース入力ファイルを読み取り、一致した場合の事前定義された値を含む出力ファイルを返すtest.plが運営。):

#!/usr/bin/perl 

use strict; 
#use warnings; 
use Math::BigInt; 
#use Math::Gauss ':all'; 
#use Math::Gauss; 
use 5.010; 
use List::Util qw(sum); 

my $Astrip="cmp_top.iop.sparc0.exu.rml."; 
my $Aj=0; 
my @Aoutput; 
my $At=0; 
my $Agen; 
my @Aitems; my @Aweights; 
my @Aitems_p; my @Aweights_p; 
my $Ap=0; 
my $Aselected_p = 0; 
my $Atotal_p; my $Arand_p; my $Alimit_p; 
my $Ai=0; my $Am=0; my $Ak=0; 
my $Atotal; my $Arand; my $Alimit; 
my $Aselected =0; my $Attemp=0; my $Ane=0; my $Asum=0; 
my $Al=0; my $Attest=0; 

#### change edb workload - matmul 
open(CSV,'database.db')||die("Cannot open edb file $!"); 
my @Aedb; 

while(<CSV>){ 
    my @Arow=split(/\t/,$_); 
    push(@Aedb,\@Arow); 
} 
close CSV || die $!; 
#  if ($At == 0) { goto ASTART;  } 
my @Ainput=do{ 
    open my $Afh,"<","test.input" or die("Cannot open an input file $!"); 
    <$Afh>; 
}; 
for (my $An=0; $An < (scalar @Ainput); $An +=3) { 
### First loop 
$Attest = 0; 
for ($Ai=0; $Ai < (scalar @Aedb); $Ai +=2) { 
    $a = Math::BigInt->new("$Aedb[$Ai][1]"); 
    $b = Math::BigInt->new("$Ainput[$An]"); 
    if ($a == $b) { 

    $a = Math::BigInt->new("$Aedb[$Ai+1][1]"); 
    $b = Math::BigInt->new("$Ainput[$An+1]"); 
    if ($a == $b) {  $Attemp=0; 
     $Attest++; 
     $Agen=$Ainput[$An+2]; 
     if (not defined $Agen) { $Arand_p = rand();} 
     else { $Arand_p = $Agen; } 
     #$Attemp=0; 
     for ($Aj=2; $Aj < scalar @{ $Aedb[$Ai+1] }; $Aj++) { 
      if ($Aedb[$Ai+1][$Aj]/$Aedb[$Ai+1][2] > $Arand_p) { 
       $At++; 
        $Aedb[$Ai][$Aj] =~ s/\n//g; 
       $Aoutput[$At+$An/3]= $Astrip.$Aedb[$Ai][$Aj]; 
       $Attemp++; 
      } 
     } 
    #$Aoutput[$An/3+$At-$Attemp]= $Attemp; 
    } 
    } 
} 

} 
open(my $Afh2, '>', 'test.output'); 
print $Afh2 join("\n", @Aoutput); 
close $Afh2; 

database.dbの(データベースファイル):

0.1 11001100100010110111110110101001000010110101111101 rml_irf_old_e_cwp_e[1] rml_irf_new_e_cwp_e[1] rml_irf_swap_even_e rml_irf_old_e_cwp_e[0] rml_irf_new_e_cwp_e[0] rml_irf_swap_odd_e 
0.1 11101100110010011011001101100111001001100000010011 3.923510310023e-06 3.19470818154393e-08 7.05437377900141e-10 7.05437377900141e-10 4.89200539851702e-17 5.01433479478681e-19 
0.1 10000110001111010010111101110011001001011110000100 rml_irf_new_e_cwp_e[1] rml_irf_new_e_cwp_e[0] 
0.1 01110111010010000000101001000001100011011100011111 0.052908822741908 2.7185508579738e-05 
0.1 01001100100100001011101000011111100101111011000111 rml_irf_new_e_cwp_e[1] 
0.1 00111101000100001101010111010100000111100100100101 1.09213787524617e-25 
0.1 00001000011110000101010110111000000111011110011001 rml_irf_new_e_cwp_e[1] rml_irf_new_lo_cwp_e[1] rml_irf_new_lo_cwp_e[2] 
0.1 01101001011110101011111011011011101100110100000101 2.28019753307221e-06 2.89026436307201e-14 2.89026436307201e-14 

test.input:

11001100100010110111110110101001000010110101111101 
11101100110010011011001101100111001001100000010011 

TES t.output(入力に対してはあらかじめ定義された値で、不一致の場合には何もありません。私はX10011で同じ出力をしたいと思います...):

cmp_top.iop.sparc0.exu.rml.rml_irf_old_e_cwp_e[1] 

何か助けていただければ幸いです。

+4

1)50ビットのために 'BigInt'は必要ありません。 2) 'X'を' .'で置き換え、パターンマッチをチェックすることができます。 –

+0

@SinanÜnür、私はBigIntなしでは動作しないと確信していますが、ビット単位のAND番号を使用し、IVサイズは32ビットです。 (Bitwise-ANDは正規表現マッチよりも効率的です。) – ikegami

+0

@ikegamiそうであれば、2つの32ビット整数はまだBigIntより速くなります。私は 'BigInt'を使わずにこれを行うことができるすべての方法に入っていませんでした。 –

答えて

3
#!/usr/bin/env perl 

use strict; 
use warnings; 

my $search_for = 'X1001100100010110111110110101001000010110101111101'; 
(my $pat = $search_for) =~ s/X/./g; 

while (my $line = <DATA>) { 
    next unless $line =~ /\S/; 
    my $key = (split ' ', $line, 3)[1]; 
    if ($key =~ /^$pat\z/) { 
     print $line; 
    } 
} 

__DATA__ 
0.1 11001100100010110111110110101001000010110101111101 rml_irf_old_e_cwp_e[1] rml_irf_new_e_cwp_e[1] rml_irf_swap_even_e rml_irf_old_e_cwp_e[0] rml_irf_new_e_cwp_e[0] rml_irf_swap_odd_e 
0.1 11101100110010011011001101100111001001100000010011 3.923510310023e-06 3.19470818154393e-08 7.05437377900141e-10 7.05437377900141e-10 4.89200539851702e-17 5.01433479478681e-19 
0.1 10000110001111010010111101110011001001011110000100 rml_irf_new_e_cwp_e[1] rml_irf_new_e_cwp_e[0] 
0.1 01110111010010000000101001000001100011011100011111 0.052908822741908 2.7185508579738e-05 
0.1 01001100100100001011101000011111100101111011000111 rml_irf_new_e_cwp_e[1] 
0.1 00111101000100001101010111010100000111100100100101 1.09213787524617e-25 
0.1 00001000011110000101010110111000000111011110011001 rml_irf_new_e_cwp_e[1] rml_irf_new_lo_cwp_e[1] rml_irf_new_lo_cwp_e[2] 
0.1 01101001011110101011111011011011101100110100000101 2.28019753307221e-06 2.89026436307201e- 

さらに、あなたは本当にあなたの変数を批判的に見るべきです。あなたはあまりにも多くのものを持っており、彼らは便利に名前を付けられていません。また、すべてがAで始まる場合、Aは情報を伝えません。

1

私が正しく理解すれば、最初の(最下位)49ビットが同じである必要があります。両方のビット50を設定する。例えば

は、次いで$v1$v2のみ真を返すように、テストのために50番目のビットが異なっていてもよい整数で

if (($v1 | (1<<49)) == ($v2 | (1<<49))) { say "Match" } 

を比較します。

残りの部分は、バイナリ文字列からこれらの整数を作成する方法を選択することです。 (ikegamiの比較番号付き)問題のようMath::BigIntを使用して


use warnings; 
use strict; 
use Math::BigInt; 

my $input_bin = '01001100100010110111110110101001000010110101111101'; 
my $input = Math::BigInt->from_bin($input_bin);  
print "$input_bin input\n"; 

# First number in @nums differs from input only in the left-most bit 
my @nums = (
    '11001100100010110111110110101001000010110101111101', 
    '11101100110010011011001101100111001001100000010011' 
); 

my $bits = 49; 
foreach my $num_bin (@nums) 
{ 
    my $num = Math::BigInt->from_bin($num_bin); 

    if (($input | (1<<$bits)) == ($num | (1<<$bits))) 
    { 
     print "$num_bin matches\n"; 
    } 
    else { 
     print "$num_bin does not match\n" 
    } 
} 

プリント

 
01001100100010110111110110101001000010110101111101 input 
11001100100010110111110110101001000010110101111101 matches 
11101100110010011011001101100111001001100000010011 does not match 

、まずMath::Int64このため、他のモジュールがあります。

Math::BigIntを他に使用していない場合は、システムに64ビットのサポートがあり、Perlがコンパイルされていれば、他の方法で整数を取得できます。文字列が最初Q

q A signed quad (64-bit) value. 
    Q An unsigned quad value. 
    (Quads are available only if your system supports 64-bit 
     integer values _and_ if Perl has been compiled to support 
     those. Raises an exception otherwise.) 

>で64

my $input = unpack("Q>", pack("B*", substr("0" x 64 . $input_bin, -64))); 

にパディングする必要がpackを使用


は、必要に応じて、ビッグエンディアン修飾子であり、 Bとの契約template in packoctを使用して


ははるかに簡単です、あなたは'portable'警告

no warnings 'portable'; 

my $input = oct '0b' . $input_bin; 

my $bits = 49; 
foreach my $num_bin (@nums) 
{ 
    my $num = oct '0b' . $num_bin; 

    if (($input | (1<<$bits)) == ($num | (1<<$bits))) { 
     print "$num_bin matches\n"; 
    } else { 
     print "$num_bin does not match\n" 
    } 
} 

をオフにする気にしない場合は、警告が32ビットと64ビットのPerlの間で移植されていないこのコードについてだろう。これは、packよりもかなり速いはずです。

6

使用Math::BigInt

use Config qw(%Config); 

sub bin_to_uint64 { unpack 'Q>', pack 'B*', substr(('0' x 64) . $_[0], -64) } 

die("64-ints required\n") if $Config{ivsize} < 8; 

my $pattern = 'X1001100100010110111110110101001000010110101111101'; 
my $mask = bin_to_uint64($pattern =~ tr/X01/011/r); 
my $targ = bin_to_uint64($pattern =~ tr/X/0/r); 

for my $num_bin (qw(
    11001100100010110111110110101001000010110101111101 
    11101100110010011011001101100111001001100000010011 
)) { 
    my $num = bin_to_uint64($num); 
    if (($num & $mask) == $targ) { 
     say "$num_bin matches"; 
    } else { 
     say "$num_bin doesn't match"; 
    } 
} 
(最速いた場合は、サポートされている):ネイティブ整数を使用して(のBigIntよりも速い)

use Math::UInt64 qw(net_to_uint64); 

sub bin_to_uint64 { net_to_uint64 pack 'B*', substr(("0" x 64) . $_[0], -64) } 

my $pattern = 'X1001100100010110111110110101001000010110101111101'; 
my $mask = bin_to_uint64($pattern =~ tr/X01/011/r); 
my $targ = bin_to_uint64($pattern =~ tr/X/0/r); 

for my $num_bin (qw(
    11001100100010110111110110101001000010110101111101 
    11101100110010011011001101100111001001100000010011 
)) { 
    my $num = bin_to_uint64($num); 
    if (($num & $mask) == $targ) { 
     say "$num_bin matches"; 
    } else { 
     say "$num_bin doesn't match"; 
    } 
} 

Math::UInt64を使用して

use Math::BigInt qw(); 

my $pattern = 'X1001100100010110111110110101001000010110101111101'; 
my $mask = Math::BigInt->from_bin($pattern =~ tr/X01/011/r); 
my $targ = Math::BigInt->from_bin($pattern =~ tr/X/0/r); 

for my $num_bin (qw(
    11001100100010110111110110101001000010110101111101 
    11101100110010011011001101100111001001100000010011 
)) { 
    my $num = Math::BigInt->from_bin($num); 
    if (($num & $mask) == $targ) { 
     say "$num_bin matches"; 
    } else { 
     say "$num_bin doesn't match"; 
    } 
} 

(Perlのが付属しています)

パックされたintを使用する:(最も速いが、書かれているように、パターンを仮定し、num_binはt彼と同じ長さ)

sub bin_to_packed { pack 'B*', $_[0] } 

my $pattern = 'X1001100100010110111110110101001000010110101111101'; 
my $mask = bin_to_packed($pattern =~ tr/X01/011/r); 
my $targ = bin_to_packed($pattern =~ tr/X/0/r); 

for my $num_bin (qw(
    11001100100010110111110110101001000010110101111101 
    11101100110010011011001101100111001001100000010011 
)) { 
    my $num = bin_to_packed($num); 
    if (($num & $mask) eq $targ) { 
     say "$num_bin matches"; 
    } else { 
     say "$num_bin doesn't match"; 
    } 
} 

文字列の使用:(ループでは何もする必要はないので実際のチェックが最も速いため、 。)のパターンとnum_binが同じ長さであると仮定し

my $pattern = 'X1001100100010110111110110101001000010110101111101'; 
my $mask = $pattern =~ tr/X01/\x00\xFF\xFF/r; 
my $targ = $pattern =~ tr/X/\x00/r; 

for my $num_bin (qw(
    11001100100010110111110110101001000010110101111101 
    11101100110010011011001101100111001001100000010011 
)) { 
    if (($num_bin & $mask) eq $targ) { 
     say "$num_bin matches"; 
    } else { 
     say "$num_bin doesn't match"; 
    } 
} 
同上

が、5.14+

my $pattern = 'X1001100100010110111110110101001000010110101111101'; 
(my $mask = $pattern) =~ tr/X01/\x00\xFF\xFF/; 
(my $targ = $pattern) =~ tr/X/\x00/; 

for my $num_bin (qw(
    11001100100010110111110110101001000010110101111101 
    11101100110010011011001101100111001001100000010011 
)) { 
    if (($num_bin & $mask) eq $targ) { 
     say "$num_bin matches"; 
    } else { 
     say "$num_bin doesn't match"; 
    } 
} 

出力せずに動作します:

11001100100010110111110110101001000010110101111101 matches 
11101100110010011011001101100111001001100000010011 doesn't match 
+0

ご協力いただきありがとうございます。私は文字列バージョンを使用することを決定しました。これは最速のバージョンです。また、遅い回答には申し訳ありません。私は最近、他の州に移動し、新しい仕事を得たので、私はフォローアップしませんでした。とにかくありがとう! –

0

すべてのあなたの答えをいただき、ありがとうございます。私はすべての助けに感謝します。私が知りたかったのは、Shinanの答えです。私はDo not careシンボルは "と思う。だから私は "を使用します。 "X"を使用する代わりに。

また、最初の説明では十分ではなかったので、詳細を説明します。

1)入力のビットは、私の例の最初のビットにのみ使用しても、気にする必要はありません。

2)BigInt - 例が50ビットであっても、後でより多くのビットを使用するため、ネイティブ整数では不十分です。しかし、Math :: Uint64は、池上が提案するようにはるかに高速で、私はそれを使用します。

私はあなたの提案をすべて今夜テストし、すぐに私の答えを掲載します。ありがとうございました。

+0

これは回答ではありません。 – toolic