Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Teilen (https://www.delphipraxis.net/121642-teilen.html)

TimoB 1. Okt 2008 19:58


Teilen
 
Hallo,
habe da ein Problem wo ich überhaupt nicht weiter komme...

ich gebe eine Länge in ein Eingabefeld ein mit :

Laenge := strtofloat (editlaenge.Text);

denn wird die Anzahl der Zellen eines Regals folgendermaßen berechnet:

Anzahlzellen4 := trunc((Laenge-Staenderbreite) / (Zellenbreite4+Staenderbreite));

Ständerbreite und Zellenbreite4 sind folgendermaßen berechnet:

Staenderbreite := 0.1;

Zellenbreite4 := ( 2 * Staenderabstand ) + ( 3 * Palettenabstand )+ ( 4 * Palettenbreite );

die variablen sind wie folgt definiert:

Zellenbreite4,Staenderbreite, Palettenabstand : single ;
Anzahlzellen : integer ;

mein problem ist, das das ergebnis der anzahlzellen4 bei einer Längenangabe von 3,8 = 0 ist, obwohl eigentlich 1 rauskommen müsste.
denn:
Länge-Staenderbreite ergibt 3,7 und Zellenbreite4 + Staenderbreite ergibt auch 3,7.

wenn ich mir das ergebnis ohne trunc anzeigen lasse, kommt ein ergebnis von 0,999999945 raus und denn macht trunc da natürlich eine o von.
kann mir einer sagen, warum 0,999999945 statt 1 rauskommt. liegt das evtl an den typen der variablen?

danke im vorraus.

BullsEye 1. Okt 2008 20:03

Re: Hilfe
 
Lass mal das ganze mit Trunc etc weg.. Anstatt Single könntest du auch Integer nehmen...Und dann "StrToInt"

TimoB 1. Okt 2008 20:07

Re: Hilfe
 
ich muss aber trunc machen, da man z.b. keine 4,3 zeilen haben kann.
intger kann ich auch nicht nehmen, da wir auch kommawerte eingeben können.

ich versteh halt nicht wie er auf die 0,999999945 kommen kann. wenn man 3,7 / 3,7 hat

BullsEye 1. Okt 2008 20:10

Re: Hilfe
 
Ersetz das mal:

Delphi-Quellcode:
Anzahlzellen4 := trunc((Laenge-Staenderbreite) / (Zellenbreite4+Staenderbreite));
durch:

Delphi-Quellcode:
Anzahlzellen4 := trunc((Laenge-Staenderbreite) DIV (Zellenbreite4+Staenderbreite));

TimoB 1. Okt 2008 20:11

Re: Hilfe
 
das geht nicht, div geht doch nur bei integer oder?
und die zahlen müssen single sein, da sie kommazahlen sind

RWarnecke 1. Okt 2008 20:22

Re: Hilfe
 
Zitat:

Zitat von TimoB
das geht nicht, div geht doch nur bei integer oder?
und die zahlen müssen single sein, da sie kommazahlen sind

DIV sollte überall gehen. Ersetze mal Single durch Real.

taaktaak 1. Okt 2008 20:23

Re: Hilfe
 
Versuch es doch mal mit Round()
oder besser gleich mit Format(), da wird gerundet und gleichzeitig in String konvertiert.

TimoB 1. Okt 2008 20:29

Re: Hilfe
 
div geht nur bei ganzen zahlen, real hatten wir vorher auch gehabt und da war das gleiche problem.

round können wir nicht nehmen, da wir immer auf die ganze zahl abrunden müssen.

taaktaak 1. Okt 2008 20:31

Re: Hilfe
 
Na, dann Format()

Phoenix 1. Okt 2008 20:47

Re: Hilfe
 
Zitat:

Zitat von TimoB
round können wir nicht nehmen, da wir immer auf die ganze zahl abrunden müssen.

Auf ganze Zahl abrunden: Round(Zahl - 0.5);

Beispiel: 1 --> Round(0.5) = 1
Beispiel: 1.1 --> Round(0.6) = 1
Beispiel: 1.9 --> Round(1.4) = 1

SirThornberry 1. Okt 2008 20:54

Re: Hilfe
 
Hallo TimoB, gib deinem Beitrag bitte einen aussagekräftigen Titel entsprechend den Forenregeln :-)

