Math :: Complex搞砸了我的数组引用

时间:2012-01-23 23:23:43

标签: arrays perl reference complex-numbers

我正在尝试优化一些代码,并编写了两个不同的简单子程序,它们将从另一个向量中减去一个向量。我将一对向量传递给这些子程序,然后执行减法。第一个子例程使用中间变量来存储结果,而第二个子例程使用' - ='运算符进行内联操作。完整代码位于此问题的底部。

当我使用纯粹的实数时,程序运行正常并且没有问题。但是,如果我使用复杂的操作数,那么原始向量(最初传递给子例程的向量)将被修改!为什么这个程序适用于纯实数,但在使用复数时会进行这种数据修改?

请注意我的流程:

  1. 生成随机向量(实际或复杂,具体取决于注释掉的代码)
  2. 将主要矢量打印到屏幕
  3. 执行第一个子程序减法(使用子程序中的第三个变量中介)
  4. 再次将主要矢量打印到屏幕上以证明它们没有改变,无论使用真实还是复杂的载体
  5. 执行第二个子程序减法(使用内联计算方法)
  6. 再次将主矢量打印到屏幕上,显示使用复矢量时@ main_v1已更改,但使用实矢量时不会改变(@ main_v2不受影响)
  7. 打印减法的最终答案,无论是真实还是复杂的矢量,都是正确的答案
  8. 问题出现了,因为在第二个子程序(速度快得多)的情况下,我不希望@ 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);
    

2 个答案:

答案 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]设置为引用一个新对象,而不是修改现有对象。