Forum: Mikrocontroller und Digitale Elektronik Vergleiche mit (2^n)-1 und -(2^n) schneller?


von Daniel (Gast)


Lesenswert?

Hallo,

ich bin µC Anfänger und habe folgende Frage zum Vergleichen von 
Variablen:

So weit ich weiß sind Vergleiche eines beliebigen Werts X mit einem Wert 
Y der (2^n)-1 oder -(2^n) ist schneller als wie wenn Y beliebig ist. 
Weiß jemand warum?

Der C-Code meiner Frage sieht also quasi so aus:
Schnell: if(X => 512) {....} // Y = 2^9
Langsam: if(X => 500) {....} // Y = 500

Muss für den schnellen Vergleich nur eine Variable ins Register geladen 
werden, die dann ensprechend geshiftet und dann auf 0 geprüft wird?

Ich habe mal versucht anhand der Dokumentation des von mir genutzten TI 
TMS470 nachzuvollziehen wie viele clock-cycles für einen CMP Befehl 
benötigt werden, aber alleine bekomme ich das nicht hin...

Noch eine kurze 2.Frage/Vermutung: Ich vermute durch die bedingten 
Sprungbefehle im ARM-Mode ist der Unterschied zwischen 
schneller/langsmer Variante wengier ausgeprägt als im Thumb-Mode, oder?

Vielen Dank im Voraus,

Daniel

von Gast (Gast)


Lesenswert?

> Schnell: if(X => 512) {....} // Y = 2^9

Evtl weil nur geprüft werden muss, ob das Bit 2^9 von X gesetzt ist. 
Sonst fällt mir kein Grund ein.

von Gast (Gast)


Lesenswert?

>ich bin µC Anfänger und habe folgende Frage zum Vergleichen von
>Variablen:


Stell diese Frage wieder, wenn Du Profi geworden bist und die Antwort 
dringend zur Problemlösung benötigt wird.
Gerade als Anfänger ist es nicht sinnvoll, virtuelle Probleme zu lösen.

von Tom (Gast)


Lesenswert?

>So weit ich weiß sind Vergleiche eines beliebigen Werts X mit einem Wert
>Y der (2^n)-1 oder -(2^n) ist schneller als wie wenn Y beliebig ist.

Weil man bei diesen speziellen Werten möglicherweise nur 1 Bit 
vergleichen muss. Die modernen Prozessoren vergleichen immer 8, 16 oder 
mehr Bit auf einmal und da macht es keinen Unterschied mehr.

von Matthias L. (Gast)


Lesenswert?

>Der C-Code meiner Frage sieht also quasi so aus:
>Schnell: if(X => 512) {....} // Y = 2^9
>Langsam: if(X => 500) {....} // Y = 500

Ein 16bit Vergleich (cp, cpc) ist ein 16bit Vergleich. Das dauert immer 
gleich lange. Ist also egal, mit welcher (16bit) Zahl verglichen wird!

von Benedikt K. (benedikt)


Lesenswert?

Ich denke es hat einen anderen Grund:
Bei >= 512 muss mindestens Bit 9 oder ein höheres gesetzt sein. Es 
reicht also das high Byte auf >=2 zu Prüfen, es ist also ein 8bit 
Vergleich.
Bei >500 muss man dagegen auch das Lowbyte mit einbeziehen, also ist ein 
16bit Vergleich notwendig

von Johannes M. (johnny-m)


Lesenswert?

Benedikt K. wrote:
> Ich denke es hat einen anderen Grund:
> Bei >= 512 muss mindestens Bit 9 oder ein höheres gesetzt sein. Es
> reicht also das high Byte auf >=2 zu Prüfen, es ist also ein 8bit
> Vergleich.
> Bei >500 muss man dagegen auch das Lowbyte mit einbeziehen, also ist ein
> 16bit Vergleich notwendig
Nu ist der TMS470 aber ein 32-Bitter, wenn ich mich nicht ganz irre, und 
bei dem sollte es keinen Unterschied machen, ob ein 8-, 16- oder 
32-Bit-Vergleich...

