2012-01-23 14 views
1

私はここでいくつかのコードを最適化しようとしており、別の1つのベクトルを減算する2つの異なる単純なサブルーチンを書いています。私はこれらのサブルーチンに一対のベクトルを渡し、次に減算が実行されます。最初のサブルーチンは中間変数を使用して結果を格納し、2番目のサブルーチンは ' - ='演算子を使用してインライン演算を行います。完全なコードは、この質問の最後にあります。Math :: Complex私の配列の参照を台無しにする

純粋な実数を使用すると、プログラムは問題なく動作しますが、問題はありません。しかし、複雑なオペランドを使用している場合、オリジナルのベクトル(元々はサブルーチンに渡されたもの)が変更されます。なぜこのプログラムは純粋な実数に対してはうまくいくのですか?複素数を使用すると、この種のデータ修正を行うのはなぜですか?使用して(

  1. 印刷画面への主なベクトルを
  2. は、最初のサブルーチンの減算を実行します(コメントアウトコードに応じて、実数または複素数のいずれか)乱数ベクトルを生成します。

    は私のプロセスに注意してください。サブルーチン内の3番目の変数媒介変数)

  3. 実ベクトルまたは複素ベクトルの使用に関係なく、それらが変更されていないことを証明するために再び主ベクトルをスクリーンに表示します。
  4. 2番目のサブルーチン減算を実行する(インライン計算方法を使用)
  5. メインベクトルを画面にもう一度表示すると、複雑なベクトルを使用すると@ main_v1が変更されたが、実際のベクトルを使用すると変更されない(@ main_v2は影響を受けない)
  6. プリント常に正しい答えである減算への最終的な回答を、関係なく、実数または複素数ベクトルの

問題は、(かなり高速である)は、第2のサブルーチンの場合に生じ、 @ main_v1ベクトルを変更したくありません。私は道路をさらに計算するためにそのベクトルが必要なので、同じままにする必要があります。

これを修正する方法や、間違っていることはありますか?私のコード全体は以下の通りで、機能的でなければなりません。私は以下のCLI構文を使ってプログラムを実行しています。私はすべてを読みやすいように5を選択します。

C:\> bench.pl 5 REAL

または

C:\> bench.pl 5 IMAG

#!/usr/local/bin/perl 
# when debugging: add -w option above 
# 

use strict; 
use warnings; 
use Benchmark qw (:all); 
use Math::Complex; 
use Math::Trig; 
use Time::HiRes qw (gettimeofday); 

system('cls'); 

my $dimension = $ARGV[0]; 
my $type = $ARGV[1]; 

if(!$dimension || !$type){ 
    print "bench.pl <n> <REAL | IMAG>\n"; 
    print " <n> indicates the dimension of the vector to generate\n"; 
    print " <REAL | IMAG> dictates to use real or complex vectors\n"; 
    exit(0); 
} 

my @main_v1; 
my @main_v2; 
my @vector_sum1; 
my @vector_sum2; 

for($a=1;$a<=$dimension;$a++){ 

    my $r1 = sprintf("%.0f", 9*rand)+1; 
    my $r2 = sprintf("%.0f", 9*rand)+1; 
    my $i1 = sprintf("%.0f", 9*rand)+1; 
    my $i2 = sprintf("%.0f", 9*rand)+1; 

    if(uc($type) eq "IMAG"){ 
     # Using complex vectors has the issue 
     $main_v1[$a] = cplx($r1,$i1); 
     $main_v2[$a] = cplx($r2,$i2); 
    }elsif(uc($type) eq "REAL"){ 
     # Using real vectors shows no issue 
     $main_v1[$a] = $r1; 
     $main_v2[$a] = $r2; 
    }else { 
     print "bench.pl <n> <REAL | IMAG>\n"; 
     print " <n> indicates the dimension of the vector to generate\n"; 
     print " <REAL | IMAG> dictates to use real or complex vectors\n"; 
     exit(0); 
    } 
} 

# cmpthese(-5, { 
# v1 => sub {@vector_sum1 = vector_subtract(\@main_v1, \@main_v2)}, 
# v2 => sub {@vector_sum2 = vector_subtract_v2(\@main_v1, \@main_v2)}, 
# }); 
# print "\n"; 

print "main vectors as defined initially\n"; 
print_vector_matlab(@main_v1); 
print_vector_matlab(@main_v2); 
print "\n"; 

@vector_sum1 = vector_subtract(\@main_v1, \@main_v2); 
print "main vectors after the subtraction using 3rd variable\n"; 
print_vector_matlab(@main_v1); 
print_vector_matlab(@main_v2); 
print "\n"; 

