Mam pytanie.
Czy jest możliwość, aby dokonać operacji zmiany wartości dwóch zmiennych, tak aby nie używać 3 zmiennej (np. na początku a=1,b=2, po operacji a=2,b=1). Słyszałem coś o przesunięciach bitowych.
Jestem bardzo ciekawy. Jak ktoś może pomóc to proszę o takową pomoc.
Pozdrawiam.
Poczytaj o XOR swap: http://en.wikipedia.org/wiki/XOR_swap_algorithm
W 95% sytuacji to i tak nie ma jednak większego sensu.
Owszem można na przesunięciach to załatwić ale potrzebna bardzo dużo operacji 3 razy więcej niż bitów w liczbie.
Oczywiście można załatwić to w pętle tylko że jest mały szkopuł dla pętli użyjesz dodatkowej zmiennej.
Jeżeli już to można zrobić wstawkę assemblerową (większość procesorów posiada instrukcję exchange), z tym że tracisz na przenośności.
a = a + b;
b = a - b;
a = a - b;
Dzięki za odpowiedzi.
Właśnie chodzi mi też głównie czy te inne operacje są bardziej wydajne, mniej obciążające, zalecane niż standardowe (c=a, a=b, b=c przy pomocniczej c lub j.w.). Powiedzmy, że chciałbym, aby mój kod był jak najbardziej wydajny i profesjonalny.
pzdr
Jeśli chcesz, żeby twój kod był profesjonalny, to musi być czytelny. Robienie optymalizacji, które zaciemniają kod, a przyspieszają tylko na 1% procków, a na reszcie nic nie zmieniają, jest idiotyczne.
W nowoczesnych procesorach x86 instrukcje typu "mov reg, reg" są robione na etapie dekodowania instrukcji - te instrukcje nie wchodzą do potoków wykonawczych. Oznacza to iż są w zasadzie darmowe.
Z drugiej strony instrukcje typu "mov mem, reg" czy "mov reg, mem" lecą do potoków wykonawczych i trochę czasu zajmują. Ale i tak chcąc zrobić ten trik z XORami na komórkach pamięci, trzeba byłoby naprodukować znacznie więcej instrukcji, a zużyłoby się tyle samo rejestrów.
a = a + b;
b = a - b;
a = a - b;
Fajnie wygląda "wysokopoziomowo", ale pokaż mi jak to zaimplementujesz na x86 bez użycia dodatkowego rejestru (tzn mówię o zamianie rejestrów).
Edit:
W sumie wpadłem na pomysł jak to zrealizować na x86. Wyglądałoby to mniej więcej tak:
a += b;
b -= a;
b = -b;
a -= b;
No ale, jak widać, instrukcji robi się coraz więcej.
Wibowit napisał(a):
a = a + b;
b = a - b;
a = a - b;Fajnie wygląda "wysokopoziomowo", ale pokaż mi jak to zaimplementujesz na x86 bez użycia dodatkowego rejestru (tzn mówię o zamianie rejestrów).
Jeśli ktoś to potrafi zrobić bardziej optymalnie niż std::swap bez użycia ASM bo chętnie zobaczę.
Dla zobrazowania:
std::swap(a,b);
001A2ED0 mov eax,dword ptr [a]
001A2ED3 mov dword ptr [ebp-0Ch],eax
001A2ED6 mov ecx,dword ptr [b]
001A2ED9 mov dword ptr [a],ecx
001A2EDC mov edx,dword ptr [ebp-0Ch]
001A2EDF mov dword ptr [b],edx
vpiotr napisał(a):
Jeśli ktoś to potrafi zrobić bardziej optymalnie niż std::swap bez użycia ASM bo chętnie zobaczę.
Ano proszę:
inline void SwapInt(int &a,int &b) { register x=a; a=b; b=x; }
Dla niektórych kompilatorów należy napisać ... register int x ...
_13th_Dragon napisał(a):
vpiotr napisał(a):
Jeśli ktoś to potrafi zrobić bardziej optymalnie niż std::swap bez użycia ASM bo chętnie zobaczę.
Ano proszę:
inline void SwapInt(int &a,int &b) { register x=a; a=b; b=x; }
Dla niektórych kompilatorów należy napisać ... register int x ...
To nie kwestia kompilatora, typ powinien być podany. (Tzn. to raczej na niektórych kompilatorach można go pominąć) Po drugie w C++ register
ma status deprecated i kompilator może sobie to spokojnie olać. Po trzecie wynikowy kod dla tej funkcji oraz funkcji std::swap
jest u mnie identyczny:
mov eax, DWORD PTR [rdi]
mov edx, DWORD PTR [rsi]
mov DWORD PTR [rdi], edx
mov DWORD PTR [rsi], eax
ret
(GCC 4.7.2, -O2)
Dla mnie to kolejny dowód na to, że zajmowanie się takimi "optymalizacjami" jest stratą czasu, bo kompilator: a) zazwyczaj wie lepiej, b) i tak zrobi po swojemu.
- Opcje: Ja nie włączyłem -O2 :) I nie twierdziłem że się nie da, skąd taki wniosek?
Moja wiedza o asm na x86 jest bardzo bliska poziomowi C/C++, dlatego z -O2 nie wiedziałem jak zobaczyć ASM...
Używam VS 2010, chętnie się dowiem jak zobaczyć ASM w wersji Release (bez szukania po całym kodzie przez deassembler, w IDE kod ASM dla najważniejszych sekcji nie jest pokazywany).
-
register chyba już nic nie daje, kompilatory są o wiele bardziej agresywne (jak je odpowiednio ustawić) niż to jedno słówko daje (usuwają ścieżki kodu, same przechowują zmienne w rejestrach, zamieniają klasy / funktory na wywołania inline itd).
-
gdy pominie się typ zmiennej to kompilator może przyjąć "int". Wygląda to krzywo, pewnie niezgodne ze standardami, ale działa.