Go Down

Topic: Einfache Rechenoperation schlägt fehl und ich verstehe nicht warum (Read 683 times) previous topic - next topic

RURon

Hallo zusammen!

Ich habe ein "komisches" Problem. Ich berechne eine Anzahl an Millisekunden, die mein Sketch an einer Stelle warten soll, erhalte aber ein völlig unerwartetes Ergebnis. Das komische ist dabei, dass der Code z.B. bei Ideone.com kompiliert korrekt läuft.

Von daher tippe ich auf "irgendeine" Besonderheit auf dem Arduino Nano, den ich hierfür nutze. Vielleicht kann es mir jemand erklären, damit ich nicht dumm sterben muss :-)

Hier ein Beispielcode:

Code: [Select]

void loop() {
  unsigned long waittime;
  int seconds;
  seconds=6;
  waittime=(60-seconds)*1000;
  Serial.print("waiting milliseconds:");
  Serial.println(waittime);
  delay(2000);
}


In diesem (zur Veranschaulichung vereinfachten) Beispiel sollte als Ergebnis in waittime eigentlich 54000 stehen (also 54 Sekunden). Es wird aber 4294955760 berechnet ?! (was ganz nebenbei dann also knapp 50 Tage Wartezeit wären :-) )

Ich habe nach diesem Fehler jetzt ziemlich lange gesucht und den zum Glück gefunden und auch beheben können, indem ich die Rechenoperation

Code: [Select]
waittime=(60-seconds)*1000;

aufteile in


Code: [Select]

waittime=60-seconds;
waittime=waittime*1000;


Vielleicht kann mir das jemand erklären, würde mich sehr freuen!

Schönen Sonntag noch!

RURon.

Tommy56

Schreib mal
Code: [Select]

waittime=(60UL-seconds)*1000;

damit wird die Rechnung von vornherein auf der Basis von (unsigned) long gemacht.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

uxomm

Das fällt unter die Rubrik "Lustiges Rechnen mit C und C++"  :) :)

Ich glaube da stolpert jeder mal.
Ist nichts angegeben, dann sind alle Literale in Rechenoperationen mal Int.
Weil aber deine Variable  seconds ebenfalls int ist, sind auf der rechten Seite bei
Code: [Select]
waittime=(60-seconds)*1000;
nur Ints und deshalb wird auch nur in ints gerechnet.
Und leider ist es C/C++ eher egal ob da links ein unsigned log steht oder nicht.
Es wird also mit Int gerechnet und diese Variable läuft in deinem Fall über.

Es gibt mehrere Möglichkeiten das zu lösen, es reicht wenn links eine Zahl mit der gerechnet wird unsigned long ist z.B.:
Code: [Select]
waittime=(60-seconds)*1000UL;
(wurde ja schon von Tommy56 erwähnt)
oder du kannst sekunden ebenfalls als unsigned log deklarieren.
Always decouple electronic circuitry.

jurs

Vielleicht kann mir das jemand erklären, würde mich sehr freuen!
RURon.
Du dürftest einen Integer-Überlauf in der Zeile " waittime=(60-seconds)*1000;" bekommen.

Denn 60, seconds und 1000 sind jeweils Integer-Werte, daher erzeugt der Compiler Code für eine Integer-Berechnung. Wenn dabei ein int-Überlauf auftritt, ist das Ergebnis als int möglicherweise eine negative Zahl, und wenn Du die negative int-Zahl an eine unsigned long zuweist, wird daraus eine sehr große unsigned long Zahl.

Versuche mal die Rechnung mit long-Werten (an die Zahlenkonstante ein L dranhängen:
Code: [Select]
waittime=(60L-seconds)*1000L;

RURon

Hach ist das schön, dass hier so viele nette und aufmerksame und schnell antwortende Hilfe kommt...!

Vielen vielen Dank!

Jetzt erstmal nen Espresso und dann weiter coden!

Go Up