Forum: Mikrocontroller und Digitale Elektronik Ungültige Integer


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,

generell ist es verpönt, Werte und Status-Daten in einer Variable 
miteinander zu mischen. Für meinen aktuellen Anwendungsfall ist aber 
alles andere noch schlimmer, also Augen zu und durch. Außerdem ist es 
bei den Fließkommazahlen mit NaNs auch üblich.

Banal ist es jetzt einfach so, dass INT_MIN aus dem Pool der gültigen 
Werte entfernt wurde und ungültige Daten markiert.

Eine der einfachsten denkbaren Operation wäre dann die sättigende 
Multiplikation mit signalisierendem magischen Wert.
1
/** Saettingende warnende Multiplikation (32 Bit)
2
 *
3
 * Ist einer der Multiplikanten INT32_MIN, ist das Ergebnis auch INT32_MIN.
4
 * Ansonsten wird auf den Wertebereich -INT32MAX ... INT32_MAX gesaettigt.
5
 *
6
 * @param[in] a, b: Multiplikanten
7
 * @return: Produkt/INT32_MAX/INT32_MIN  */
8
static_inline int32_t satmulwarn_s32(int32_t fac1, int32_t fac2)
9
{
10
    if( a != INT32_MIN && b != INT32_MIN )
11
    {
12
        int64_t p = (int64_t) fac1 * fac2;
13
        CLAMP(p, INT32_MIN+1, INT32_MAX);
14
        return p;
15
    }
16
    else
17
    {
18
        return INT32_MIN;
19
    }
20
}
Ich bin mir ziemlich sicher, dass ich nicht der erste bin, der sich 
soetwas ausdenkt. Also hat das Vorgehen wohl einen Namen. Kennt jemand 
einen recherchierbaren Namen für ein solches Vorgehen?

(Ich hätte auf etwas wie "signaling value" oder so getippt, aber das 
scheint ein Begriff aus der Soziologie zu sein.)

: Bearbeitet durch User
von Der Opa aus der Muppet Show (Gast)


Lesenswert?

So etwas war früher ganz normal.

Schau dir z.B. das getc(FILE*) an. Statt einer char liefert es eine int, 
die alle alten 8bit Zeichen und zusätzlich EOF enthalten kann.

Damals hatte halt jeder ganz pragmatisch irgend etwas genommen, was ihm 
in diesem Augenblick am einfachsten erschien. Erst später, als Sprachen 
wie Rust diesen chaotischen Wildwuchs aufräumten, suchten die Entwickler 
Namen für ihre Strategie.

von Georg (Gast)


Lesenswert?

Walter T. schrieb:
> Ich bin mir ziemlich sicher, dass ich nicht der erste bin, der sich
> soetwas ausdenkt

Aber vielleicht der erste, der dafür eine Multiplikation braucht. Wer 
nicht unendliche Rechenleistung zur Verfügung hat wird Bitoperationen 
benutzen.

Georg

von Walter T. (nicolas)


Lesenswert?

Der Opa aus der Muppet Show schrieb:
> Erst später, [...] suchten die Entwickler Namen für ihre Strategie.

Ja, genau. Wir haben heutzutage später. Zu einem Konzept einen Namen zu 
kennen erlaubt einem den Zugang zu einem großen Schatz an Wissen und 
Fehlern, die man nicht mehr alle selbst machen muss und zu verwandten 
Konzepten.

Georg schrieb:
> Aber vielleicht der erste, der dafür eine Multiplikation braucht.

Ich glaube nicht, dass ich darauf ein Patent anmelden können würde.

Wo bleibt die C++-Fraktion mit einem Satz wie "Jaaa, das ist die 
eiblisitc*)-class, bei der alle Operatoren überladen sind und die ab 
C++25 zum Standardumfang gehören wird!!! Hier <LINK> gibt es eine tolle 
Diskussion dazu!"

*) Steht für "every integer behaves like it should in this context"

: Bearbeitet durch User
von Michael D. (nospam2000)


Lesenswert?