@vector_sum2 = vector_subtract_v2(\@main_v1, \@main_v2); 
print "main vectors after the inline subtraction\n"; 
print_vector_matlab(@main_v1); 
print_vector_matlab(@main_v2); 
print "\n"; 

print "subtracted vectors from both subroutines\n"; 
print_vector_matlab(@vector_sum1); 
print_vector_matlab(@vector_sum2); 


sub vector_subtract { 
    # subroutine to subtract one [n x 1] vector from another 
    # result = vector1 - vector2 
    # 
    my @vector1 = @{$_[0]}; 
    my @vector2 = @{$_[1]}; 
    my @result; 

    my $row = 0; 
    my $dim1 = @vector1 - 1; 
    my $dim2 = @vector2 - 1; 

    if($dim1 != $dim2){ 
     syswrite STDOUT, "ERROR: attempting to subtract vectors of mismatched dimensions\n"; 
     exit; 
    } 

    for($row=1;$row<=$dim1;$row++){$result[$row] = $vector1[$row] - $vector2[$row]} 

    return(@result); 
} 

sub vector_subtract_v2 { 
    # subroutine to subtract one [n x 1] vector from another 
    # implements the inline subtraction method for alleged speedup 
    # result = vector1 - vector2 
    # 
    my @vector1 = @{$_[0]}; 
    my @vector2 = @{$_[1]}; 

    my $row = 0; 
    my $dim1 = @vector1 - 1; 
    my $dim2 = @vector2 - 1; 

    if($dim1 != $dim2){ 
     syswrite STDOUT, "ERROR: attempting to subtract vectors of mismatched dimensions\n"; 
     exit; 
    } 
    for($row=1;$row<=$dim1;$row++){$vector1[$row] -= $vector2[$row]}  # subtract inline 

    return(@vector1); 
} 

sub print_vector_matlab {  # for use with outputting square matrices only 
    my (@junk) = (@_); 
    my $dimension = @junk - 1; 
    print "V=["; 
    for($b=1;$b<=$dimension;$b++){ 
     # $temp_real = sprintf("%.3f", Re($junk[$b][$c])); 
     # $temp_imag = sprintf("%.3f", Im($junk[$b][$c])); 
     # $temp_cplx = cplx($temp_real,$temp_imag); 
     print "$junk[$b];"; 
     # print "$temp_cplx,"; 
    } 
    print "];\n"; 
} 

私もしました次の行を持つように第2のサブルーチンを修正しようとしました。そして、cを使うときに@ main_v1ベクトルを変更しますomplex numbers ...私は何が起こっているかについて完全に混乱しています。

@result = @vector1; 
for($row=1;$row<=$dim1;$row++){$result[$row] -= $vector2[$row]} 

return(@result); 

と私はあまりにもこれを試してみたが...まだオブジェクトがblessされたリファレンスで、複素数Perlで

for($row-1;$row<=$dim1;$row++){$result[$row] = $vector1[$row]} 
for($row=1;$row<=$dim1;$row++){$result[$row] -= $vector2[$row]} 

return(@result); 
+1

おそらく、実際の出力と予想される出力を示すことで明確にする必要があります。 – TLP

答えて

3

でmain_V1 @修正します。 Math::Complex esの配列は参照配列です。これは単なる普通のスカラである実数には当てはまりません。

あなたはこの変更した場合:これに

$vector1[$row] -= $vector2[$row] 

$vector1[$row] = $vector1[$row] - $vector2[$row] 

をあなたが行ってもいいでしょう:新しいオブジェクトを参照するように$vector1[$row]を設定するのではなく、既存のを修正すること1。

+0

うわー、それはあいまいです。 +1 – TLP

+0

こんにちはruakh、それはそれをするように見えた。残念ながら、これは私が達成したいと考えていたパフォーマンスの向上を無効にします。ああ、少なくとも今はうまくいく。ありがとう! – user1164453

5

Math :: Complexを少なくともバージョン1.57にアップグレードします。 the changelogが説明するように、そのバージョンの変更されたの1:

は、コピーコンストラクタを追加し、それが適切に呼ばれるように手配、デビッドMadoreとアレクサンドル・Ciorniiによって発見問題。

+1

+1。私はあなたが気にしないことを願っています。私はあなたの答えを編集して、なぜ*理由を説明するかを編集しました。 – ruakh

+0

ありがとう、みんな!それが問題を完全に解決しました。私はこれが愚かな質問で終わったと思うが、初心者で、コピーコンストラクタのようなものは何か分からないので、変更ログを読んだとき、そのものは私の頭の上にうまくいく。 – user1164453

+0

新しいMath :: Complexは1次元配列に対しては機能しますが、2次元行列を使用しようとすると同じ問題が発生します。 – user1164453

関連する問題