AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

FloatToStrF Rundungsfehler ?

Ein Thema von egentur · begonnen am 28. Jan 2021 · letzter Beitrag vom 5. Feb 2021
Antwort Antwort
Seite 1 von 2  1 2   
Rollo62

Registriert seit: 15. Mär 2007
4.174 Beiträge
 
Delphi 12 Athens
 
#1

AW: FloatToStrF Rundungsfehler ?

  Alt 28. Jan 2021, 16:01
Ich bin ja nicht 100% sicher, aber FloatToStrF würde ich nicht fürs Runden missbrauchen.
Insbesondere wenn es mir wirklich auf die letzte Stelle ankommt.
Das steuert doch nur die Anzeige, und die Rundungsfunktion ist Abfallprodukt.
Evtl. vorher Runden, wie gewünscht mit der gewünschten Rundungs-Funktion, und dann erst FloatToStrF.
  Mit Zitat antworten Zitat
Incocnito

Registriert seit: 28. Nov 2016
229 Beiträge
 
#2

AW: FloatToStrF Rundungsfehler ?

  Alt 28. Jan 2021, 16:29
Ja scheint auf den ersten Blick seltsam ...

0.5025 beispielsweise wird bei IEEE-754 (das müsste Single sein)
als
0.502499997615814208984375
gespeichert (dichter kommt der PC mit der Speicherung in 32-Bit nicht ran)
Dort würde ein Runden auf 3 Nachkommastellen nicht wie erwartet
0.503 sondern 0.502 ergeben.

Runden war schon immer ein Spaß für sich.

Dein 0.5015 wäre in IEEE-754 (Single?) übrigens 0.50150001049041748046875.
Es hilft also nur bei genau dieser Zahl von Double auf Single zu wechseln,
bei anderen Zahlen schlägt es genau umgekehrt fehl, bei noch anderen Zahlen
wäre der Datentyp dann vermutlich egal.

Wenn du 4 Nachkommastellen als Maximum hast könnte Currency gehen,
oder du baust deine eigene "sichere" Runden-Funktion.

MfG Incocnito
  Mit Zitat antworten Zitat
egentur

Registriert seit: 27. Sep 2006
Ort: Freising
60 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#3

AW: FloatToStrF Rundungsfehler ?

  Alt 29. Jan 2021, 15:37
Hallo Incocnito

Genauso verhält es sich bei mir.
Ich habe die 8 Jahre alte Software übernommen.

Ein Messwert kommt als String '0.50015' ,
wird dann für eine weitere Berechnung in Double konvertiert

val(messwert, double, error) double ist dabei 0.500149999...

und dann wieder in String
result := Floattostrf(double , fffixed, 6,4)

result ist dann '0,5001'

zur Anzeige.

Warum rundet die Funktion an diese Stelle ab statt auf (0,5002) ?

Ist dies ein bekannter Fehler ?
  Mit Zitat antworten Zitat
Delphi.Narium

Registriert seit: 27. Nov 2017
2.558 Beiträge
 
Delphi 7 Professional
 
#4

AW: FloatToStrF Rundungsfehler ?

  Alt 29. Jan 2021, 15:48
Weil 0.500149999 bei Rundung auf vier Nachkommastellen halt 0.5001 ergibt.

Floattostrf weiß nicht, dass vorher aus dem String 0.50015 ein Double 0.500149999 gemacht wurde und daraus dann eigentlich ein String 0.50015 werden müsste, der dann zu 'nem gerundeten String 0.5002 werden sollte.

Floattostrf kennt nunmal nur den aus dem String erstellten Doublewert von 0.500149999, rundet den auf vier Nachkommastellen = 0.5001 und macht dann daraus einen String.
  Mit Zitat antworten Zitat
Incocnito

Registriert seit: 28. Nov 2016
229 Beiträge
 
#5

AW: FloatToStrF Rundungsfehler ?

  Alt 29. Jan 2021, 16:09
Ok, Himitsu war schneller ... ich poste das aber trotzdem jetzt!

1) Um Gedanklich ungefähr dahin zu kommen zu verstehen, was da passiert:
Man nehme an, für die Nachkommastellen gäbe es im Computer nur 2 Bits.
Durch die Beschaffenheit eines Computers könnte dieser nur auf 1/4-Werte speichern.
Er kann also nur 0.000, 0.250, 0.500 und 0.750 (und 1.000 usw.) speichern.
Jetzt kommst du mit dem Wert "0.100" und der Computer muss sich entscheiden,
ob er das als 0.000 oder als 0.250 speichern soll.
Der Computer hat herausgefunden, dass 0.000 dichter am Originalwert ist, also
speichert er den Wert als diesen ab.
Wenn du dann fragst "Wert <> 0" sagt der Computer "Nein", obwohl dein Ursprungswert
sehr wohl <> 0 wäre.

