PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Fehler beim Multiplizieren? Weiß nicht mehr weiter!



Jacob2
22.12.2008, 18:10
Hallo,
Ich (eigentlich eher mein Programm) habe ein Problem und zwar folgendes:
Bei mir bewirken folgende Zeilen nicht dasselbe:

int ba = 6, tempo = 45, temp;
temp = 8505 - (ba * tempo);
for (i=0; i < temp; i++) {};



for (i=0; i < 8235; i++) {};


Wie kann das sein? Wenn ich rechne, müsste jedesmal gleichlang gewartet werden!

vohopri
22.12.2008, 18:49
Hallo,

1. was genau steht in {} bei der Ausführung?

2. wie schaut das Compilat dieser Schleife (der Assemblercode vom Debugger) in beiden Fällen aus? Ganz das gleiche wird nicht gemacht. einmal wird eine Variable ausgewertet und einmal eine Konstante, die anders abgespeichert sein kann.

3. Welchen Typ hat temp?

grüsse,
vohopri

Dirk
22.12.2008, 18:54
Hallo Jacob2,

es sind ja auch nicht identische Schleifen.
Die Endebedingung (i < ...) testet beim ersten Mal 2 Variablen (i, temp) gegeneinander, beim zweiten Mal eine Variable (i) gegen eine Konstante (8235).

Die Schleifen sind also nicht identisch.

Wenn sie dann auch noch zum WARTEN benutzt werden, dann produzieren sie eben verschiedene Ablaufzeiten.

Gruß Dirk

radbruch
22.12.2008, 18:59
Wie ist diese Variante?

temp=8235;
for (i=0; i < temp; i++) {};

War mal wieder zu langsam :)

Dirk
22.12.2008, 19:24
War mal wieder zu langsam :)
Obwohl: Der Hai erwischt dich ja (bis jetzt) nie ... O:)

Gruß Dirk

Jacob2
22.12.2008, 19:59
@vohopri
1. Da steht nichts, es soll nur gewartet werden.
2. Ich weiß nicht wo man das sehen kann.
3. temp ist ein Integer

@Dirk Die Variable hat aber den selben Wert wie die Konstante! Identisch sind sie natürlich nicht, aber sie müssten doch gleich lange dauern oder?

@radbruch Es passiert das selbe, es muss daran liegen, dass es einmal eine Zahl und einmal eine Variable ist!

Hat vielleicht noch jemand eine Idee, es soll nämlich ein Weihnachtsgeschenk werden :frown:

vohopri
22.12.2008, 20:16
Das ist es ja: der selbe wert wird von unterschiedlichen Speichern geholt - abhängig davon, obs eine Variable oder eine Kostante ist. Und das braucht unterschiedlich viel Zeit. Wenn zwei verschieden lang dauernde Vorgänge gleich oft durchführst, dann dauerts unterschiedlich lang.

Mit einem Debugger, der den Assemblercode anzeigt, wäre das gut sichtbar.

grüsse,
v.

Besserwessi
22.12.2008, 20:19
Ohne optimierung wird ein anderer vergleich durchgeführt. Da kannes schon mal zu etwas anderen Laufzeiten kommen. Mit optimierung könnte in beiden Fällen nichts passieren, denn die Schleife könnte komplett wegoptimiert werden, wenn die variable i danach nicht gelesen wird. Eher unwahrscheinlich ist der Fall, dass die optimierung davon abhängt ob da eine Variable oder Konstante steht.

lorcan
22.12.2008, 20:21
Ich denke eher bei der Konstanten schlägt die Optimierung des Kompilers zu, der lässt nämlich ein Warten auf Konstanten nicht unbedingt zu.
Radbruchs Variante sollte dein Problem lösen.
Evtl. noch ein Semikolon in die FOR-Schleife.
Gruß
Lorcan

radbruch
22.12.2008, 20:56
Keine Ahnung wie der Kompiler das anstellt:

int main(void)
{
int i;
int ba = 6, tempo = 45, temp;
temp = 8505 - (ba * tempo);
// Schleife1 Anfang
for (i=0; i < temp; i++) {};
// Schleife 1 Ende
// Schleife2 Anfang
for (i=0; i < 8235; i++) {};
// Schleife2 Ende
while(1);
return(0);
}
Wird bei mir zu

