ReadingsNum und sehr kleine Zahlen wie 2e-05

Begonnen von AlexMuc, 29 Februar 2024, 13:20:46

Vorheriges Thema - Nächstes Thema

betateilchen

Zahlenwerte aus einem String zu extrahieren, ist in jeder Programmiersprache eine Herausforderung, nicht nur in perl. Das wird vermutlich nie alle denkbaren Konstellationen zu 100% abdecken können. Man sollte ReadingsNum() als mögliches Hilfsmittel betrachten, nicht als mathematische Funktion.

Eine andere interessante Konstellation ist beispielsweise die Situation, wenn in einem String zwei oder mehr Zahlenblöcke vorkommen. Dann müsste man eigentlich ein array mit Werten zurückgeben, denn ReadingsNum() kann ja nicht wissen oder entscheiden, welchen Zahlenwert ich haben möchte. Und ob das Runden dann für alle Werte gewünscht ist, ist auch noch unklar *duck-und-weg*  8)
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

noansi

ZitatDann müsste man eigentlich ein array mit Werten zurückgeben, denn ReadingsNum() kann ja nicht wissen oder entscheiden
Soll sie auch nicht, denn eine solche Funktion sollte als ReadingsNums() ergänzt werden, wenn Bedarf danach besteht.  ;)

Otto123

Ich will ja keine Verbesserung ausbremsen, aber für mich war ReadingsNum() immer so zu verstehen: extrahiert die erste Zahl aus der Zeichenkette...
ZitatDie Funktion ReadingsNum extrahiert den numerischen Teil des Readings $reading der Definition $name und gibt diesen zurück, wenn er existiert. Dabei werden Zeichenketten wie z.B. Einheiten eliminiert und nur die eigentliche Zahl (Ganzzahl- oder Fließkommazahl) zurückgegeben.
Insofern habe ich auch ganz am Anfang von dem Thread verstanden, dass exponential Darstellung wahrscheinlich "hintenrunterfällt" ;)
Wird das Problem jetzt noch größer wenn ich die analoge Funktion in set magic ins Spiel bringe?
ZitatAb featurelevel 5.7 ersetzt der set und setreading Befehl
[device:name] mit dem Wert des Readings, Internals oder Attributes für device, falls sowohl device, als auch Reading, Internal oder Attribut existiert, und nicht leer ist.
Man kann einen der Präfixe r:, i: oder a: verwenden, um die Suche einzuschränken, genau wie im devspec.
Das Suffix :d extrahiert die erste Zahl.
Das Wort Zahl am Schluss kann man ja auch wieder sehr vielfältig interpretieren.
Wieviele Zahlensysteme gibt es? hex oktal binär ...  ;D 
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz

betateilchen

Bevor die Diskussion weiter ausufert, weil meine Anmerkung wieder mal völlig falsch interpretiert wird, möchte ich hiermit klarstellen, dass meine Text mit den mehrfachen Zahlenwerten lediglich ein Beispiel dafür war, was man an ReadingsNum() noch "bemängeln" könnte, wenn man wollte. Es war aber kein Feature-Request.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

noansi

Hallo Rudolf,

ZitatDas Suffix :d extrahiert die erste Zahl.
Korrekt, hier fällt die Exponentialdarstellung ebenfalls hinten runter.

AttrNum läßt die Exponentialdarstellung ebenfalls nicht zu. Gefühlt würde ich numberFromString bei AttrNum wegen möglicher Oktal-Nebenwirkungen und default Behandlung jedoch nicht anwenden, sondern nur auf Exponentialdarstellung erweitern, solltest Du es ändern.

Gruß, Ansgar.

betateilchen

-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Otto123

ich wollte auch keinen Feature-Request, ich bin eher für Büchse wieder schließen. ;) Lasst es so wie es war und kommuniziert es so.
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz

noansi