> Also hat das Vorgehen wohl einen Namen. Kennt jemand
 > einen recherchierbaren Namen für ein solches Vorgehen?

wie wäre es mit https://en.wikipedia.org/wiki/Saturation_arithmetic

bzw. mit dem darin erwähnten 
https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html :
1
Built-in Function: bool __builtin_mul_overflow (type1 a, type2 b, type3 *res)
2
Built-in Function: bool __builtin_smul_overflow (int a, int b, int *res)
3
Built-in Function: bool __builtin_smull_overflow (long int a, long int b, long int *res)
4
Built-in Function: bool __builtin_smulll_overflow (long long int a, long long int b, long long int *res)
5
Built-in Function: bool __builtin_umul_overflow (unsigned int a, unsigned int b, unsigned int *res)
6
Built-in Function: bool __builtin_umull_overflow (unsigned long int a, unsigned long int b, unsigned long int *res)
7
Built-in Function: bool __builtin_umulll_overflow (unsigned long long int a, unsigned long long int b, unsigned long long int *res)

  Michael

von Oliver S. (oliverso)


Lesenswert?

Walter T. schrieb:
> Zu einem Konzept einen Namen zu
> kennen

https://en.wikipedia.org/wiki/Nullable_type

Oliver

von Walter T. (nicolas)


Lesenswert?

Michael D. schrieb:
> wie wäre es mit https://en.wikipedia.org/wiki/Saturation_arithmetic

Das ist die eine Hälfte. Ob jetzt die builtins für sättigende Arithmetic 
besser sind als breiter rechnen und dann klemmen habe ich noch nicht 
getestet, weil die ganze Geschichte in einem nicht-zeitkritischen 
Code-Teil liegt. Die Builtins sind schon schnell, aber das Vorzeichen 
muss dann wieder separat erzeugt werden. Ohne Benchmarks ist das 
wahrscheinlich nicht zu entscheiden, was besser geht.

Die andere Hälfte ist die Fehlersignalisierung mittels magischem Wert 
(hier: INT_MIN, der sich angeboten hat).

Nachtrag:

Oliver S. schrieb:
> https://en.wikipedia.org/wiki/Nullable_type

Das ist wohl die zweite Hälfte. Also habe ich wohl einen "nullable 
saturating integer". Oder "saturating nullable integer"? Aber das klingt 
vielversprechend. Oder eine "saturating operation on nullable Integer". 
Jetzt kann ich meinen Teil der Literaturarbeit weitermachen.

Danke für die brauchbaren Stichwörter!

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Walter T. schrieb:
> (Ich hätte auf etwas wie "signaling value" oder so getippt, aber das
> scheint ein Begriff aus der Soziologie zu sein.)

Mit "sentinel value" oder "Wächterwert" kommt man weiter.

Eine übliche Namenskonvention für Funktionen in C, die Wächterwerte 
berücksichtigen, habe ich noch nicht gefunden.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

In meinen Augen ist das Hackercoding der übelsten Sorte. Sowas sollte 
man sich nicht als Beispiel nehmen.

NaN bedeutet oft ein Speicherfehler (Pointer zeigt in den Wald). Da 
Speicherfehler immer kritisch sind, sollte NaN nicht absichtlich 
verwendet werden.

Will man einen Fehlerstatus kennzeichnen, nimmt man dafür eine Variable.
Man kann aber auch ein Struct returnieren, was aus Rückgabewert und 
Status besteht.

von Walter T. (nicolas)


Lesenswert?

Peter D. schrieb:
> NaN bedeutet oft ein Speicherfehler

Da sind wir wohl in verschiedenen Welten. In meiner anderen Welt 
bedeutet "NaN" zu 99% "Variable kann nicht in double konvertiert werden" 
oder "Gleichungssystem kann aufgrund der Konditionszahl nicht gelöst 
werden" - sprich: Inf, -Inf, NaN und -NaN sind Werte, die in einem 
fehlerfreien Programm vorkommen können. Aber das ist nicht C und auch 
nicht µC.