Vielleciht hilft auch das hier:
https://www.matheretter.de/rechner/dezimalbinar

2) Der Datentyp Currency hilft hier, da er in Wirklichkeit den 10000-stel Wert
speichert. (4 Nachkommastellen)
Speicherst du 1,20 € als Currency speichert er 12000 als Integer (Int64), weiß aber
wenn du damit arbeiten willst, dass du nur den 10000sten Teil meinst.
Für das Runden von Beträgen, welche in Float-Werten (Real, Float, Double, Extended)
in irgendeiner Form zwischengespeichert wurden habe ich etwas gebaut,
was das kleinste Diff aufaddiert, die Kommastellen (um 2 Stellen) verschiebt
0,5 aufaddiert, dann das ganze Truncated und den Wert wieder zurück verschiebt.
Hierbei klappte das Runden dann bisher immer auch bei Werten aus Fließkommavariablen.
Andere Funktionen hatten immer irgendeine Zahl, bei der das Runden
dann doch nicht funktionierte. Eben wegen der Beschaffenheit der Fließkommazahlen
in der EDV.

Das war schon wieder viel zu viel Text. Sorry.

Liebe Grüße
Incocnito
  Mit Zitat antworten Zitat
markus888

Registriert seit: 23. Dez 2018
46 Beiträge
 
#6

AW: FloatToStrF Rundungsfehler ?

  Alt 2. Feb 2021, 19:53
habe ich etwas gebaut, was das kleinste Diff aufaddiert
darf ich fragen, was du da genau machst?

Beim Konvertieren zu einem String, wird ja vermutlich auch eine Differenz aufaddiert.
Hab mich da aber noch nicht tiefer damit beschäftigt.
  Mit Zitat antworten Zitat
Incocnito

Registriert seit: 28. Nov 2016
229 Beiträge
 
#7

AW: FloatToStrF Rundungsfehler ?

  Alt 3. Feb 2021, 08:47
habe ich etwas gebaut, was das kleinste Diff aufaddiert
darf ich fragen, was du da genau machst?...
Ich ermittel je nach Datentyp die kleinste Differenz, welche beim Aufaddieren den Wert der Variable noch ändert.
Zum Verständnis: Wenn du 4 Bits als Nachkommastellen hättest, könntest der Computer ja
1,00 / 1,0625 / 1,1250 / 1,1875 / 1,2500 / 1,3125 / 1,3750 / 1,4375 / 1,5000 / 1,5625 / 1,6250 / ...
abbilden.
Die Genauigkeit welche ich brauche darf dann natürlich nur entsprechend sein. In dem Fall mit 4 "Nachkomma-Bits"
reicht es nichmal für 1 Nachkommastelle, aber ich kann hier nicht eine Liste für 10 Nachkomma-Bits machen,
damit wir 2 Nachkommastellen zum "Spielen" haben.
Wenn ich '1,4' als Wert bekomme sagt der PC "Ok, 1,3750 ist näher dran als 1,4375, dann speicher ich '1,4' als 1,3750".
Ich rechne in diesem Fall stumpf 0,0625 auf alle ermittelten Ergebnisse.
Wenn ich also den Wert 1,3750 sehe wird daraus 1,4375. Welcher bei der Ausgabe wieder unkritisch wäre.

Ja, wie gesagt, die 4 Bits reichen leider nicht für 1 Nachkommastelle, wie man bei der 1,5000 sieht.
Ich denke mal, dass man 7 Nachkomma-Bits bräuchte (1/128 = 0,0078125) für dieses
Prinzip.
Rechne ich bei 1,5000 die 0,0625 drauf würde gerundet ja tatsächlich 1,6 heraus kommen.
Wenn ich
http://docwiki.embarcadero.com/RADSt...ormate_(Delphi)
richtig lese hat selbst Single 23 Nachkomma-Bits.
Für eine Anwendung die 4 Nachkommastellen braucht ist das also ausreichend.

Anmerkung für die Allwissenden unter euch: Nein, ich lasse die Verschiebung der Mantisse
jetzt mal absichtlich weg und beziehe mich nur auf die Differenz zum Wert 1,0.
Sonst wird das echt zu konpliziert.


...Beim Konvertieren zu einem String, wird ja vermutlich auch eine Differenz aufaddiert.
Hab mich da aber noch nicht tiefer damit beschäftigt.
Der Computer bahandelt hier nur die Darstellung als Text. Das ist nur
numerisch gesehen ein Aufaddieren (oder Abziehen), lass dich davon nicht beirren.

---

