Gibt es noch andere Lösungen um den Inhalt ohne Zwischenspeichern
zu tauschen?
#include<stdio.h>
int main()
{
int x=10; int y=25;
x ^= y; y ^= x; x ^= y;
printf("\n x = %i y = %i ", x, y);
}
Walter K. schrieb: > Gibt es noch andere Lösungen um den Inhalt ohne Zwischenspeichern > zu tauschen? > > > #include<stdio.h> > > int main() > { > int x=10; int y=25; > > x ^= y; y ^= x; x ^= y; > > printf("\n x = %i y = %i ", x, y); > }
1 | |
Gast
#5796146
1 | |
2 | |
Hat sogar überhaupt keine Laufzeitkosten!
Gast
#5796169
Jemand schrieb: > #define x y > #define y x 1. April ist vorbei.
Gast
#5796179
In [[https://graphics.stanford.edu/~seander/bithacks.html#SwappingValuesSubAdd]] wird es mit Addition und Subtraktion gezeigt.
Jemand schrieb: > #define x y > #define y x > > Hat sogar überhaupt keine Laufzeitkosten! Ah - ein Experte!
Gast
#5796232
Hanns schrieb: > In > [[https://graphics.stanford.edu/~seander/bithacks.html#SwappingValuesSubAdd]] > wird es mit Addition und Subtraktion gezeigt. Wobei das nur für unsigned int definiert ist und bei signed int undefined behaviour.
Gast
#5796246
Hanns schrieb: > In > [[https://graphics.stanford.edu/~seander/bithacks.html#SwappingValuesSubAdd]] > wird es mit Addition und Subtraktion gezeigt.
1 | |
Wenn man diese Variante für signed integer benutzt möchte, sollte man vorher nach unsigned casten, damit man kein undefined sondern implementation defined behavior hat. Oder besser gleich die xor Variante nehmen die für signed und unsigned geeignet ist.
1 | |
Was ist die raw integer representation eines floats?
Gast
#5796286
mh schrieb: > Was ist die raw integer representation eines floats? Das, was du bekommst, wenn du per Union eine Gleitkommazahl als Integer interpretierst.
Gast
#5796287
Warum? Offensichtich geht es um C (steht in der Überschrift, und du machst dir um undefined behaviour Sorgen). Du weißt also eh nicht, was nach dem Optimieren raus kommt. Warum nimmst du nicht die am einfachsten zu verstehende Lösung, bei der du noch hoffen kannst dass auch der Compiler versteht was du willst, weil er das Muster erkennt (mit Zwischenspeichern) und läßt den Compiler optimieren?
Gast
#5796303
Und wenn die Variablen Strings sind? Oder struct-Variablen?
Gast
#5796317
Hier, mal ganz was erstaunliches ;-)
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
Ausgabe:
1 | |
2 | |
Gast
#5796331
und mit Multiplikation/Division ;-)
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
Gast
#5796358
Jemand schrieb: > mh schrieb: >> Was ist die raw integer representation eines floats? > > Das, was du bekommst, wenn du per Union eine Gleitkommazahl als Integer > interpretierst. Soweit ich das sehe ist das legal, wenn man einen unsigned int passender Größe nimmt. Interessant. Sebastian schrieb: > Warum nimmst du nicht die am einfachsten zu verstehende Lösung, bei der > du noch hoffen kannst dass auch der Compiler versteht was du willst, > weil er das Muster erkennt (mit Zwischenspeichern) und läßt den Compiler > optimieren? Ich weiß nicht, was der Anlass für diese Frage ist, aber es gibt Fälle in denen diese Art der Optimierung notwendig ist, um Register einzusparen.
Gast
#5796378
zitter_ned_aso schrieb: > Und wenn die Variablen Strings sind? Oder struct-Variablen? 2 unsigned char* + Schleife
Gast
#5796379
mh schrieb: > aber es gibt Fälle > in denen diese Art der Optimierung notwendig ist, um Register > einzusparen. Ich denke mal, das braucht mehr Register (4?) als das simple Swap (3) (angenommen der Item passt in ein Register). Warum das herumgeistert ist wohl nur wegen unbekannt und erstaunlich Effekten. leo
mh schrieb: > Jemand schrieb: >> mh schrieb: >>> Was ist die raw integer representation eines floats? >> >> Das, was du bekommst, wenn du per Union eine Gleitkommazahl als Integer >> interpretierst. > Soweit ich das sehe ist das legal, wenn man einen unsigned int > passender Größe nimmt. Interessant. Nein, man darf immer nur auf das Union-Element zugreifen, das "aktiv" ist, und das ist das zuletzt geschriebene. leo schrieb: > Ich denke mal, das braucht mehr Register (4?) als das simple Swap (3) Wofür sollten so viele Register nötig sein?
Gast
#5796392
Rolf M. schrieb: >> Ich denke mal, das braucht mehr Register (4?) als das simple Swap (3) > > Wofür sollten so viele Register nötig sein? Ja, sorry - da hab ich wohl geirrt. leo
Gast
#5796403
Rolf M. schrieb: > Nein, man darf immer nur auf das Union-Element zugreifen, das "aktiv" > ist, und das ist das zuletzt geschriebene. C11 erlaubt das. 6.5.2.3 Structure and union members:
1 | |
Gast
#5796420
Rolf M. schrieb: > Nein, man darf immer nur auf das Union-Element zugreifen, das "aktiv" > ist, und das ist das zuletzt geschriebene. In C erlaubt in C++ verboten (mit Ausnahmem)
zitter_ned_aso schrieb: > Und wenn die Variablen Strings sind? Kein Problem. Pointer kann man genauso tauschen wie unsigned int.
Gast
#5796474
tja, dann wollt ihr Strings in irgendwelchen Schleifen durchlaufen. Also kommt eine Laufvariable zum Einsatz. Man hat also doch eine zusätzliche Variable.
zitter_ned_aso schrieb: > tja, dann wollt ihr Strings in irgendwelchen Schleifen durchlaufen. Nö, wozu?
Gast
#5796493
ja, stimmt. man kann alles per Hand machen
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
Ich habe gerade etwas Interessantes festgestellt: Der GCC erzeugt bei eingeschalteter Optimierung für alle drei Varianten des folgenden Codes
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
exakt den gleichen Assemblercode. Betrachtet man diesen näher, findet man darin die folgende Codesequenz (in Pseudoassembler, gilt sowohl für PC als auch für AVR):
1 | |
2 | |
3 | |
Somit braucht man sich wenigstens nicht den Kopf darüber zu zerbrechen, welche der drei Methoden die effizienteste (in Bezug auf Laufzeit oder Speicher) ist :)
Gast
#5796540
lol
Yalu X. schrieb: > Somit braucht man sich wenigstens nicht den Kopf darüber zu zerbrechen, > welche der drei Methoden die effizienteste (in Bezug auf Laufzeit oder > Speicher) ist :) Was dann auch zur (wenig erstaunlichen) allumfassend Antwort auf die Eingangsfrage führt: Gar nicht. Oliver
zitter_ned_aso schrieb: > ja, stimmt. man kann alles per Hand machen Du hast es immer noch nicht verstanden: Warum soll man die Strings iterieren, um zwei Zeiger auszustauschen?
zitter_ned_aso schrieb: > ja, stimmt. man kann alles per Hand machen
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
Gast
#5796892
Walter K. schrieb: > Gibt es noch andere Lösungen um den Inhalt ohne Zwischenspeichern > zu tauschen? > > #include<stdio.h> > > int main() > { > int x=10; int y=25; > > x ^= y; y ^= x; x ^= y; > > printf("\n x = %i y = %i ", x, y); > } Bester Tipp: Lass den Quatsch, das ist nicht effizienter. Zweitbester Tipp: Was passiert denn wenn x und y identisch sind (im Sinne identische Variable wenn du das Konstrukt später als Makro oder inline Funktion verpackt hast)?
1 | |
2 | |
3 | |
4 | |
5 | |
x^y schrieb: > Was passiert denn wenn x und y identisch sind naja .. einfach if(x^y) { /*tausche*/ }
Mit int in C wird das so nix. Allenfalls wenn man die Nibbles eines Bytes vertauschen möchte könnte man beispiesweise auf ATMegas inline Assembler verwenden um SWAP (https://www.microchip.com/webdoc/avrassembler/avrassembler.wb_SWAP.html) zu verwenden. Aber das ist dann nicht mehr wirklich C.
Walter K. schrieb: > x^y schrieb: >> Was passiert denn wenn x und y identisch sind > > naja .. einfach if(x^y) { /*tausche*/ } Dann ist es aber definitiv ineffizienter als die Methode mit der temporären Variable.
Jobst Q. schrieb: > (unsigned long)str1 ^= (unsigned long)str2; > (unsigned long)str2 ^= (unsigned long)str1; > (unsigned long)str1 ^= (unsigned long)str2; Und was wenn "long" nicht groß genug für einen Pointer ist? Wenn schon dann "uintptr_t" ... Alternativ C++ verwenden und std::swap(x,y); aufrufen. Das nutzt automatisch den optimalen Weg für den jeweiligen Typ (insb. für Strings).
Gast
#5797053
zitter_ned_aso schrieb: > Hier, mal ganz was erstaunliches ;-) ja ;-) Hanns schrieb: > In > [[https://graphics.stanford.edu/~seander/bithacks.html#SwappingValuesSubAdd]] > wird es mit Addition und Subtraktion gezeigt. Wobei XOR ja auch eine Addition ist, nur halt Bitweise und man nicht zwischen Addition und Subtraktion unterscheiden muss (daher beides mal XOR nehmen kann).
Gast
#5797110
x^y schrieb: > Walter K. schrieb: >> Gibt es noch andere Lösungen um den Inhalt ohne Zwischenspeichern >> zu tauschen? >> >> #include<stdio.h> >> >> int main() >> { >> int x=10; int y=25; >> >> x ^= y; y ^= x; x ^= y; >> >> printf("\n x = %i y = %i ", x, y); >> } > > Bester Tipp: Lass den Quatsch, das ist nicht effizienter. Zweitbester > Tipp: Was passiert denn wenn x und y identisch sind (im Sinne identische > Variable wenn du das Konstrukt später als Makro oder inline Funktion > verpackt hast)? > x = y = 42; > -> x ^= y; > -> x = x ^ y; > -> x = x ^ x; > -> x = 0 Leider seh ich nicht was Du genau meinst. Vielleicht liegt es auch an der Optimierung des GCC, allerdings glaube ich das (noch) nicht. #include<stdio.h>
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
[K]ein Sohn [des] Admins (frei nach Lk 3,33) schrieb im Beitrag
#5797110:
> Leider seh ich nicht was Du genau meinst
Sollte man auf die Idee kommen das Tauschen (hässlich) in ein Makro zu
packen:
1 | |
und das Makro auf einer Variable mit sich selbst aufrufen (was in verschachtelten Konstruktionen schon mal passieren kann):
1 | |
2 | |
3 | |
4 | |
5 | |
kommt 0 heraus. Mit std::swap ist das kein Problem:
1 | |
2 | |
3 | |
4 | |
5 | |
Das funktioniert übrigens so:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
Also der klassische Ringtausch mit temporärer Variable. Wäre interessant ob man einen Testfall basteln kann, in dem der Optimizer den Xor-Trick nutzt.
Gast
#5797377
Niklas G. schrieb: > [K]ein Sohn [des] Admins (frei nach Lk 3,33) schrieb im Beitrag > #5797110: >> Leider seh ich nicht was Du genau meinst > > Sollte man auf die Idee kommen das Tauschen (hässlich) in ein Makro zu > packen: > #define UINT_SWAP(x,y) do { (x) ^= (y); (y) ^= (x); (x) ^= (y); } while > (0) Danke, jetz seh ichs auch.
Walter K. schrieb: > Gibt es noch andere Lösungen um den Inhalt ohne Zwischenspeichern > zu tauschen? In C kümmert sich der Compiler um die Optimierung und da sollte man ihm gefälligst nicht ins Handwerk pfuschen. In C gilt: Schreib es so hin, wie es am besten lesbar ist. Irgendwelche dirty Assemblerhacks haben in C-Programmen nichts verloren.
Beitrag #5798240 wurde von einem Moderator gelöscht.
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.