Peter D. schrieb:
> der übelsten Sorte.

Ich bin darüber auch nicht maximal glücklich, aber die anderen Lösungen 
sind m.E. schlimmer. Eine zweite Variable mitnehmen oder eine globale 
Fehlervariable setzen ist etwas mühsamer threadsicher zu bekommen. (Mein 
eigentliches Ziel ist es, Sensordaten aus einer ISR in die Hauptschleife 
zu bekommen. Der Fehler ist zu 99,8% timeout wegen nicht angeschlossenem 
Sensor und zu 0,2% das ungültige halb empfangene Datentelegramm am 
Start.)

Peter D. schrieb:
> Will man einen Fehlerstatus kennzeichnen, nimmt man dafür eine Variable.

Ich wäre sehr dankbar für jeden Literaturtipp (auch Quelltext) zum Thema 
"sauberere Fehlerbehandlung in C auf dem µC.

: Bearbeitet durch User
von PittyJ (Gast)


Lesenswert?

So in der Art hätte ich das auch gemacht:

Built-in Function: bool __builtin_mul_overflow (type1 a, type2 b, type3 
*res)

Bei allem anderen fängt man sich später nur Probleme ein, weil man an 
die Sonderrückgaben nicht mehr denkt. Oder die Architektur den INT_MIN 
anders definiert, oder oder oder ....

Dan lieber gleich richtig. Einen Parameter mehr und gut ist es.

von Egon D. (Gast)


Lesenswert?

Walter T. schrieb:

> Eine der einfachsten denkbaren Operation [...]

.... um WAS zu erreichen?

von Egon D. (Gast)


Lesenswert?

Peter D. schrieb:

> Will man einen Fehlerstatus kennzeichnen, nimmt man
> dafür eine Variable. Man kann aber auch ein Struct
> returnieren, was aus Rückgabewert und Status besteht.

Bei Rückgabewerten kein Problem.

Wenn aber größere Mengen solcher Daten irgendwo zu
puffern sind, wird das halt ganz schöne Verschwendung.

von Walter T. (nicolas)


Lesenswert?

Peter D. schrieb:
> Will man einen Fehlerstatus kennzeichnen, [...]

Die Implikation habe ich eben überlesen. Ich sehe einen ungültigen Wert 
nicht als Fehler, genauwenig wie ich einen leeren String oder das Ende 
einer Datei als Fehler sehe.

Wahrscheinlich bin ich deshalb auch gar nicht auf die Idee gekommen, das 
als Fehlerbehandlung zu betrachten.

Egon D. schrieb:
> .... um WAS zu erreichen?

Um eine Variable weiterzuverarbeiten, ohne dass der Status-Wert verloren 
geht.

von Ulrich (Gast)


Lesenswert?

Walter T. schrieb:
> (Mein
> eigentliches Ziel ist es, Sensordaten aus einer ISR in die Hauptschleife
> zu bekommen. Der Fehler ist zu 99,8% timeout wegen nicht angeschlossenem
> Sensor und zu 0,2% das ungültige halb empfangene Datentelegramm am
> Start.)

dann übergebe halt nur gültige Werte in deine MAIN....
solange die Sensordaten ungültig sind gibt es keine neuen
1
ISR()
2
{
3
  if(data_valid & mutex_free)
4
  {
5
    global_sensor_data = sensor_data;
6
    global_sensor_flag = true;
7
  }
8
}
9
10
main()
11
{
12
  while(1)
13
  {
14
    if(global_sensor_flag)
15
    {
16
      mutex_free = false;
17
      local_data = global_sensor_data;
18
      global_sensor_flag = false;
19
      mutex_free = true;
20
    }    
21
  }
22
}

das ist auch thread sicher

von Egon D. (Gast)


Lesenswert?

Walter T. schrieb:

> Ich sehe einen ungültigen Wert nicht als Fehler,
> genauwenig wie ich einen leeren String oder das
> Ende einer Datei als Fehler sehe.