Bei einer 8-Bit-Architektur stimme ich Dir zu, da muss bei solchen 
Vergleichen mit 2^n jeweils nur ein Bit in einem Byte überprüft werden.

von Benedikt K. (benedikt)


Lesenswert?

Johannes M. wrote:

> Vergleichen mit 2^n jeweils nur ein Bit in einem Byte überprüft werden.

Wiso schreiben das alle ? Das ist doch falsch !
Was ist wenn z.B. die Zahl den Wert 1024 hat ? Dann reicht es nicht das 
512er Bit zu prüfen, wenn man >= haben möchte !

von Michael G. (linuxgeek) Benutzerseite


Lesenswert?

right... *g
naja mein Hirn is heute nimmer so auf der Hoehe :D Natuerlich musste 
Bits, die hoeher sind da auch beruecksichtigen...

von Johannes M. (johnny-m)


Lesenswert?

Benedikt K. wrote:
>> Vergleichen mit 2^n jeweils nur ein Bit in einem Byte überprüft werden.
>
> Wiso schreiben das alle ? Das ist doch falsch !
> Was ist wenn z.B. die Zahl den Wert 1024 hat ? Dann reicht es nicht das
> 512er Bit zu prüfen, wenn man >= haben möchte !
Richtig, aber es muss trotzdem nur das High-Byte berücksichtigt werden 
(also nur ein Byte anstatt zweier)! Und das ist bei einer 
8-Bit-Architektur deutlich schneller als der Vergleich zweier Bytes. 
Aber wie gesagt: Bei einer 32-Bit-Architektur sollte es bei dem obigen 
Beispiel keinen Unterschied machen. Erst, wenn es an Werte > 32 Bit 
geht.

von Niels H. (monarch35)


Lesenswert?

Ein Vergleich wird mit Hilfe einer Substraktionsfunktion durchgeführt. 
Dabei wird Y von X abgezogen. Ist das Ergebnis 0, waren beide Werte 
gleich gross. Dementsprechend war X grösser Y, wenn es in der 
Subtraktion einen 0-Durchlauf (Carryflag) gegeben hat. usw.

Vergleiche finden also Hauptsächlich in der ALU statt. Die 
Verarbeitungsgeschwindigkeit gängt demnach von der Bitbreite der ALU ab. 
Nämlich ob diese die Werte in einem Rutsch verarbeiten kann oder ob 
dafür mehrere "Anläufe" nötig sind.

von Peter X. (vielfrass)


Lesenswert?

Habe einfach das mal Compiliert und angeschaut, was der Compiler daraus 
macht:
1
    62:         if(X >= 0)bla(); 
