Pytanie Więcej o użyciu i i j jako zmiennych w Matlabie: prędkość


The Dokumentacja Matlaba mówi że

Aby zwiększyć szybkość i poprawić niezawodność, możesz zastąpić złożone i i j przez 1i. Na przykład zamiast używać

a = i;

posługiwać się

a = 1i;

The krzepkość część jest jasna, ponieważ mogą być wywoływane zmienne i lub j. Jednak w przypadku prędkośćZrobiłem prosty test w Matlab 2010b i uzyskuję wyniki, które wydają się być sprzeczne z twierdzeniem:

>>clear all

>> a=0; tic, for n=1:1e8, a=i; end, toc
Elapsed time is 3.056741 seconds.

>> a=0; tic, for n=1:1e8, a=1i; end, toc
Elapsed time is 3.205472 seconds.

Jakieś pomysły? Czy to może być problem związany z wersją?

Po komentarzach @TryHarda i @horchlera próbowałem przypisać inne wartości do zmiennej a, z tymi wynikami:

Rosnąca kolejność upływu czasu:

"i" <"1i" <"1 * i" (trend "A")

"2i" <"2 * 1i" <"2 * i" (trend "B")

"1 + 1i" <"1 + i" <"1 + 1 * i" (trend "A")

"2 + 2i" <"2 + 2 * 1i" <"2 + 2 * i" (trend "B")


10
2017-08-10 15:37


pochodzenie


Co powiesz na bardziej ogólny przypadek 2*i vs. 2i (lub nawet 2*1i)? - horchler
Widzę poprawę x 5 z R14 na laptopie Dink Rinky z XP. - Try Hard
Chciałbym się zgłosić clear all przed każdą pętlą? - Try Hard
@RashHard Clearing a znacznie wydłuża czas (oczekiwany) i odwraca różnicę. Czemu? - Luis Mendo
@horchler z 2*i vs. 2i jest szybszy z 2i (i najwolniejszy z 2*1i). - Luis Mendo


Odpowiedzi:


Myślę, że patrzysz na patologiczny przykład. Spróbuj czegoś bardziej złożonego (wyniki pokazane dla R2012b na OSX):

(powtórzone dodawanie)

>> clear all
>> a=0; tic, for n=1:1e8, a = a + i; end, toc
Elapsed time is 2.217482 seconds. % <-- slower
>> clear all
>> a=0; tic, for n=1:1e8, a = a + 1i; end, toc
Elapsed time is 1.962985 seconds. % <-- faster

(wielokrotne mnożenie)

>> clear all
>> a=0; tic, for n=1:1e8, a = a * i; end, toc
Elapsed time is 2.239134 seconds. % <-- slower
>> clear all
>> a=0; tic, for n=1:1e8, a = a * 1i; end, toc
Elapsed time is 1.998718 seconds. % <-- faster

9
2017-08-10 16:15



"Spróbuj czegoś bardziej złożonego ..." - mam nadzieję, że mam nadzieję. :-) - horchler
Może być tak, jak mówisz. Następnie twierdzenie "W celu zwiększenia szybkości i poprawionej odporności można zastąpić złożone i i j przez 1i. Na przykład, zamiast używać a = i; używać a = 1i" w dokumentacji jest ściśle błędne - Luis Mendo
Dla solidności dokumentacja jest poprawna (na przykład, jeśli przypadkowo uruchomisz i=3, następnie a=i ustawi 3, ale a=1i domyślnie będzie złożony i), ale zgadzam się, że nie jest jasne, dlaczego dodali względy prędkości - SheetJS


Należy pamiętać, że optymalizacje są stosowane w różny sposób, niezależnie od tego, czy korzystasz z wiersza poleceń, czy z zapisanej funkcji M.

Oto mój własny test:

function testComplex()
    tic, test1(); toc
    tic, test2(); toc
    tic, test3(); toc
    tic, test4(); toc
    tic, test5(); toc
    tic, test6(); toc
end

function a = test1
    a = zeros(1e7,1);
    for n=1:1e7
        a(n) = 2 + 2i;
    end
end

function a = test2
    a = zeros(1e7,1);
    for n=1:1e7
        a(n) = 2 + 2j;
    end
end
function a = test3
    a = zeros(1e7,1);
    for n=1:1e7
        a(n) = 2 + 2*i;
    end
end

function a = test4
    a = zeros(1e7,1);
    for n=1:1e7
        a(n) = 2 + 2*j;
    end
end

function a = test5
    a = zeros(1e7,1);
    for n=1:1e7
        a(n) = complex(2,2);
    end
end

function a = test6
    a = zeros(1e7,1);
    for n=1:1e7
        a(n) = 2 + 2*sqrt(-1);
    end
end

Wyniki na moim komputerze z systemem Windows z zainstalowanym R2013a:

>> testComplex
Elapsed time is 0.946414 seconds.    %// 2 + 2i
Elapsed time is 0.947957 seconds.    %// 2 + 2j
Elapsed time is 0.811044 seconds.    %// 2 + 2*i
Elapsed time is 0.685793 seconds.    %// 2 + 2*j
Elapsed time is 0.767683 seconds.    %// complex(2,2)
Elapsed time is 8.193529 seconds.    %// 2 + 2*sqrt(-1)

Należy zauważyć, że wyniki zmieniają się nieco w zależności od różnych przebiegów, w których kolejność połączeń jest tasowana. Więc mierz czasy z przymrużeniem oka.

Mój wniosek: nie ma znaczenia pod względem prędkości, jeśli używasz 1i lub 1*i.


Jedną z interesujących różnic jest to, że jeśli masz także zmienną w zakresie funkcji, w której również używasz jej jako jednostki wyobrażeniowej, MATLAB zgłasza błąd:

Error: File: testComplex.m Line: 38 Column: 5
"i" previously appeared to be used as a function or command, conflicting with its
use here as the name of a variable.
A possible cause of this error is that you forgot to initialize the variable, or you
have initialized it implicitly using load or eval.

Aby zobaczyć błąd, zmień powyższe test3 funkcjonować w:

function a = test3
    a = zeros(1e7,1);
    for n=1:1e7
        a(n) = 2 + 2*i;
    end
    i = rand();        %// added this line!
end

tj. zmienna i został użyty zarówno jako funkcja, jak i zmienna w tym samym zasięgu lokalnym.


5
2017-08-10 20:40



Założę się, że jeśli "rozgrzejesz" te funkcje przed ich rozłożeniem, wszelkie różnice znikną w hałasie. - horchler
Dla mnie z rozgrzewką lub bez wyników, wyniki były takie same: około 0,43 dla pierwszych czterech metod (bez znaczącej różnicy), a następnie odpowiednio 0,58 i 1,2. Przebiegł kilka razy, a ostatnie dwa są znacznie wolniejsze niż pierwsze cztery. - Dennis Jaheruddin
prawda, sposób, w jaki zmierzyłem czas, jest niezbyt dokładny. Lepszym rozwiązaniem jest użycie TIMEIT z wymiany plików, która zajmuje się rozgrzewaniem kodu, kilkoma uruchomieniami i uśrednianiem wyników, przy jednoczesnym uwzględnieniu narzutów funkcji wywoływania ... Z przyjemnością dowiesz się, że następna wersja MATLAB (prerelease as of know) obejmuje tę funkcję natywnie! - Amro