Diese Fälle sind nicht vergleichbar, sondern aus
mathematischen bzw. logischen Gründen wesensverschieden.


> Egon D. schrieb:
>> .... um WAS zu erreichen?
>
> Um eine Variable weiterzuverarbeiten, ohne dass der
> Status-Wert verloren geht.

Der Status-Wert "ungültig" sagt, dass keine Belegung
vorliegt, die dem Wertebereich der Variablen angehört.

Wie sinnvoll es ist, mit einem Algorithmus Werte zu
verarbeiten, für die der Algorithmus überhaupt nicht
definiert ist, kannst Du Dir vielleicht selbst
überlegen.

Du kommst mir wie ein Schüler vor, der "einfach Unendlich
durch Unendlich teilen" will. Jeder Mathematiker antwortet
darauf, dass Unendlich keine reelle Zahl ist, durch die
man so einfach teilen darf.

von Egon D. (Gast)


Lesenswert?

Ulrich schrieb:

> dann übergebe halt nur gültige Werte in deine MAIN....
> solange die Sensordaten ungültig sind gibt es keine neuen

Ungünstig, wenn der folgende Algorithmus von gleichmäßiger
Abtastung ausgeht...

Immer Wert und Zeitstempel abzuspeichern vergrößert den
Speicherbedarf beträchtlich.

von Ulrich (Gast)


Lesenswert?

Egon D. schrieb:
> Ungünstig, wenn der folgende Algorithmus von gleichmäßiger
> Abtastung ausgeht...

und wo hat der TO dieses Requirement gestellt?

von Walter T. (nicolas)


Lesenswert?

Ulrich schrieb:
> dann übergebe halt nur gültige Werte in deine MAIN....
> solange die Sensordaten ungültig sind gibt es keine neuen

Ist das (inkl. Quelltext) als Scherz oder sokratisches Argument gemeint? 
Es ist komplizierter. Es muss eine Extra-Initialisierung für Start bei 
ungültigem Wert vorgesehen werden. Die main()-Funktion merkt gar nicht, 
wenn der "aktuell gültige" Wert schon uralt ist. Das sieht auf den 
ersten Blick eher wie ein Antipattern aus.
1
int32_t value = INT_MIN;
2
int32_t lastValid = INT_MIN;
3
const int32_t scaling = 25400;
4
const int32_t offset = 30;
5
6
ISR()
7
{
8
    int32_t temp;
9
    bool isValid = getSensor(&temp);
10
    if( isValid )
11
    {
12
        value = temp;
13
        lastValid = temp;
14
    }
15
    else
16
    {
17
        value = INT32_MIN;
18
    }  
19
}
20
main()
21
{
22
    while(1)
23
    {
24
         int32_t len = satmulwarn_s32(value, scaling);
25
         len = sataddwarn_s32(len, offset);
26
         if( len != INT32_MIN ) display(len);
27
         else display("error");
28
         
29
         doWhatYouWantWith(lastValid);
30
    }
31
}

Das ist einfacher, lockfrei, main() weiß, ob die gültigen Daten aktuell 
sind, es gibt keine Initialisierungsprobleme. Ich darf nur nicht auf die 
dumme Idee kommen, aus "lastValid" auf irgendeine Eigenschaft von 
"valid" schließen zu wollen.

Nicht gegen Mutexe in Kontexten, wo ein solches Konstrukt wirklich nötig 
ist. Aber hier?

Egon D. schrieb:
> Wie sinnvoll es ist, mit einem Algorithmus Werte zu
> verarbeiten, für die der Algorithmus überhaupt nicht
> definiert ist, kannst Du Dir vielleicht selbst
> überlegen.

Warum sollte man einen Algorithmus so designen, dass er mit 
vorhersehbaren Werten nicht klarkommt?

: Bearbeitet durch User
von Ulrich (Gast)


Lesenswert?

Walter T. schrieb:
> Nicht gegen Mutexe in Kontexten, wo ein solches Konstrukt wirklich nötig
> ist. Aber hier?

was ist denn dein Ziel system?