TimoB 1. Okt 2008 21:29

Re: Teilen
 
sorry wegen derm themenbezeichnung.
das round (zahl - 0,5) kann mir auch nicht weiterhelfen. z.b. 0,99999955 -0,5 = 0,49999955 und damit auch 0

SirThornberry 1. Okt 2008 21:46

Re: Teilen
 
der neue Titel ist ja auch nicht gerade grob das Problem beschreibend :roll: Aber wenigstens war der Wille vorhanden?!

taaktaak 1. Okt 2008 22:08

Re: Teilen
 
Ich begreife nicht ganz, was hier so schwer fällt.
Und insbesondere nicht, warum du es nicht mit Format() versuchst!

Also, hier mal ein Beispiel
Delphi-Quellcode:
label1.caption:=floattostr(3.7/3.7);             // label zeigt 1
 label2.caption:=floattostr(3.7/3.70101010);      // label zeigt 0,9997270....
 label3.Caption:=format('%2.0f',[3.7/3.70101010]) // label zeigt 1
Abgesehen davon, dass 3.7 / 3.7 tatsächlich 1 ergibt, kann mit Format() dein Rundungsproblem gelöst werden :warn:

Korrekter, als den Rundungsfehler am Ende zu korrigieren, wäre es, die Berechnung schrittweise durchzugehen und die Zwischenergebnisse zu überprüfen. Vielleicht muss ja ein krummer Wert 'rauskommen, vielleicht aber auch nicht.

Gute Nacht für Heute

BUG 1. Okt 2008 22:12

Re: Hilfe
 
Zitat:

Zitat von Phoenix
Auf ganze Zahl abrunden: Round(Zahl - 0.5);

Was dann wieder trunc entspricht.

@Topic:

IMHO liegt das ganze an der Ungenauigkeit der Gleitkommazahlen. Wenn sich 3,7 mit dem Datentyp nicht genau darstellen lassen, kommt eben auch nicht 1 heraus.

2 mögliche Lösungen:
  • Nimm eine andere Einheit z.B. Millimeter und rechne mit Ganzzahlen.
  • Addiere vor dem Abrunden einen Toleranzwert (1 mm oder weniger [einfach mal probieren]).
Evtl. könnte es bei Lösung zwei auch nützlich sein, einen anderen Datentypen mit höherer Genauigkeit, z.B. Double oder Currency zu wählen, wenn der Toleranzwert möglichst klein sein soll.

[edit]Aber taaktaaks Lösung ist einfacher und vermutlich die passende für dein Problem.,gibt aber im manchen Fällen, z.B. 2.25, Kommazahlen aus, nicht wie sinnvollerweise gefordert, Ganzahlen.[/edit]

MfG,
Bug

Medium 2. Okt 2008 00:02

Re: Teilen
 
Zitat:

Zitat von taaktaak
Delphi-Quellcode:
label1.caption:=floattostr(3.7/3.7);             // label zeigt 1

Ich gehe stark davon aus, dass der Compiler die Literale bereits zur Compiletime optimiert, und zusätzlich rechnet der TE noch zuvor mit seinen Werten herum. Er hat ja nicht 3.7 als Literal im Code, und auch keine Variablen denen er beiden je direkt diesen Wert zuweist, sondern es ist ein Ergebnis einer Rechnung, und diese kann durch die Funktionsweise von Floats bereits ungenau sein, und dies zieht sich dann eben durch.
Das ist einfach nur wieder ein Fall von "kenne deine Typen, und wisse um ihre Schwächen" ;). Wenn es auf hundertprozentige Genauigkeit ankommt, kommst du um Ganzzahltypen nicht herum. Man büßt dafür allerdings die maximale Anzahl der Nachkommastellen ein, und handelt sich sobald mehr als nur Addieren/Subtrahieren vor kommt erneut Fehler durch die nötige Rundung ein.
Manchmal ist es aber auch schon genug, die Rechnungen umzustellen, anders zu klammern, und generell Operatoren zu minimieren. Ob und wo das reicht ist aber von Fall zu Fall sehr unterschiedlich.


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:09 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz