PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Ergebnis einer ungültiger Rechnung erkennen?



fredyxx
09.07.2016, 05:51
Hallo,

wenn ich mir eine float-Variable auf dem Seriellen Monitor ansehe, die aber aus einer nicht möglichen Rechnung, z.B acos (1.2) entstanden ist, wird als Wert "nan" ausgegeben.
Wie kann ich diesen Wert, der ja kein float ist, in einem Arduino-Programm abfragen und als Fehler auswerten?

Gruß
fredyxx

i_make_it
09.07.2016, 07:08
NAN (Not a Number) und INFINITY (unendlich) sind schon die Auswertung auf Fehler. eigentlich würde bei einem Fehler 0.00 angezeigt werden. Da weis man aber nicht ob das ein Fehler ist oder ob da ein gültiges Ergebnis 0,00 steht.

Am besten also die selbe Auswertung machen die zur Anzeige von NAN führt.

http://forum.arduino.cc/index.php?topic=46912.0

HaWe
09.07.2016, 07:56
die Fehler muss man normalerweise vorher abfangen, indem man die Werte außerhalb der Definitionsbereiche der Funktion vorher ausschließt.

z.B. bei

float x, y;
y=1/x;
Serial.print(y);


muss es mathematisch und programmier-logisch richtig heißen:



float x, y;
if(x!=0) {
y=1/x;
Serial.print(y);
}
else {
Serial.print("ERROR! x=0 => NAN! Ungültiger Wertebereich!");
}

Genauso musst du deine x-Werte beim acos vorher prüfen und eingrenzen.

Andere Programmiersprachen benutzen dafür eine Konstruktion wie
try / catch / throw exception
etc., die genau solche Fehler durch interne Routinen abfangen.

In C geht das nicht, in C++ aber doch, ist aber nicht meine Baustelle.

try catch throw exception C++:
http://www.cplusplus.com/doc/tutorial/exceptions/
http://www.tutorialspoint.com/cplusplus/cpp_exceptions_handling.htm

Sisor
09.07.2016, 11:07
Im Arduino-Kontext sind die C++ Exceptions ausgeschaltet, u.a. weil die Implementierung von Exceptions größere Programme produziert.

HaWe
09.07.2016, 11:13
nur aus Interesse, C++ ist ja eh nicht mein Ding...

Im Arduino-Kontext sind die C++ Exceptions ausgeschaltet, u.a. weil die Implementierung von Exceptions größere Programme produziert.
tatsächlich? immer? oder nur bei AVRs?

Peter(TOO)
09.07.2016, 11:31
Hallo fredyxx ,

wenn ich mir eine float-Variable auf dem Seriellen Monitor ansehe, die aber aus einer nicht möglichen Rechnung, z.B acos (1.2) entstanden ist, wird als Wert "nan" ausgegeben.
Wie kann ich diesen Wert, der ja kein float ist, in einem Arduino-Programm abfragen und als Fehler auswerten?
Eigentlich sollte man VOR der Berechnung eine Plausibiltätsprüfung der Parameter vornehmen.
Da muss irgend etwas schief gegangen sein, wenn z.B. ein Divisor 0 ist.

Bei Ganzzahlrechnungen muss man auch aufpassen, dass Zwischenprodukte nicht überlaufen.

Grundsätzlich sind Fliesskomma-Berechnungen langsam. Bei vorhandener FPU etwa 2-5 mal langsamer als Integer-Berechnungen. Muss die FPU emuliert werden, ist man etwa 100x langsamer als eine FPU. Hinzu kommt noch der Speicherplatz für die Bibliothek.

In meinen µC-Projekten konnte ich FP immer umgehen, z.B. kann man Temperaturen in 1/100 Grad speichern, dann kann man alles mit Ganzzahlen berechnen und muss nur bei der Ausgabe das Komma reinflicken.
Für gebrochene Zahlen kann man Brüche verwenden. Anstatt
x*0.75 was FP benötigt
Kann man
(x*3)/4 rechnen, was dann mit Ganzzahlen geht. Aufpassen muss man nur, dass (x*3) keinen Überlauf erzeugt.

Bei Seriengeräten kann dies dann einiges ausmachen, wenn man einen kleineren und günstigeren µC einsetzen kann.

Auch komplizierte Berechnungen wie die Linearisierung eines NTCs und damit eines Feuchtesensors habe ich ganz ohne FP hin bekommen. OK, hat mich eine halben Tag Zeit gekostet um die Formeln entsprechend anzupassen, aber auf 1'000 Geräte umgelegt und beim µC gespart ...

MfG Peter(TOO)