0000005c <main>:
int main(void)
{
5c: cf e5 ldi r28, 0x5F ; 95
5e: d4 e0 ldi r29, 0x04 ; 4
60: de bf out 0x3e, r29 ; 62
62: cd bf out 0x3d, r28 ; 61
64: 8a e2 ldi r24, 0x2A ; 42
66: 90 e2 ldi r25, 0x20 ; 32
int i;
int ba = 6, tempo = 45, temp;
temp = 8505 - (ba * tempo);
// Schleife1 Anfang
for (i=0; i < temp; i++) {};
68: 8d 97 sbiw r24, 0x2d ; 45
6a: 97 ff sbrs r25, 7
6c: fd cf rjmp .-6 ; 0x68 <main+0xc>
6e: 8a e2 ldi r24, 0x2A ; 42
70: 90 e2 ldi r25, 0x20 ; 32
// Schleife 1 Ende
// Schleife2 Anfang
for (i=0; i < 8235; i++) {};
72: 8d 97 sbiw r24, 0x2d ; 45
74: 97 ff sbrs r25, 7
76: fd cf rjmp .-6 ; 0x72 <main+0x16>
// Schleife2 Ende
while(1);
78: ff cf rjmp .-2 ; 0x78 <main+0x1c>
Identischer Code! 68-6c bzw. 72-76, hier mein Output beim Kompilieren:

rm -f test.hex
rm -f test_eeprom.hex
rm -f test.elf
rm -f test.map
rm -f test.cof
rm -f test.lst
rm -f temp.lst
rm -f temp.o
avr-gcc -mmcu=atmega8 -Os -mno-interrupts -funsigned-char -funsigned-bitfields -Wall -Wstrict-prototypes -ggdb -c -DF_CPU=8000000UL -Wa,-acdhlmns=temp.lst temp.c -o temp.o
avr-gcc -mmcu=atmega8 -Os -mno-interrupts -funsigned-char -funsigned-bitfields -Wall -Wstrict-prototypes -ggdb temp.o -o test.elf -Wl,-Map=test.map --cref -lm
avr-objcopy -j .text -j .data -O ihex test.elf test.hex
avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex test.elf test_eeprom.hex
avr-objdump -d -S test.elf > test.lst
0
Verblüffend.

SprinterSB
22.12.2008, 21:05
Solche Schleifen haben keinen Effekt auf die Maschine. Ergo: Ein optimierender Compiler wie GCC kann das *komplett* in die Tonne kloppen.

radbruch
22.12.2008, 21:10
Bei mir wurden die Schleifen ja offensichtlich nicht wegrationalisiert.

Ich verwende Optimierung: Size (Größe). Bei beiden Schleifen wird vor der Schleife der Vergleichswert in R24/25 gespeichert. Das hätte ich nicht erwartet, aber ich bin ja auch Kompilerlaie :)

Normalerweise verzögere ich so:

int count, dummy;
for(count=0; count<1234; count++) dummy^=count;

Das exclusive OR bremst die Schleife zusätzlich und wird nicht wegoptimiert.

Ach, noch was:

int ba = 6, tempo = 45, temp;
temp = 8505 - (ba * tempo);

temp ist hier für den Kompiler ja eigentlich auch 'ne Konstante, oder? Weil an dieser Stelle des Programms ba und tempo vor der Zuweisung von temp nicht verändert werden kann ein schlauer Kompiler hier ohne Rechnung direkt das Ergebniss als Konstante ablegen. Deshalb wird wohl vor Adresse 62 auch nichts multipliziert oder subtrahiert.

Besserwessi
22.12.2008, 23:33
Wenn der Compiler mit den Konstaten so gut ist, fragt sich, wieso die Schleifen nicht ganz wegfallen. Das einzige was sich tut is da i verändert wird, aber i wird danach ja gar nicht weiter genutzt. Wenn der Compiler noch etwas besser wird könnter er die schleifen wirklich weglassen.

SprinterSB
23.12.2008, 00:38
Wenn der Compiler mit den Konstaten so gut ist, fragt sich, wieso die Schleifen nicht ganz wegfallen. Das einzige was sich tut is da i verändert wird, aber i wird danach ja gar nicht weiter genutzt. Wenn der Compiler noch etwas besser wird könnter er die schleifen wirklich weglassen.

So ist es. Und dann wundert man sich, daß nix mehr geht...

Wenn man wiklich Warteschleifen braucht, dann gibt's das Zeug aus util/delay.h (Doku siehe Doku zur avr-libc, ist bei WinAVR anbei) oder sowas

http://www.mikrocontroller.net/topic/120146

Falls es unbedingt handgeklöppelt sein soll, muss man dem Compiler sagen, daß er die Schleife nicht wegwerfen darf. Das geht zB so:


for (i=0; i < 1000; i++)
asm volatile (""::);


Aber selbst dann muss es nicht eine Schleife sein, der Compiler könnte die Schleife aufrollen in 1000 leere Inline-ASM-Zeilen...

Mir fällt wirklick keine Möglichkeit ohne Inline-Assembler ein, die /garantiert/ zu einer Schleife wird. Weder for noch goto-Konstrukte.

Wenns um Verzögerung geht, wohl sowas:


for (i=0; i < 1000; i++)
asm volatile (" ":"=r"(i):"0"(i));

Aber auch das kann (teilweise) aufgerollt werden; selbst wenn die Anzahl der Durchläufe nicht zur Compilezeit bekannt ist.

Jacob2
23.12.2008, 09:04
Bei dem Link oben von SprinterSB wird immer von Ticks geredet. Ist das jeweils ein Takt? Der ATmega8 wird glaub ich mit 1MHz ausgeliefert, sind das die Ticks?

SprinterSB
23.12.2008, 10:18
Bei einem Takt von 1MHz vergehen in 1 Sekunde 1000000 Ticks.

Bei einem Takt von x MHz vergehen in 1 Sekunde x*1000000 Ticks.

Jacob2
23.12.2008, 10:35
ok danke! Ich nehm jetzt aber doch _delay_ms/us