Hast du mal versucht auf die Werte, welche du vom Sensor bekommst einfach etwas
drauf zu rechnen? ... Du könntest zum Testen sogar hingehen und sowas machen:
Delphi-Quellcode:
var
  dWert : Single; // oder Double
  sWert : String;
...
  sWert := WertAusSensor();
  dWert := StrToFloatDef(sWert, 0);
  if (dWert <> Trunc(dWert)) then sWert := sWert + '1'; // Nur wenn Nachkommastellen, sonst machst du ja aus "2" eine "21" ;-)
  dWert := StrToFloatDef(sWert, 0);
  ShowMessage(FloatToStrF(dWert, ffFixed, 6, 4));
Ob man jetzt stiltechnisch sagt "ich mache StrToFloat() und fange die Exception ab/nicht ab" oder
ob man für den Default-Wert einen unrealistischen Wert nimmt und eine Meldung ausgibt,
falls dieser Wert dann heraus kommt oder man direkt mit "TryStrToFloat" arbeitet,
kann sich meinetwegen jeder selbst aussuchen.
Für deinen speziellen Fall dürfte das so aber reichen.

Anmerkung: Da es je nach Anwendungsfall anders gehandhabt werden muss, können Programmiersprachen
das nicht "von sich aus korrigieren". Delphi bietet allerdings mit dem Datentyp "Currency" eine
gute Möglichkeit solche Fehler mit Hausmitteln einfach zu bekämpfen, wenn man 4 Nachkommastellen
und weniger braucht. Leider reicht das für deinen Fall hier nicht.

Melde dich, ob du mit meinem Ansatz das Problem beheben konntest.

LG Incocnito
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.372 Beiträge
 
Delphi 12 Athens
 
#8

AW: FloatToStrF Rundungsfehler ?

  Alt 29. Jan 2021, 15:57
Warum?
Das wurde doch gesagt und du hast es selbst auch nochmal bestätigt.

Intern wird es als 0.500149999... gespeichert (Darstellungsfehler, da wir in einem 10er-System denken, aber der Computer mit einem 2er-System rechnen muss.
(10 lässt sich nunmal nicht als 1 Bit darstellen und wird somit zwangsläufig unscharf, denn 8-10-16)

Und bei Rundung auf 4 Nachkommastellen, kommt für 0.500149999 nunmal 0.5001 raus.


Wenn man davon ausgehen könnte, dass bei String-zu-Float immer abgerundet würde,
dann könnte man vor dem Runden einen kleinen Offset zurechnen (z.B. 0.00001 also 10% von der kleinstmöglichen Nachkommastelle) und schon stimmt es.
Aber ich vermute fasst hier wird das Nächstliegendste gespeichert.
Würde dabei manchmal aufgerundet, also 0.500150000001..., dann müsste man den Offset ja eigentlich abziehen.



Aus diesem Grund gibt es z.B. auch den Typ Currency (ist intern ein Int64, wo die letzten 4 Dezimalstellen als Nachkomma definiert sind, womit es dort nicht solche Rundungsfehler gibt, bei bis zu 4 Nachkommastellen)
Man kann auch BCD oder andere Big-Nummer-Systeme verwenden, wenn es sein muß. (BCD speichert in einem 10er-System und hat somit keinen Darstellngsfehler)
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu (29. Jan 2021 um 16:08 Uhr)
  Mit Zitat antworten Zitat
Andreas13

Registriert seit: 14. Okt 2006
Ort: Nürnberg
722 Beiträge
 
Delphi XE5 Professional
 
#9

AW: FloatToStrF Rundungsfehler ?

  Alt 29. Jan 2021, 16:26
... Aus diesem Grund gibt es z.B. auch den Typ Currency (ist intern ein Int64, wo die letzten 4 Dezimalstellen als Nachkomma definiert sind, womit es dort nicht solche Rundungsfehler gibt, bei bis zu 4 Nachkommastellen)
Aber nur, wenn man lediglich addiert oder subtrahiert. Bei sonstigen mathematischen Operationen gibt es auch dort Rundungsfehler.
Andreas
Grüße, Andreas
Wenn man seinem Nächsten einen steilen Berg hinaufhilft, kommt man selbst dem Gipfel näher. (John C. Cornelius)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.372 Beiträge
 
Delphi 12 Athens
 
#10

AW: FloatToStrF Rundungsfehler ?

  Alt 29. Jan 2021, 18:02
In x86 war eine Erweiterung für BCD integriert,
aber im 64 Bit hat es nicht mehr eingebaut und sich den Platz im Silizium gespart.
https://en.wikipedia.org/wiki/Intel_BCD_opcode

Schade, dass es praktisch niemand benutzt hatte und man es somit als Nutzlos ansah.
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2   

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:35 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz