a=b, b=a, bez zmiennej c

0

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.

1

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.

2
 
a = a + b;
b = a - b;
a = a - b;
0

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

4

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.

0
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
1
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 ...

0
_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.

Można też poczytać sobie artykuł o tym, że to słowo kluczowe w kodzie w zasadzie znaczy tyle co spacja.

0
  1. 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).

  1. 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).

  2. gdy pominie się typ zmiennej to kompilator może przyjąć "int". Wygląda to krzywo, pewnie niezgodne ze standardami, ale działa.

1 użytkowników online, w tym zalogowanych: 0, gości: 1