falls es ein 8bit Microcontroller ist (was dieses Forum nahelegt)
ist dein code buggy

von Walter T. (nicolas)


Lesenswert?

Ulrich schrieb:
> falls es ein 8bit Microcontroller ist (was dieses Forum nahelegt)
> ist dein code buggy

Es ist natürlich ein 32Bitter, sonst wäre der Code buggy.

Egon D. schrieb:
> Jeder Mathematiker antwortet
> darauf, dass Unendlich keine reelle Zahl ist, durch die
> man so einfach teilen darf.

Und jeder Numeriker wird Dir sagen, dass "unendlich" ein Wert ist, mit 
dem Dein Programm gefälligst klarzukommen hat.

von Ulrich (Gast)


Lesenswert?

Walter T. schrieb:
> Es ist natürlich ein 32Bitter

natürlich

von Melba (Gast)


Lesenswert?

Walter T. schrieb:
> Ulrich schrieb:
>> falls es ein 8bit Microcontroller ist (was dieses Forum nahelegt)
>> ist dein code buggy
>
> Es ist natürlich ein 32Bitter, sonst wäre der Code buggy.
>
> Egon D. schrieb:
>> Jeder Mathematiker antwortet
>> darauf, dass Unendlich keine reelle Zahl ist, durch die
>> man so einfach teilen darf.
>
> Und jeder Numeriker wird Dir sagen, dass "unendlich" ein Wert ist, mit
> dem Dein Programm gefälligst klarzukommen hat.

Jeder Psychiater würde euch sagen, dass ihr Nullen seid.

von Egon D. (Gast)


Lesenswert?

Ulrich schrieb:

> Egon D. schrieb:
>> Ungünstig, wenn der folgende Algorithmus von
>> gleichmäßiger Abtastung ausgeht...
>
> und wo hat der TO dieses Requirement gestellt?

Nun, der TO hat davon gesprochen, dass es ihm um die
Übergabe von Sensorwerten aus einer ISR an das
Hauptprogramm geht, und eine denkbare Interpretation
dieser Worte ist, dass die ISR am Timer-Interrupt
hängt.

Das war zumindest das Bild, das sich mir aufdrängte.

von Walter T. (nicolas)


Lesenswert?

Ulrich schrieb:
> dann übergebe halt nur gültige Werte in deine MAIN....
> solange die Sensordaten ungültig sind gibt es keine neuen
> ISR()
> {
>   if(data_valid & mutex_free)
>   {
>     global_sensor_data = sensor_data;
>     global_sensor_flag = true;
>   }
> }
> main()
> {
>   while(1)
>   {
>     if(global_sensor_flag)
>     {
>       mutex_free = false;
>       local_data = global_sensor_data;
>       global_sensor_flag = false;
>       mutex_free = true;
>     }
>   }
> }
>

So langsam wird es off-Topic, aber: Fehlt hier nicht eine 
Memory-Barrier? (Unter der Annahme, dass die drei globalen Variablen 
volatile sind und die Schreib- und Lesereihenfolge nicht vertauscht 
werden kann.)
1
ISR()
2
{
3
  if(data_valid & mutex_free)
4
  {
5
    global_sensor_data = sensor_data;
6
    /* Wenn global_sensor_data _und_ global_sensor_flag volatile, ist hier 
7
       keine memory barrier noetig, da ISR nicht unterbrochen wird */ 
8
    global_sensor_flag = true;
9
  }
10
}
11
main()
12
{
13
  while(1)
14
  {
15
    if(global_sensor_flag)
16
    {
17
      mutex_free = false;
18
      local_data = global_sensor_data;
19
      global_sensor_flag = false;
20
    /* Memory Barrier erforderlich? */
21
      mutex_free = true;
22
    }
23
  }
24
}
Ich habe ehrlich gesagt noch nie etwas mit Mutexen programmiert. Bislang 
habe ich immer Doppelpufferstrategien bevorzugt.

von Egon D. (Gast)


Lesenswert?

Walter T. schrieb:

