Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Berechnungsfehler (https://www.delphipraxis.net/188833-berechnungsfehler.html)

schand99 11. Apr 2016 15:36

Berechnungsfehler
 
Hallo,

kann einen unschönen Berechnungsfehler beobachten.
Habe folgende Variablen:
Rohrzahl, Rohrlagen, RohrReihen, Kreisläufe: Integer
RohreProKreis: Single

Wenn nun Rohrlagen = 38, RohrReihen = 4 und Kreisläufe = 40, dann

RohrZahl := RohrLagen * RohrReihen;
RohreProKreis := RohrZahl / Kreisläufe:

Ergebnis: RohreProKreis = 3,79999995231628
Wie kommt es dazu? Das korrekte Ergebnis wäre 3,8

Hat jemand von Euch eine Ahnung was zu dieser falschen Berechnung führt?

Gruß
Andreas

baumina 11. Apr 2016 15:42

AW: Berechnungsfehler
 
Das liegt am Datentyp Single (Float), der ist ungenau. Nimm stattdessen Extended.

Sir Rufo 11. Apr 2016 15:45

AW: Berechnungsfehler
 
Zitat:

Zitat von baumina (Beitrag 1335299)
Das liegt am Datentyp Single (Float), der ist ungenau. Nimm stattdessen Extended.

Der ist nicht ganz so ungenau ... aber eben auch noch :stupid:

4dk2 11. Apr 2016 15:52

AW: Berechnungsfehler
 
Double geht auch!

Delphi Hilfe: Der Typ Extended bietet eine höhere Genauigkeit, ist aber nicht so einfach portierbar wie die anderen reellen Typen. Verwenden Sie Extended mit Bedacht, wenn Sie Datendateien anlegen, die gemeinsam und plattformübergreifend genutzt werden sollen.
sollte man sich immer merken ;)

Lemmy 11. Apr 2016 16:15

AW: Berechnungsfehler
 
Zitat:

Zitat von schand99 (Beitrag 1335297)

Ergebnis: RohreProKreis = 3,79999995231628
Wie kommt es dazu? Das korrekte Ergebnis wäre 3,8

wenn dir max. 4 Nachkommastellen ausreichen (sowie die Wertgrenze), dann nimm den Typ Currency, da hast Du keine solchen Probleme

Grüße

Zacherl 11. Apr 2016 17:01

AW: Berechnungsfehler
 
Zitat:

Zitat von schand99 (Beitrag 1335297)
Hat jemand von Euch eine Ahnung was zu dieser falschen Berechnung führt?

Wenn dich die technischen Infos dazu interessieren: Floating Point Accuracy Problems.

MEissing 11. Apr 2016 17:12

AW: Berechnungsfehler
 
Achtung: Im 64-Bit Modus gibt es Extended nur als Synonym für Double....

32-Bit kann genauer rechnen, als 64 Bit :-)

(OK: Mit 64 Bit rechne *ich* ziemlich ungenau... :shock: :drunken:)

himitsu 11. Apr 2016 17:15

AW: Berechnungsfehler
 
Wobei "Rundungsfehler" hier garnicht zu vermeiden sind, egal wie groß man den Fließkommadatentyp wählt.

Am Ende muß man ganz einfach bei der Ausgabe auf das gewünschte Maß runden und darf "niemals" mit = vergleichen.

Currency "rundet" automatisch auf 4 Nachkommastellen.
Bei BCD hängt das von der Speichergröße ab. (aber maximal mit der Auflösung vom Extended, wenn man es über die FPU berechnen lässt)

PS: Bei 64 Bit ist Extended nur noch FPU-intern und steht dem Programmierer quasi außerhalb garnicht mehr zur Verfügung.
In Delphi stand es halt unter 32 Bit nur deswegen zur Verfügung, weil es ging, aber offiziell war es nicht zur Benutzung angedacht.
Drum kennen Andere sowas Großes garnicht erst. :stupid: https://msdn.microsoft.com/de-de/library/cc953fe1.aspx


Zitat:

Zitat von MEissing (Beitrag 1335311)
32-Bit kann genauer rechnen, als 64 Bit :-)

"rechnen" tun Beide womöglich gleich, nur "speichern" halt nicht. (so lange es innerhalb der entsprechenden CPU-Register bleibt)

Luckie 11. Apr 2016 18:10

AW: Berechnungsfehler
 
Hier noch mal auf deutsch: http://michael-puff.de/Programmierun...esskomma.shtml

himitsu 11. Apr 2016 18:49

AW: Berechnungsfehler
 
DX35 kann dann bestimmt auch endlich 128 Bit. :stupid:
https://msdn.microsoft.com/de-de/lib...3fe1.aspx#mt62 __int128