2
0x0008052C  E5950034  LDR       R0,[R5,#0x0034]
3
0x00080530  E59F41CC  LDR       R4,[PC,#0x01CC]
4
0x00080534  E3500000  CMP       R0,#0x00000000
5
0x00080538  BA000000  BLT       0x00080540
6
0x0008053C  EBFFFFD5  BL        bla(0x00080498)
7
    63:         if(X >= 512) bla(); // Y = 2^9 
8
0x00080540  E5950034  LDR       R0,[R5,#0x0034]
9
0x00080544  E3500C02  CMP       R0,#0x00000200
10
0x00080548  BA000000  BLT       0x00080550
11
0x0008054C  EBFFFFD1  BL        bla(0x00080498)
12
    64:         if(X >= 500) bla(); // Y = 500 
13
0x00080550  E5950034  LDR       R0,[R5,#0x0034]
14
0x00080554  E3500F7D  CMP       R0,#0x000001F4
15
0x00080558  BA000000  BLT       0x00080560
16
0x0008055C  EBFFFFCD  BL        bla(0x00080498)
17
    65:         if(X >= 0x12345)bla(); 
18
0x00080560  E5950034  LDR       R0,[R5,#0x0034]
19
0x00080564  E59F119C  LDR       R1,[PC,#0x019C]
20
0x00080568  E1500001  CMP       R0,R1
21
0x0008056C  BA000000  BLT       0x00080574
22
0x00080570  EBFFFFC8  BL        bla(0x00080498)
23
    66:         Port_init(); 
24
0x00080574  EBFFFF32  BL        Port_init(0x00080244)
25
26
27
28
29
0x00080700  00010514  DD        0x00010514
30
0x00080704  FFFFF460  DD        0xFFFFF460
31
0x00080708  00012345  DD        0x00012345
32
0x0008070C  000800FC  DD        0x000800FC
33
0x00080710  0008011C  DD        0x0008011C
Der Arm7 kann 8 Bit-Konstanten im Befehl enthalten haben, die dann um 
2,4,6,..32 Bits nach links geschoben werden können. Hier im Beispiel 
wird 0x7D durch zwei mal links schieben zu 0x1F4 gleich 500 dezimal.
Wenn der Wert so beliebig ist, das er nicht mit 8Bit und 2*N 
linksschieben erzeugt werden kann (0x12345), dann wird ein 32-Bit-Wert 
aus dem Programmspeicher gelesen. Das würde dann etwas länger dauern.

von Niels H. (monarch35)


Lesenswert?

Peter X. wrote:
> Habe einfach das mal Compiliert und angeschaut, was der Compiler daraus
> macht:

Wozu? Ich glaube, es ging eher um die prozessorinterne Verarbeitung als 
um Assemblercode.

> Wenn der Wert so beliebig ist, das er nicht mit 8Bit und 2*N
> linksschieben erzeugt werden kann (0x12345), dann wird ein 32-Bit-Wert
> aus dem Programmspeicher gelesen. Das würde dann etwas länger dauern.

Das ist abhängig von der internen Busbreite, aber im Prinzip ist davon 
auszugehen, das ein 32-Bit-Prozessor einen 8-BitWert genauso schnell 
einließt wie einen 32Bit-Wert; nämlich in einem Zyklus.

von Peter X. (vielfrass)


Lesenswert?

Niels Hüsken wrote:
> Das ist abhängig von der internen Busbreite, aber im Prinzip ist davon
> auszugehen, das ein 32-Bit-Prozessor einen 8-BitWert genauso schnell
> einließt wie einen 32Bit-Wert; nämlich in einem Zyklus.

Ja eben nicht, wie das Beispiel oben zeigt.
Bei einem 8-Bit-Wert kann dieser Teil des Befehles sein.
Bei einem 32-Bit-Wert ist ein extra Wort aus dem Programmspeicher zu 
lesen.

Die Befehle brauchen auch mehr als einen Zyklus, je nachdem ob sie auf 
dem Flash oder aus dem RAM geholt werden.

von yalu (Gast)


Lesenswert?

x >= C ist bei praktisch allen Prozessoren optimierbar, wenn C
konstant, C=m*2**n und n größer oder gleich der Wortbreite des
Prozessors ist. Dann kann die Anzahl der benötigten Compare-Befehle
auf Maschinenebene reduziert werden.

Ansonsten gibt es prozessorspezifische Optimierungsmöglichkeiten wie
das von Peter X. angeführte Beispiel für einen ARM.

von Daniel (Gast)


Angehängte Dateien:

Lesenswert?

Vielen Dank schon mal an alle die mir bislang geholfen haben!

Peter X. wrote:
> Bei einem 8-Bit-Wert kann dieser Teil des Befehles sein.
> ...
> Die Befehle brauchen auch mehr als einen Zyklus, je nachdem ob sie auf
> dem Flash oder aus dem RAM geholt werden.

...genau darauf zielt meine Frage ab!

Wie bereits schon richtig vermutet ist der TMS470 ist  ein 32 bitter 
(der ARM und THUMB unterstützt).

Eine Optimierung bei 2^n Werten hätte ich auch erst mal beim Compiler 
vermutet (wie ja der Assembler-Code auch zeigt), erst in zweiter Linie 
beim µC.

Leider bin ich jetzt irgendwie immer noch nicht wirklich schlauer, da ja 
die eigentliche Frage noch nicht ganz geklärt ist.

Ich hänge mal ein Datenblatt an dem ich an, vielleicht versteht ja einer 
mehr davon als ich...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.