HaWe
09.07.2016, 11:40
fredyxx ist Anfänger, aber wer sagt, dass er Geschwindigkeitsprobleme hat und nicht vlt sogar einen Arduino mit ARM-cpu hat, wo die float-Performance gar keine Rolle spielt?
Aber das ist ja eigentlich auch OT, denn die Frage war ja der Umgang mit NANs.
Und da braucht man entweder eine Programmiersprache, die die Fehler per Handles abfängt (C++ exceptions, geht aber wohl / ggf nicht bei Arduino) - oder man muss es korrekt selber machen, wie ich schon sagte:
denn eine Funktion ist mathematisch immer nur auf einem bestimmten Wertebereich definiert, und der muss dann durch das eigene Programm eben eingrenzt werden (ungleich Null, größergleich Null, ungleich pi/2 oder pi/4, kleiner 1 oder was auch immer).

Sisor
09.07.2016, 11:40
tatsächlich? immer? oder nur bei AVRs?
So weit ich weiss gilt das für alle Arduinos, definitiv auch für z.B. den DUE.

HaWe
09.07.2016, 11:49
ok, das ist mal wieder ne Einschränkung, die ziemlich dämlich ist, wenngleich sie auch mich nicht persönlich betrifft.... :(

Sisor
09.07.2016, 12:27
ok, das ist mal wieder ne Einschränkung, die ziemlich dämlich ist, wenngleich sie auch mich nicht persönlich betrifft.... :(Exceptions sind defaultmäßig aus, weil sie normalerweise nicht gebraucht werden. Ansonsten rede mit dem Compiler, er lässt sich (mittels Flag) überreden. :p

HaWe
09.07.2016, 12:28
Ansonsten rede mit dem Compiler, er lässt sich (mittels Flag) überreden.
DAS wäre dann vlt der richtige Tipp für fredyxx 8)

Sisor
09.07.2016, 13:04
Ich würde floats ggf. mit isnan() oder isinf() testen.
Hier ein Auszug aus Print.cpp des Arduino-Kerns:

if (isnan(number)) return print("nan");
if (isinf(number)) return print("inf");
if (number > 4294967040.0) return print ("ovf"); // constant determined empirically
if (number <-4294967040.0) return print ("ovf"); // constant determined empirically

Peter(TOO)
09.07.2016, 13:43
Ich würde floats ggf. mit isnan() oder isinf() testen.
Hier ein Auszug aus Print.cpp des Arduino-Kerns:

Eigentlich sind die Konstanten FLT_MAX und FLT_MIN, bzw. DBL_MAX und DBL_MIN und auch NAN in math.h definiert.

HaWe
09.07.2016, 13:57
sprichst du da als Arduino-Nutzer?
Wir reden ja hier von der Arduino-IDE, als Rat für einen Arduino-Nutzer - hast du's mal ausprobiert?

(müsste aber auch in <float.h> stehen, nicht in <math.h>, CMIIW - aber sag das mal nem Arduino-Anfänger, der sonst nie #includes benutzen muss... dann könnte es gehen mit FLT_MAX - was aber hier nicht das Problem ist...)

fredyxx
09.07.2016, 13:58
NAN (Not a Number) und INFINITY (unendlich) sind schon die Auswertung auf Fehler. eigentlich würde bei einem Fehler 0.00 angezeigt werden. Da weis man aber nicht ob das ein Fehler ist oder ob da ein gültiges Ergebnis 0,00 steht.

Am besten also die selbe Auswertung machen die zur Anzeige von NAN führt.

http://forum.arduino.cc/index.php?topic=46912.0

Danke für eure reichlichen Tipps!

Frage an i_make_it:

Die Info aus deinem Link habe ich so versucht umzusetzen:



#include <math.h>

void setup() {
Serial.begin (250000);
while (!Serial);
}

void loop() {

float x = acos(1.2);
int testFloat(float x);
if (x == NAN)
{
Serial.println("Mist");

}

Serial.println ( x);

}


Es kommt zwar der Text "nan" auf der Konsole, aber nicht "Mist".
Wenn ich es genau so wie im Link mache, klappt schon das Kompilieren nicht.

Gruß
fredyxx

HaWe
09.07.2016, 13:59
@fredyxx:
bevor du hier den Überblick verlierst...

ich würde es so machen wie hier beschrieben:
https://www.roboternetz.de/community/threads/69441-Ergebnis-einer-ung%C3%BCltiger-Rechnung-erkennen?p=629121&viewfull=1#post629121

fredyxx
09.07.2016, 14:31
@fredyxx:
bevor du hier den Überblick verlierst...

ich würde es so machen wie hier beschrieben:
https://www.roboternetz.de/community/threads/69441-Ergebnis-einer-ung%C3%BCltiger-Rechnung-erkennen?p=629121&viewfull=1#post629121

Danke,

das habe ich nicht übersehen, aber ich würde auch gerne die andere Variante kennen lernen.

Gruß

fredyxx

HaWe
09.07.2016, 15:19
dann ist es ntl ok ! :)

wie kommt es denn (nur aus Interesse), dass dein Programm einen verbotenen Wert für deinen acos generiert? Das dürfte doch eigentlich gar nicht passieren?

fredyxx
09.07.2016, 15:30
dann ist es ntl ok ! :)