Meinerseits handelt es sich lediglich um eine Ergänzung der Code Analyse, wo AlexMuc Ausgangsproblem in der Zukunft ebenfalls mal wegen Fließkommadarstellungseinschränkung auftreten kann.

Was bedeutet, das der betroffene Code bis dahin noch älter ist und damit die Wahrscheinlichkeit für Nebenwirkungen durch Änderung zu diesem Zeitpunkt nicht kleiner wird.

Konkrete Probleme habe ich derzeit nicht mit den genannten Funktionen, da ich sie nicht oder nicht in der Problemform benutze.

Gruß, Ansgar.

noansi

#23
Hallo Rudolf,

über das Geplänkel, ob an anderer Stelle noch Änderungen sinnvoll sein könnten, ist leider der Test der Änderung selbst zu kurz gekommen.

Und mir ist noch was bezüglich Default Behandlung aufgefallen.

An den relevanten Stellen wird numberFromString in der Art aufgerufen:
vergiss esDadurch, dass in diesem Beispiel ReadingsVal mit $default aufgerufen wird, wird ReadingsVal $default zurück liefern, wenn das Reading nicht existiert.
Ist $default selbst eine Zahl oder enthält eine Zahl, dann wird in numberFromString der zurück gelieferte Default als
- gültiges Zahlergebnis behandelt, also um den ggf. enthaltenen Text beraubt
- und manipuliert, also ggf. gerundet

Das widerspricht der von Otto schon angemerkten Beschreibung https://wiki.fhem.de/wiki/DevelopmentModuleAPI#ReadingsNum und wohl auch der Intention.

Vorschlag:

vergiss esReadingsVal würde mit dem Default undef undef liefern, wenn das Reading nicht existiert. (natürlich singemäß an den anderen beiden Verwendungstellen auch)
Und

vergiss eswürde dann und wenn das Reading keine Zahl enthält den $default unmanipuliert zurück liefern, entsprechend Beschreibung.

Edit: Und da das im alten Code auch schon so war, wäre die Alternativlösung die Beschreibung dem Code anzupassen.
Edit2: Sorry, im Kleingedruckten habe ich doch noch entdeckt, dass das Runden den Defaults beabsichtigt ist. "Der ermittelte Wert, ob Standard oder aus einem Reading, wird auf $round Anzahl Stellen gerundet." Jedoch passiert dies nicht, wenn im Reading keine Zahl vorkommt.
Edit3: Letzteres, also das uneinheitliche Rundungsverhalten hat mich überhaupt motiviert einen Bug zu vermuten. Jedoch bietet es die Möglichkeit, mit Runden zu unterscheiden, was beim Reading schief gelaufen sein könnte, wenn der Default auf die ein oder andere Art zurück geliefert wird. Das könnte Absicht gewesen sein, ist jedoch nicht aus der Beschreibung oder Code Kommentaren ersichtlich.

Gruß, Ansgar.

PS: Und zu dem Oktal Problem, gebe ich im Webbrowser
{ReadingsNum("bla","blub","0672.9840")}ein, erhalte ich 0672.9840 als Antwort. Device "bla" und Reading "blub" exisitieren in meinem System nicht
{ReadingsNum("bla","blub",0672.9840)}liefert dagegen das unerwünschte 4429840, d.h. in diesem Fall wirkt der Oktal Fix nicht (auch nicht in der aktuellen code Version im SVN). Die Oktal-Interpretation passiert in diesem Fall schon vorher. Getestet mit perl Version 5.14.2. Das als Randbemerkung, falls es mal relevant sein sollte.

rudolfkoenig

Zitatliefert dagegen das unerwünschte 4429840
Meine Meinung dazu: der Benutzer hat in der Hand die default Werte zu setzen.

betateilchen

Wenn ReadingsNum() in einem existierenden reading keinen Zahlenwert findet, weil da z.B. "abc" drinsteht, wird der angegebene default-Wert von ReadingsNum() zurückgegeben. Ich grüble seit zwei Tagen, ob das Verhalten wirklich richtig ist. Außerdem habe ich noch nie verstanden, warum ReadingsNum() überhaupt alphanumerische default-Werte zulässt.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

