我正在尝试优化一些代码,并编写了两个不同的简单子程序,它们将从另一个向量中减去一个向量。我将一对向量传递给这些子程序,然后执行减法。第一个子例程使用中间变量来存储结果,而第二个子例程使用' - ='运算符进行内联操作。完整代码位于此问题的底部。
当我使用纯粹的实数时,程序运行正常并且没有问题。但是,如果我使用复杂的操作数,那么原始向量(最初传递给子例程的向量)将被修改!为什么这个程序适用于纯实数,但在使用复数时会进行这种数据修改?
请注意我的流程:
问题出现了,因为在第二个子程序(速度快得多)的情况下,我不希望@ 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";
}
我甚至尝试修改第二个子程序,使其具有以下行,并且当使用复数时它仍然会改变@ main_v1向量...我对发生了什么感到困惑。
@result = @vector1;
for($row=1;$row<=$dim1;$row++){$result[$row] -= $vector2[$row]}
return(@result);
我也试过了......仍然用复数修改@ main_V1
for($row-1;$row<=$dim1;$row++){$result[$row] = $vector1[$row]}
for($row=1;$row<=$dim1;$row++){$result[$row] -= $vector2[$row]}
return(@result);
答案 0 :(得分:5)
将Math :: Complex升级到至少1.57版。正如the changelog所解释的那样,该版本的一个变化是:
添加复制构造函数并安排适当调用它,David Madore和Alexandr Ciornii发现问题。
答案 1 :(得分:3)
在Perl中,一个对象是一个受祝福的引用;所以Math::Complex
es数组是一个引用数组。实际数字并非如此,它们只是普通的标量。
如果你改变了这个:
$vector1[$row] -= $vector2[$row]
到此:
$vector1[$row] = $vector1[$row] - $vector2[$row]
你会很高兴:这会将$vector1[$row]
设置为引用一个新对象,而不是修改现有对象。