![]() |
Delphi-Version: 5
Nachkommastellen von Extended abschneiden um Integer zu erhalten
Liste der Anhänge anzeigen (Anzahl: 2)
Hallo Zusammen,
ich habe jetzt mit dem bekannten Problem von 0.1 bei Extended Zahlen zu kämpfen. Zur Entwurfszeit steht der Cursor auf AIMINGRESULT und hat de Wert 24.1 * 10 sollte eigentlich 241 ergeben. Mit Trunc möchte ich danach den Extended in ein Integer umwandeln um die 241 als Integer in die DB zu schrieben. Doch aus 24.1 * 10 ergibt nicht 241 sondern 240. Hat jemand eine Idee ich ich zuverlässig aus einem Extended mit 10 multiplizieren kann und danach evl. vorhandene Nachkommastellen abschneiden kann so dass ich einen Integer bekomme? |
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Also bei mir ergibt 24.1 * 10.0 genau 241
Code:
Also müsstest du (AIMINGRESULT * 10.0).AsInterger in die Datenbank schreiben.
var iDummy: Integer;
iDummy := (24.1 * 10.0); |
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
ja, bei mir auch wenn ich es so teste.
Die 24.1 werden aus mehreren Werten zusammen addiert und genau das führ zu diesem Seiteneffekt. Es hängt damit zusammen wie Float Werte verarbeitet werden.
Code:
var a,b,c:extended;
begin inherited; a := 8.0; b := 8.4; c := a + b + 7.7; ShowMessage(Trunc(c * 10).ToString); [Edit] ich könnte für meinen Fall anstelle von extended auch real verwenden. Dann würde zumindest dieser Fall funktionieren aber es muss doch eine zuverlässige Lösung dafür geben oder? [Edit2]
Code:
var a,b,c,d,e:extended; i:integer; begin inherited; a := 8.0; b := 8.4; c := 7.7; d := a + b + c; e := d * 10.0; // hier ist der Wert immer noch richtig e=241. i := Trunc(e); //Trunc schneidet nicht ab sondern Rundet oder konvertiert. ShowMessage(i.ToString); |
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Bei mir geht das, wenn man das TRUC weg lässt:
Code:
var a,b,c:extended;
begin a := 8.0; b := 8.4; c := a + b + 7.7; ShowMessage((c * 10.0).ToString); // <-- Ergibt bei mir 241; end; |
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
es könnten eben Nachkommastellen entstehen je nachdem was addiert wird. Ich benötige nach der Addition NUR die vor Kommastellen abgeschnitten nicht gerundet.
|
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Du schreibst du willst nicht runden. Darum kommst du nicht rum, wenn du mit trunc arbeitest. trunc rundet immer gegen 0: Wenn der in e:extended gespeicherte Wert zwar nahe einer integer Zahl i liegt, aber etwas unter i, dann liefert trunc(e) den Wert i-1 zurück.
Du schreibst weiter oben im Code // e := d * 10.0; // hier ist der Wert immer noch richtig e=241. - Das stimmt nicht; da "betrügt" dich die IDE. Fall A: In e.frac ist nach e := d * 10.0; 1111000011111111111111111111111111111111111111111111111111 111111 gespeichert (gespeicherter Wert in e 240.höchstdarstellbare Nachkommazahl) Fall B: Wohingegen nach e := 241; in e.frac 1111000100000000000000000000000000000000000000000000000000 000000 gespeichert ist - also genau 241. Da trunc gegen 0 rundet, wird im Fall A 240 (11110000) ausgegeben, im Fall B 241 (11110001). Es gibt diverse Möglichkeiten, das Problem zu lösen (und viele Beiträge dazu in DP). ![]() ![]() Daran denken, dass extended unter Win32 genauer ist als unter Win64 (extended=double) und damit nicht die gleichen "Rundungsprobleme" aftreten. ![]() |
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Das gemeine darin ist auch, dass diese Problematik an unterschiedlichen Stellen im Zahlenraum auftritt, je nachdem ob man mit Single, Double oder Extended arbeitet.
|
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Eine Möglichkeit wäre, in String zu konvertieren, nach dem Komma abscheiden und wieder ein Integer daraus machen, das das ist doch sicherlich nicht dir Lösung.
In diesem speziellen Fall kann ich zuverlässig sagen, ich habe zwei Stellen. Für die eine habe ich immer zuverlässig eine Nachkommastelle und für den anderen Fall haben ich zuverlässig immer nur zwei Nachkommastellen. Der Bereich geht von 0.0 bis 799.9 oder 0.0 bis 799.99 |
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Zitat:
Delphi-Quellcode:
So vielleicht?
var Value:Extended; IntValue:Integer; Value:=24.1 * 10; IntValue:=Trunc(Value+0.5); |
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Zitat:
Trunc(1.9) = 1 Trunc(1.9+0.5) = 2 Aber ja, ein +0.00…001 und dann Trunc, wäre eine mögliche Lösung, allerdings nur, wenn es kleiner ist, als real vorkommende Nachkommastellen. Oder vielleicht auch ein RoundTo mit einem passenden SetFPURoundMode. Oder ... |
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Es kommt halt drauf an, wie hoch der Nachkommastellenwert gehen kann bevor er abgeschnitten werden soll. Wir wissen ja noch nichts über die Bedeutung dieser Werte und was mit dem Abschneiden erreicht werden soll. Wenn ein Wert z.B. ungefähr 4.999999999 entspricht, soll das dann wirklich 4 werden oder gilt das dann eher als 5?
|
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Abgesehn davon, dass Extended "ursprünglich" nie dafür gedacht war von Entwicklern zur Speicherung genutzt zu werden,
weswegen es das anfangs in vielen anderen Sprachen (C++) garnicht gab, bzw. teilweise immernoch nicht gibt. Merkt man jetzt, dass es in Bezug auf Win64 und Multiplatform (Android/iOS) wieder nicht mehr gibt. Kann man von der Verwendung von Extended sowieso nur ausdrücklich von abraten.
Delphi-Quellcode:
Schon erklärt sich, warum vermeintlich "Identisches" eigentlich nur annähernd gleich ist
Value := 24.1 * 10; // löst der Compiler auf und nimmt direkt 241.0
Value := 24.1; Value := Value * 10; // wird erst zur Laufzeit gerechnet (mit den aktuellen Möglichkeiten und Einstellungen der FPU) und sich somit doch unterscheiden kann, vor allem in Bezug darauf, wann und wie bezüglich der Ungenauigkeiten von Fließkommazahlen es sich leicht abweichen muß. 241.00000000…001 241.00000000…000 241.99999999…999 |
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Zitat:
|
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Das Problem ist hier eigentlich die Verwendung von Trunc statt Round bzw. RoundTo. Zur internen Darstellung einer Float-Zahl wird die nächstgelegene Zahl verwendet, die mit der aktuellen Auflösung darstellbar ist. In den Fällen, wo das nicht exakt machbar ist, kann die dargestellte Zahl kleiner oder größer als die gewünschte Zahl sein, je nachdem welche näher dran liegt. Bei einer kleineren Zahl liefert ein Trunc dann aber nicht das erwartete Ergebnis.
Leider gibt es kein Allheilmittel für dieses Problem, da es immer von der aktuellen Bedeutung der Zahl und deren Verwendung abhängt. Unter der Annahme, dass eine Genauigkeit von zwei Nachkommastellen ausreicht, kann man ein RoundTo auf die zwei Stellen machen und darauf dann das Trunc loslassen. Alternativ multipliziert man mit 1000, macht ein Round auf Integer mit anschließendem DIV 10. Es gibt viele Wege, aber für alle braucht es etwas Kontext. |
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Meine Zahlen haben einen Bereich von 0.0 bis 799.99. Die Zahlen kommen von Maschinen die dessen Werte über RS232 senden. Je nachdem wie die Maschine eingestellt ist, werden die Werte mit einer oder zwei Nachkommastellen gesendet. Die einzelnen Werte werden zu einem Gesamtergebnis addiert. Jetzt kann es vorkommen dass die Maschine ein- oder zweistellig sendet und das Ergebnis jedoch OHNE der Nachkommazahl addiert werden soll. Wenn das Ergebnis als Ganzzahl benötigt wird ist das Ergebnis bei 9.1 + 9.9 = 18 als NUR 9 + 9. Wenn das Ergebnis mit einer Nachkommastelle benötigt wird, dann muss das Ergebnis 9.1 + 9.9 = 19 sein. Ich habe also wirklich die Anforderung nicht zu runden sondern bei Bedarf die Nachkommastellen abzuschneiden.
|
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
![]() ![]() ![]() ![]() ![]() PS: {$EXTENDEDCOMPATIBILITY OFF} {$EXCESSPRECISION ON} ![]() ... |
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Wenn die Werte schon mit nur bis zu zwei Nachkommastellen ankommen, dann könntest du die ja auch als Currency speichern. Das ist ja so wie Integer mit (bis zu vier) Nachkommastellen. Multiplizieren und Dividieren passiert dann ja offenbar nicht und wenn es dann nach dem Trunc erstmal Integer sind, ist ja eh alles easy.
|
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Zitat:
Wenn du keine Fließkommazahlen verwendest, vermeidest du auch alle Probleme in der Richtung. Solange du nur addieren musst, kannst du das alles vollkommen problemlos mit Integerwerten umsetzen. |
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Zitat:
Dann erhält man die ganzzahligen Werte mittels div 100 und die Nachkommastellen mittels mod 100. Und wenn man addiert, erhält man wieder eine Zahl, für die dasselbe gilt. Bei halbwegs modernem Delphi kann man das sogar in einen enhanced Record packen. |
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Zitat:
Ausrede für Helden: Es ging um 24.1*10, nicht um 1.9. |
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Die Werte die ich über RS232 bekommen sind Strings mit keiner, einer oder zwei Nachkommastellen. Nach dem Empfang werden die sie in einen Array of Record, da es noch weitere Daten pro Datensatz gibt. Das Feld für den Zahlenwert werde ich jetzt vom extended auf Real umstellen. Wie gesagt, die Einzelwerte die ich bekomme sind im Bereich von 0.0 bis 799.99 Maximal können 100 einzelne Werte zusammenaddiert werden. In die Datenbank muss ich dann eh ein Integer speichern. Die Auswertungen können jedoch ohne Nachkommastellen, mit einer oder zwei Nachkommastellen notwendig sein.
Vielen lieben Dank für die aktive Hilfe. |
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Zitat:
Warum bleibst du nicht einfach gleich bei Integer? Dann hast du doch keinerlei Probleme mehr damit. |
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Eigentlich hast du recht. Dann formatiere ich eben nur fürs Reporting und arbeiten intern auch mit Integer.
Ja, dann mache ich das genau so. Dankeschön nochmals. |
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Zitat:
|
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Oder Ceil oder Floor aus Math, da ist wenigstens klar, was sie machen. Es gibt im Übrigen auch RoundTo (nicht Round Two :-), vielleicht hilft das
|
AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
Integer und mit einem zusätzlich einen Faktor ist wahrscheinlich die beste Lösung.
Genau das macht auch Currency (Faktor ist 1000). Leider beherscht Delphi nicht von Haus aus Numeric(), dass arbeitet in Datenbanken genau wie Currency, aber man kann die Anzahl der Vor-und Nachkommastellen angeben. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:12 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