> Egon D. schrieb:
>> Jeder Mathematiker antwortet darauf, dass Unendlich
>> keine reelle Zahl ist, durch die man so einfach teilen
>> darf.
>
> Und jeder Numeriker wird Dir sagen, dass "unendlich"
> ein Wert ist, mit dem Dein Programm gefälligst
> klarzukommen hat.

Moment.

Erstens macht Deine Entgegnung meine Aussage nicht
falsch.

Zweitens hat Deine Entgegnung nix mit dem konkreten
Problem zu tun, das Du geschildert hast.

Daten im Speicher sind ja erstmal nur Binärvektoren;
deren Interpretation als ganze oder natürliche Zahlen
ist zwar üblich und sinnvoll, aber keineswegs zwingend.
Es ist daher absolut zulässig zu definieren: "Jene
Belegung des Binärvektors signalisiert einen ungültigen
Zahlenwert, und für alle anderen Belegungen wird der
Binärvektor nach der üblichen Vorschrift in eine ganze
Zahl umgewandelt."
Das ist mathematisch völlig sauber.

Unsinnig wird es ab dem Punkt, wo Du die "üblichen"
Arithmetik-Befehle des Computers auf Deine privat
umdefinierten Daten anwendest und hoffst, es käme
automagisch das Richtige heraus. Das mag sich für
einzelne Rechenoperationen noch absichern lassen, aber
für ganze Verarbeitungsalgorithmen ist diese Eigenschaft
erst nachzuweisen, und das wird eine harte Nuss werden.
Kein Digitalfilter, keine FFT, kein kleinste-Quadrate-
Schätzer kommt, wenn der Algorithmus für äquidistante
Werte formuliert wurde, automagisch mit nicht-äquidistanten
klar.

Die trivialisierst eine mathematische Frage zu einer
programmiertechnischen Üblichkeit, die man auch
problemlos ändern könnte.


Soviel erstmal. Muss weg.

von Walter T. (nicolas)


Lesenswert?

Egon D. schrieb:
> Die trivialisierst eine mathematische Frage zu einer
> programmiertechnischen Üblichkeit, die man auch
> problemlos ändern könnte.

WTF? Haben wir wieder Aktionswochen für lange Wörter?

Es geht immer noch primär um die Kodierung eines Nicht-Wertes in 
Integer. (Für float muss das nicht diskutiert werden, da schon 
standardisiert.)

Wie ich schon eingangs schrieb, ist das verpönt. PeDas Reaktion 
enspricht dieser Aussage. Das ist gut - es bedeutet, dass es diese 
Vorbehalte wirklich gibt.

Bei niedrigen Funktionen sind Vorbehalte üblicherweise ein vages 
Unbehagen oder Ekel. Allerdings sollten Menschen ab einem gewissen 
Bildungsstand innerhalb ihres eigenen Fachgebiets soetwas 
differenzierter beschreiben können.

(Der letzte Absatz ist kein Angriff auf PeDa. Im Gegenteil schätze ich 
sogar, dass der eine genannte Grund bei float sogar sehr konkret ist.)

Für GOTO hat mal ein Dijkstra die wichtigsten Kontra-Argumente 
zusammengeschrieben. Der hat ja auch nicht einfach "Du bist ein 
Pfuscher! So macht man das nicht!" geschrieben. Er hat sich auch nicht 
in lange Wortgebilde aus angrenzenden Fachrichtungen geflüchtet. 
Deswegen nahm und nimmt man ihn auch ernst, selbst wenn man nicht jedem 
Argument zustimmt.

Niemand erwartet, dass plötzlich alle Programmiersprachen oder Libraries 
umgestellt werden.

Aber dafür oder dagegen, ob man ein Pattern in eigenen Programmen 
verwendet, sollten gute Gründe existieren.

Gründe dafür habe ich gefunden. Sonst wäre mir dieses "Pattern" nicht 
eingefallen. Gründe für die Vorbehalte suche ich noch. Einen kenne ich: 
Es ist nicht in der Standard-Library. Aber das float in der heutigen 
Form irgendwann auch mal nicht.

: Bearbeitet durch User
von Egon D. (Gast)


Lesenswert?

Walter T. schrieb:

> Egon D. schrieb:
>> Die trivialisierst eine mathematische Frage zu
>> einer programmiertechnischen Üblichkeit, die man
>> auch problemlos ändern könnte.
>
> WTF? Haben wir wieder Aktionswochen für lange Wörter?

Echt jetzt?
In meinem Text war wohl kein Tippfehler zur Hand -- so
als passender Vorwand, um mich vollzupflaumen?


> Es geht immer noch primär um die Kodierung eines
> Nicht-Wertes in Integer.

Lies einfach Deinen Eröffnungsbeitrag.

Um die Kodierungsfrage geht es sechs Zeilen lang; die
restlichen 29 Zeilen geht es um die Weiterverarbeitung
eines solchen Wertes.


> [...]
> Bei niedrigen Funktionen sind Vorbehalte üblicherweise
> ein vages Unbehagen oder Ekel. Allerdings sollten
> Menschen ab einem gewissen Bildungsstand innerhalb ihres
> eigenen Fachgebiets soetwas differenzierter beschreiben
> können.

Sicher.

Menschen eines gewissen Bildungsstandes sollten auch ihre
Fragen so formulieren können, dass die Antworten, die sie
erhalten, zielführend sind.
Und wenn die ersten Antworten am Thema vorbeizugehen
scheinen (oder es tatsächlich tun), sollten sie höflich
und geduldig auf diese Antworten eingehen und ihre Frage
präzisieren oder umformulieren können.


> Aber dafür oder dagegen, ob man ein Pattern in eigenen
> Programmen verwendet, sollten gute Gründe existieren.

Selbstverständlich, das ist ein berechtigter Wunsch.

Deine Fragestellung ist im Prinzip interessant und führt
m.E. weit über Dein ursprüngliches Beispiel (Messwerte
und ISR) hinaus.
Dennoch nervt mich Deine schnippische Art der Diskussions-
führung ganz gewaltig; für mich ist hier Schluss.

von Klaus W. (mfgkw)


Lesenswert?

Wenn es um Sensordaten geht, sind die 32 Bit vielleicht gar nicht nötig?
Dann könnte man doch davon ein Bit abzweigen für gültig/ungültig.

In C formulieren könnte man das dann als struct mit 2 Bitfeldern (1 bzw. 
31 Bit lang) und rechnet dann halt auf dem einen Teil, während man den 
anderen Teil als Status setzt.
Damit ist Schreiben und Lesen nach wie vor atomar möglich (auf einem 
32-Bit-µC natürlich) und kein Platz verschwendet.

von W.S. (Gast)


Lesenswert?

Walter T. schrieb:
> Außerdem ist es
> bei den Fließkommazahlen mit NaNs auch üblich.
>
> Banal ist es jetzt einfach so, dass INT_MIN aus dem Pool der gültigen
> Werte entfernt wurde und ungültige Daten markiert.

Du kannst seltsame Probleme haben...

Also mal aus meiner Sicht: Integerzahlen kennen zwar den Überlauf, aber 
keinerlei NaN. Allenfalls kann man dort ein Min und ein Max definieren 
und benutzen, um einen zulässigen Integerwert zu ermitteln.

Bei Fließkommazahlen gibt es NaN, die zumeist bei Rechenoperationen 
entstehen, wenn das Rechenergebnis zu groß oder zu klein werden würde. 
Das ist das Pendent zum Überlauf bei Integer.

All sowas ist auf zu saloppe Planung der zu schreibenden Firmware 
zurückzuführen. Sowas ist mir auch schon passiert, aber man kuriert es 
am sinnvollsten an der richtigen Stelle und bastelt nicht nachträglich 
mit Gültigkeitsflags herum.

W.S.

von Walter T. (nicolas)


Lesenswert?

