Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Nachkommastellen von Extended abschneiden um Integer zu erhalten (https://www.delphipraxis.net/215201-nachkommastellen-von-extended-abschneiden-um-integer-zu-erhalten.html)

Kostas 26. Mai 2024 17:43

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?

DaCoda 26. Mai 2024 18:12

AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
 
Also bei mir ergibt 24.1 * 10.0 genau 241

Code:
var iDummy: Integer;

iDummy := (24.1 * 10.0);
Also müsstest du (AIMINGRESULT * 10.0).AsInterger in die Datenbank schreiben.

Kostas 26. Mai 2024 18:36

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);

DaCoda 26. Mai 2024 19:01

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;

Kostas 26. Mai 2024 19:43

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.

Michael II 26. Mai 2024 23:42

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).

Data.FmtBcd
Currency (Im "Mischbetrieb" mit extended und Co treten natürlich ähnliche Probleme auf)
Daran denken, dass extended unter Win32 genauer ist als unter Win64 (extended=double) und damit nicht die gleichen "Rundungsprobleme" aftreten.
setroundmode - Rundungsverhalten der FPU steuern - zum Beispiel: setroundmode( rmUp );

Uwe Raabe 27. Mai 2024 09:59

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.

Kostas 27. Mai 2024 12:21

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

Amateurprofi 27. Mai 2024 15:21

AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
 
Zitat:

Zitat von Kostas (Beitrag 1537154)
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?

Delphi-Quellcode:
So vielleicht?
var
   Value:Extended;
   IntValue:Integer;
Value:=24.1 * 10;
IntValue:=Trunc(Value+0.5);

himitsu 27. Mai 2024 15:25

AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
 
Zitat:

+0.5
Bei 0.9 würde dann aber +1 rauskommen.

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 ...

Uwe Raabe 27. Mai 2024 15:30

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?

himitsu 27. Mai 2024 15:41

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:
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)
Schon erklärt sich, warum vermeintlich "Identisches" eigentlich nur annähernd gleich ist
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

dummzeuch 27. Mai 2024 16:32

AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
 
Zitat:

Zitat von himitsu (Beitrag 1537203)
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.

Das würde aber hier keinen Unterschied machen, da dasselbe Problem auch mit Single oder Double auftritt.

Uwe Raabe 27. Mai 2024 16:44

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.

Kostas 27. Mai 2024 19:23

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.

himitsu 27. Mai 2024 19:34

AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
 
Delphi-Referenz durchsuchenSystem.Currency :stupid: http://docwiki.embarcadero.com/RADSt...)#Reelle_Typen
Delphi-Referenz durchsuchenSystem.Extended
Delphi-Referenz durchsuchenBCD (https://www.sps-lehrgang.de/bcd-code/)


PS:
{$EXTENDEDCOMPATIBILITY OFF}
{$EXCESSPRECISION ON}
http://docwiki.embarcadero.com/RADSt...e_Applications
...

Uwe Raabe 27. Mai 2024 21:08

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.

jaenicke 28. Mai 2024 01:16

AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
 
Zitat:

Zitat von Kostas (Beitrag 1537216)
Meine Zahlen haben einen Bereich von 0.0 bis 799.99. Die Zahlen kommen von Maschinen die dessen Werte über RS232 senden.

Bei solchen Protokollen werden die Zahlen oft als String übertragen. Ist das auch hier der Fall? Wenn ja, dann speichere die Werte einfach als Integer vor dem Komma plus Nachkommateil ebenfalls als Integer.

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.

dummzeuch 28. Mai 2024 07:49

AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
 
Zitat:

Zitat von jaenicke (Beitrag 1537224)
Zitat:

Zitat von Kostas (Beitrag 1537216)
Meine Zahlen haben einen Bereich von 0.0 bis 799.99. Die Zahlen kommen von Maschinen die dessen Werte über RS232 senden.

Bei solchen Protokollen werden die Zahlen oft als String übertragen. Ist das auch hier der Fall? Wenn ja, dann speichere die Werte einfach als Integer vor dem Komma plus Nachkommateil ebenfalls als Integer.

Oder den Wert * 100, was bei dem Wertebereich problemlos in einen Integer passt (Int16 ist out, ebenso UInt16, wegen des Wertebereichs).

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.

Amateurprofi 28. Mai 2024 16:57

AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
 
Zitat:

Zitat von himitsu (Beitrag 1537201)
Zitat:

+0.5
Bei 0.9 würde dann aber +1 rauskommen.

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 ...

Recht hast Du.
Ausrede für Helden: Es ging um 24.1*10, nicht um 1.9.

Kostas 28. Mai 2024 19:28

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.

jaenicke 28. Mai 2024 19:39

AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
 
Zitat:

Zitat von Kostas (Beitrag 1537254)
Das Feld für den Zahlenwert werde ich jetzt vom extended auf Real umstellen.
[..]
In die Datenbank muss ich dann eh ein Integer speichern.

Wie schon geschrieben:
Warum bleibst du nicht einfach gleich bei Integer? Dann hast du doch keinerlei Probleme mehr damit.

Kostas 28. Mai 2024 20:03

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.

himitsu 28. Mai 2024 20:08

AW: Nachkommastellen von Extended abschneiden um Integer zu erhalten
 
Zitat:

Zitat von himitsu (Beitrag 1537217)

:stupid:

TomyN 29. Mai 2024 13:46

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

Blup 30. Mai 2024 12:27

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