Math :: Сложная ошибка в ссылках на массив

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

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

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

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

Проблема возникает из-за того, что в случае второй подпрограммы (которая работает немного быстрее) я не хочу, чтобы вектор @ main_v1 изменялся. Мне нужен этот вектор для дальнейших вычислений в будущем, так что мне нужно, чтобы он оставался прежним.

Есть идеи, как это исправить, или что я делаю не так? Весь мой код приведен ниже и должен быть работоспособным. Я использовал синтаксис CLI, показанный ниже, для запуска программы. Я выбираю 5, чтобы мне все было легко читать.

c: \> bench.pl 5 НАСТОЯЩИЙ

or

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);

person user1164453    schedule 23.01.2012    source источник
comment
Возможно, вам стоит уточнить, указав фактический и ожидаемый результат.   -  person TLP    schedule 24.01.2012


Ответы (2)


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

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

person Alexandr Ciornii    schedule 23.01.2012
comment
+1. Надеюсь, вы не против, я отредактировал ваш ответ, чтобы также объяснить почему. - person ruakh; 24.01.2012
comment
Спасибо ребята! Это полностью решило проблему. Думаю, в итоге это был глупый вопрос, но, будучи новичком, я не знаю, что такое «конструктор копирования», поэтому, когда я читаю журналы изменений, все это выходит у меня из головы. - person user1164453; 24.01.2012
comment
Новый Math :: Complex работает с одномерными массивами, но если я попытаюсь использовать 2D-матрицу, у меня возникнет та же проблема. - person user1164453; 24.01.2012
comment
@ user1164453: Совершенно не глупый вопрос. Перегрузка операторов и конструкторы копирования хорошо знакомы программистам на C ++, но не так знакомы программистам на большинстве других языков. Фактически, я не могу вспомнить ни одного другого языка, в котором они есть. (И если бы это было действительно глупо / очевидно, то до версии 1.56 этого модуля не добралось бы!) - person ruakh; 24.01.2012

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

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

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

к этому:

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

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

person ruakh    schedule 23.01.2012
comment
Привет, руах, похоже, это сработало. К сожалению, это сводит на нет любое улучшение производительности, которого я надеялся достичь. Ну, по крайней мере, теперь это работает. Спасибо! - person user1164453; 24.01.2012