noansi

#26
Hallo betateilchen,

statt "abc" könnte da auch, z.B. beim FHEM Start oder Wiederverbinden vom Device, "noch nicht empfangen" drin sein und denoch würde ReadingsNum den default liefern. So weit gut.

Der default Wert wiederum kann statt einer Zahl auch undef sein, was effizient wäre zur unspezifischen Fehlerbehandlung, kann aber auch ein Fehlertext sein, auf den verglichen werden kann. Der default kann z.B. auch wiederum ein Aufruf von ReadingsVal oder einer anderen Funktion sein, was ggf. wiederum verschiedene Texte oder Fehlertexte liefern könnte, auf die verglichen werden kann.

Mal so ein paar Gedanken zur Intention und Flexibilität und, wie Rudolf schon geschrieben hat, "der Benutzer hat in der Hand die default Werte zu setzen".
Wenn das schon mal so genutzt wurde und das Verhalten wird geändert, dann hüpft die Büchse der Pandora vor Freude...

Blöd nur, wenn der Text oder Fehlertext doch mal eine Ziffer oder Zahl enthält und das Reading nicht existiert im Vergleich zu Reading existiert aber enthält puren Text wie "abc" oder ist einfach nur "". Dann kommt nur die Ziffer oder Zahl (ggf. mit Rundungserweiterung) statt des vollständigen default Textes oder es kommt der vollständige default Text mit Nummer und wenn das nicht beachtet wird oder nicht bewusst ist, dann heist es mühsames Debuggen von Ausnahmefällen.
Das ist quasi die Steigerung der "Default Rundungsvarianz", die ich oben bereits beschrieben hatte.

Gruß, Ansgar.

PS: Es fällt schwer, einen nicht numerischen Default bei ReadingsNum in den Modulen zu finden, in 10_CUL_HM.pm habe ich es jedoch exemplarisch in Form von
      my $d = ReadingsNum($name,'temperature','');
      CUL_HM_Set($hash,$name,"virtTemp",$d) if($d =~ m/^[-+]?[0-9]+\.?[0-9]*$/);
      $d = ReadingsNum($name,"humidity","");
      CUL_HM_Set($hash,$name,"virtHum" ,$d) if($d =~ m/^[-+]?[0-9]+\.?[0-9]*$/);
im SVN gefunden. Die Büchse der Pandora steht also in den Startlöchern.  ;)
Und ich habe nicht sämtliche Module durchsucht.

PS2: In numberFromString
  $val = ($val =~ /(([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?)/ ? $1 : "");
  $val =~ s/^([+-]?)0+([1-9])/$1$2/; # Forum #135120, dont want octal numbers
  return $default if($val eq "");
würde mit Texten ein wenig effizienter den default mit
  $val = ($val =~ /(([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?)/ ? $1 : "");
  return $default if($val eq "");
  $val =~ s/^([+-]?)0+([1-9])/$1$2/; # Forum #135120, dont want octal numbers
liefern.

PS3: In 59_HCS.pm habe ich ebenfalls ReadingsNum mit Text default gefunden:
    $devs{$d}{tempDesired}  = ReadingsNum($d,"setpointTemp","n/a",1)          if($t =~ m/(ZWave)/);... und "Fehlerauswertung"
    if($mode eq "thermostat" && ($devs{$d}{tempMeasured} eq "n/a" || $devs{$d}{tempDesired} eq "n/a")) {Und ich habe nicht sämtliche Module durchsucht.

betateilchen

ReadingsNum() mit alphanumerischen Defaultwerten sind mir bisher hauptsächlich in Code-Auszügen von fragestellenden Forumteilnehmern untergekommen, und genau da finde ich es besonders problematisch, dass das überhaupt funktioniert.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!