Math :: Complex испортил мой массив ссылок - PullRequest
1 голос
/ 24 января 2012

Я пытаюсь оптимизировать некоторый код здесь и написал две разные простые подпрограммы, которые будут вычитать один вектор из другого.Я передаю пару векторов этим подпрограммам, и затем выполняется вычитание.Первая подпрограмма использует промежуточную переменную для хранения результата, тогда как вторая выполняет встроенную операцию, используя оператор «- =».Полный код находится внизу этого вопроса.

Когда я использую чисто реальные числа, программа работает нормально и проблем не возникает.Однако, если я использую сложные операнды, то исходные векторы (те, которые изначально были переданы подпрограммам) изменяются!Почему эта программа работает нормально для чисто вещественных чисел, но выполняет такую ​​модификацию данных при использовании комплексных чисел?

Обратите внимание на мой процесс:

  1. Генерация случайных векторов (действительных или сложных в зависимостив закомментированном коде)
  2. Вывести основные векторы на экран
  3. Выполнить первое вычитание подпрограммы (используя третью переменную-посредник в подпрограмме)
  4. Распечатать основные векторыснова на экран, чтобы доказать, что они не изменились, независимо от того, используются ли действительные или комплексные векторы
  5. Выполните вычитание второй подпрограммы (используя метод встроенных вычислений)
  6. Распечатайте основные векторы дляснова на экране, показывая, что @ main_v1 изменился при использовании сложных векторов, но не изменится при использовании реальных векторов (@ main_v2 не затронут)
  7. Вывести окончательные ответы на вычитание, которые всегда являются правильными ответами,независимо от реальных или сложных векторов

Возникла проблемаПотому что в случае второй подпрограммы (которая немного быстрее) я не хочу, чтобы вектор @ 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 ]

5 голосов
/ 24 января 2012

Обновите Math :: Complex до версии не ниже 1.57.Как объясняет список изменений , одним из изменений в этой версии было:

Добавить конструктор копирования и сделать так, чтобы он вызывался соответствующим образом, проблема, обнаруженная Дэвидом Мадором и Александром Чёрным.

3 голосов
/ 24 января 2012

В Perl объект является благословенной ссылкой; поэтому массив Math::Complex es - это массив ссылок. Это не относится к действительным числам, которые являются просто обычными скалярами.

Если вы измените это:

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

к этому:

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

Вы будете в порядке: это установит $vector1[$row] для ссылки на новый объект, а не для изменения существующего.

...