Jens01 11. Apr 2016 20:18

AW: Berechnungsfehler
 
Zitat:

Ergebnis: RohreProKreis = 3,79999995231628
Wie kommt es dazu? Das korrekte Ergebnis wäre 3,8
Ist doch richtig gerechnet!

Mache RohreProKreis := RoundTo(RohreProKreis, -2)
Man muss sich daran gewöhnen, dass nicht genau der erwartete Wert erscheint, sondern der ungefähr erwartete. Man benutzt eine Maschine zum Rechnen und die hat Tolerenzen. Die Toleranzen muß man bewerten und damit umgehen. Wie im Maschinenbau.
Spannend wird es erst, wenn Du Werte vergleichen willst. Sowas wie "if Wert = 0 then .."

Lemmy 11. Apr 2016 20:35

AW: Berechnungsfehler
 
Zitat:

Zitat von himitsu (Beitrag 1335312)
Wobei "Rundungsfehler" hier garnicht zu vermeiden sind, egal wie groß man den Fließkommadatentyp wählt.

Die Ursache dafür ist aber kein Rundungsfehler sondern eine Speicherungenauigkeit bei Fließkommawerten. Das sind 2 unterschiedliche Dinge und sollte man tunlichst nicht verwechseln.

Zitat:

Zitat von Jens01 (Beitrag 1335334)
Mache RohreProKreis := RoundTo(RohreProKreis, -2)

ganz toll...
http://docwiki.embarcadero.com/Libra...m.Math.RoundTo

Du fütterst einen Extended rein, bekommst einen Extended raus. Ändert genau gar nichts. Ok, es mag seht oft ein gerundetes ERgebnis raus kommen, aber es gibt halt auch Werte die hier wieder mit dem Speicherfehler aus der Funktion kommen. (und ja: Ich hatte das Thema schon oft mit Entwicklern die vom Glauben abgefallen sind, weil bei RoundTo hin und wieder eben nicht der auf 2 Stellen genaue Wert raus kommt sondern was anderes).

Wenn Du RoundTo verwendest, dann solltest Du das ganze einem Currency zuweisen (wenn es dir wichtig ist mit genau 2 Nachkommastellen weiter zu rechnen)

Jens01 11. Apr 2016 20:57

AW: Berechnungsfehler
 
@Lemmy
Ja hast recht.
Gedanklich habe ich das aus Ausgabe bzw letztes Ergebnis angesehen:
StrRohreProKreis := RoundTo(RohreProKreis, -2).ToString

Wenn man es als Zwischenergebnis nutzt, würde ich eh mit dem Wert so weiterrechnen.
Bei technischen Berechnungen bringt dies Extended doch nichts. Ich nutze sogar bei FEM-Berechnungen Double-Werte.

Lemmy 11. Apr 2016 22:17

AW: Berechnungsfehler
 
Zitat:

Zitat von Jens01 (Beitrag 1335341)
@Lemmy
Bei technischen Berechnungen bringt dies Extended doch nichts. Ich nutze sogar bei FEM-Berechnungen Double-Werte.

keine Frage... wenn Du mit Koordinaten zu tun hast, kommst Du daran nicht vorbei, weil die 4 Nachkommastellen vom Currency einfach zu wenig sind, wenn du mit 1.000 multiplizieren musst - da hast Du dann schon Fehler im Dezimeterbereich :-) Es kommt halt immer darauf an...

himitsu 12. Apr 2016 09:24

AW: Berechnungsfehler
 
[QUOTE]Die Ursache dafür ist aber kein Rundungsfehler sondern eine Speicherungenauigkeit bei Fließkommawerten. Das sind 2 unterschiedliche Dinge und sollte man tunlichst nicht verwechseln.[QUOTE]
OK, aber wenn man es so sieht, dann wird es beim Speichern auf den nächsten Wert "gerundet", den der Typ speichern kann. :angle2:

matashen 12. Apr 2016 09:31

AW: Berechnungsfehler
 
Auch mal kurz mein süßer Senf dazu

Es liegt einfach da dran das digital zum Beispiel kein drittel kennt und damit 0,3333333 speichert und irgendwann das "unendlich" fehlt (unendlich kennt dein System nicht). Bei weiteren Berechnungen treten eben hier Ungenauigkeiten auf. Das muss dann dein Code ausgleichen mit Runden an der passenden Stelle.

Medium 12. Apr 2016 10:09

AW: Berechnungsfehler
 
Und dem wäre noch hinzuzufügen, dass binär Perioden an anderen Stellen auftauchen als bei dezimal. Zum Beispiel ist 0,2 als Float niemals exakt darstellbar, da es immer in einer Periode mündet. Egal wie genau der Typ ist den man wählt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:56 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