wie kommt es denn (nur aus Interesse), dass dein Programm einen verbotenen Wert für deinen acos generiert? Das dürfte doch eigentlich gar nicht passieren?


Es ist eigentlich kein Problem. Aber wenn ich was dazu lernen kann, ist das ja auch gut.

Gruß
fredyxx

HaWe
09.07.2016, 17:01
alles klar, so gehts mir zur Zeit mit anderen Dingen auch ;)

- - - Aktualisiert - - -

ps:

zu deinem Code

if (x == NAN)
{
Serial.println("Mist");
}

Du kannst nicht x mit NAN vergleichen, NAN ist kein gültiger numerischer Wert.
Dass du nan auf dem Screen hast, ist die Folge dessen, dass du an Serial.print einen Wert übergibst, der als ungültig definiert ist, und daher gibt print von sich aus nan aus.

Daher kannst du auch mit if() keine Abfrage machen wie beim Exception-Handling mit try...catch - du musst die Exceptions von dir aus selber, manuell behandeln, wie schon von Sisor angedeutet

Ich würde floats ggf. mit isnan() oder isinf() testen.
d.h. z.B. versuchen per

if (isnan(x))
{
Serial.println("Mist");
}

, oder versuchen, per Flag die C++ Exceptions einzuschalten,
oder die gültigen/ungültigen Bereiche vorher auszuschließen, wie ich es getan habe..

fredyxx
09.07.2016, 17:33
Du kannst nicht x mit NAN vergleichen,

Hier wird das aber so gemacht! Daher mein Versuch

http://http://forum.arduino.cc/index.php?topic=46912.0 (http://forum.arduino.cc/index.php?topic=46912.0")

HaWe
09.07.2016, 18:27
ich persönlich bin nicht überzeugt, dass der Code valide ist, immerhin ist allerdings in Arduinisch einiges möglich, was sonst in C so nicht möglich ist.
Aber es ist ja auch C++ im Hintergrund: Wer weiß, welche Klassen da verdeckt eingeschlossen wurden, welche Exceptions da verdeckt ausgelöst werden, und was da privat oder public ist.
Die Tatsache, dass der Code bei dir aber nicht kompiliert wird, stützt zumindest meine Zweifel.

- - - Aktualisiert - - -

hier findet man weiterführende Erklärungen:

http://stackoverflow.com/questions/1923837/how-to-use-nan-and-inf-in-c



The existence of INFINITY is guaranteed by C99 (or the latest draft at least), and "expands to a constant expression of type float representing positive or unsigned infinity, if available; else to a positive constant of type float that overflows at translation time."

NAN may or may not be defined, and "is defined if and only if the implementation supports quiet NaNs for the float type. It expands to a constant expression of type float representing a quiet NaN."

Note that if you're comparing floating point values, and do:

a = NAN;

even then,

a == NAN;

is false. One way to check for NaN would be:

#include <math.h>
if (isnan(a)) { ... }

You can also do: a != a to test if a is NaN.

There is also isfinite(), isinf(), isnormal(), and signbit() macros in math.h in C99.

C99 also has nan functions:

#include <math.h>
double nan(const char *tagp);
float nanf(const char *tagp);
long double nanl(ocnst char *tagp);

fredyxx
10.07.2016, 10:29
Hallo,

das geht mir nun doch zu weit in die Tiefe.
Da es , wie ich oben schon sagte, für mich zZ kein Problem darstellt, möchte ich mich damit nicht weiter beschäftigen und euch auch nicht.

Danke

vG

fredyxx

HaWe
10.07.2016, 12:03
du hast Recht, es ist wirklich ein sehr ausgefallenes Spezial-Rand-Thema.
Normalerweise unmschifft man das Problem ungültiger Funktionswertbereiche eben anders, wie bereits beschrieben.

Übrigens ist wichtig für dich zu wissen:
C-Programme können durchaus absolut unbemerkt vom Beobachter Myriaden von nans bei Berechnungen produzieren, ohne dass das Programm irgendwie in welcher Weise auch immer auffällig wird (sich aufhängt, abstürzt, was auch immer)
- nur wenn du zufällig einen Wert genauer betrachten willst, und eine Ausgabe auf den Bildschirm machst, fällt dir plötzlich ein "nan" auf.

Selber schon erlebt, bei einem Benchmark-Test, der für manche Benchmarks auf manchen Systemen unglaublich (unglaubhaft) schnell lief.
Der Grund war, dass es zu nans kam, mit denen er einfach die folgenden Operationen nicht mehr durchgeführt hat, und daher war er damit ntl sehr schnell fertig und hat dann einfach die nächsten Programmschritte etwas früher als geplant in Angriff genommen... ;)

fredyxx
11.07.2016, 08:25
Interessanter Hinweis, danke.

vG

fredyxx