W.S. schrieb:
> Bei Fließkommazahlen gibt es NaN, die zumeist bei Rechenoperationen
> entstehen, wenn das Rechenergebnis zu groß oder zu klein werden würde.
> Das ist das Pendent zum Überlauf bei Integer.

Nicht ganz. Bei Rechenoperationen, bei denen der Wertebereich der float 
ins Positive oder negative überschritten wird, entsteht Inf bsw. -Inf 
("Überlauf"). In Bezug auf "Unterlauf" unterscheiden sich die 
Bezeichnungen in der Literatur. In einigen Fällen ist "Unterlauf" der 
Bereich, der nicht mehr normalisiert dargestellt werden kann. Dann merkt 
der Benutzer erst einmal nur, dass die Auflösung abnimmt. Meist ist aber 
"Ergebnis kleiner als eps()" gemeint, und das Ergebnis ist einfach 0. 
oder -0. .

Mit Inf und -Inf kann man auch weiterrechnen. Ein paar Operationen 
weniger als bei regulären Zahlen sind erlaubt. Wird eine nicht-erlaubte 
Operation vorgenommen, entsteht ein NaN oder -NaN (Beispiel: Inf * 0 -> 
NaN)

NaN sind gedacht als "Ergebnis lässt sich nicht als float/double 
darstellen".

Typischer Anwendungsfall: Eingelesene Daten (z.B. Textstrings) lassen 
sich nicht als double interpretieren oder noch häufiger: Werte lassen 
sich nicht errechnen. Klassiker: Rangabfall. Dann lassen sich einige 
Zeilen des Gleichungssystems lösen, einige nicht. Die ungültigen 
Ergebnisse werden mit NaN markiert.

Wenn einige Zeilen ungültig sind, heisst das nicht, dass mit dem Rest 
der Lösung nichts angefangen werden kann. Deswegen ziehen die number 
cruncher es oft vor, eine Rechnung nicht sofort bei einem auftauchenden 
NaN abzubrechen, sondern erst einmal weiterzurechnen und nachher 
nachzukorrigieren.

Die beste laienverständliche Erklärung dazu habe ich in der 
Autobiographie Richard Feynmans gelesen. Seine Mitarbeiter haben damals 
in Los Alamos die Verfahren entwickelt, wie man mit falschen 
Zwischenergebnissen zu einem korrekten Endergebnis kommt.

Sprich: Bei der Entwicklung der IEEE 754 Fließkommazahlen ist sehr 
vieles sehr richtig gemacht worden.

Mit meinem laienhaften Umgang mit Integer hat das wenig zu tun. Aber 
komplett abwegig ist das auch nicht.

Bislang habe ich bis auf PeDas sinngemäßes "NaNs sind in meiner 
Anwendung meist falsch zugeordnete Zeiger" noch kein Argument gelesen.

Es kam jetzt mehrmals die Behauptung "wenn Du das brauchst, ist Deine 
Architektur übel" - ein klassischer Zirkelschluss. Wenn ich ein 
"nicht-empfohlenes"-Konstrukt nutzen muss, um ein Ziel zu erreichen, ist 
die Architektur nicht gut. Warum ist das Konstrukt nicht empfohlen? Weil 
es nur für nicht-gute Architektur gebraucht wird.

von Walter T. (nicolas)


Lesenswert?

Zweimal drüber geschlafen ist mir immer noch nicht die Eingebung 
gekommen, was das Schlechte an "Nullbaren Integer" sein soll - 
unabhängig vom hier angedachten Anwendungsfall.

von Jim M. (turboj)


Lesenswert?

Walter T. schrieb:
> Also hat das Vorgehen wohl einen Namen. Kennt jemand
> einen recherchierbaren Namen für ein solches Vorgehen?

Etwa "inband signaling" könnte passen.

Ergibt in der Praxis aber furchtbaren Spaghetti Code der langfristig 
schlecht zu warten ist. Man möchte die Fehlerbehandlung oftmals getrennt 
abarbeiten,
z.B. C++ hat dafür die Exceptions.

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.