AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Nur x Nachkommastellen von Float

Ein Thema von anse · begonnen am 2. Okt 2023 · letzter Beitrag vom 10. Okt 2023
 
Michael II

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
772 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: Nur x Nachkommastellen von Float

  Alt 8. Okt 2023, 01:40
Double Zahlen sind etwas gefährlich. Die Mantisse bei double ist 52 Bits gross. Wenn ein Dezimalbruch binär geschrieben unendlich viele Stellen hat, dann kann die Mantisse mit ihren 52 Bits unendlich viele der 1en nicht aufnehmen.

Beispiel 0.1(10) ist binär geschrieben periodisch 0.000110011001100....(2) mit Periode 1100. D.h. die Dezimalzahl 0.1 lässt sich als double nicht genau abspeichern. Es werden nur die ersten 52 Bits NACH der ersten 1 (implizites Bit) abgespeichert.

Wenn zum Beispiel genau die ersten 52 Bits der Binärdarstellung eines solchen Bruchs abgespeichert werden, dann ist der effektiv abgespeicherte Wert etwas zu klein (Bits 53+ gehen alle verloren).

Delphi-Quellcode:
procedure testD;
var avalue, d1, d2 : double;
   a,b, res : integer;
begin
  avalue := 98.103;
  d1 := frac(avalue);
  d2 := d1 * 1000;
  res := trunc(d2);
  showmessage(res.ToString);
  showmessage(getdigits(avalue,3).ToString );
end;
wobei GetDigits die weiter oben vorgeschlagene Funktion ist.
Wenn der Code oben in Delphi ausgeführt wird, dann ist d1=0.102999999999994; der Output lautet beide Male 102; wir hätten gern 103.

Was helfen kann:
Wenn man den gespeicherten Wert um den kleinstmöglichen Wert Epsilon = 0 00 00 00 00 00 01 (hex) erhöht, dann liegt im Speicher neu eine etwas zu grosse Zahl. trunc funktioniert dann wie erwartet.

Hinweis: Der Code plusepsilon (unten) kann Plattform abhängig sein und berücksichtigt den Fall "alle 52 Mantissenbits=1" nicht.

Delphi-Quellcode:
function plusepsilon(d: Double): Double;
// addiert die kleinstmögliche zahl zu d.
// Bedingung: d>0
var
  Bits: Int64 absolute d;
begin
  Inc(Bits);
  Result := d;
end;

procedure testD;
var avalue, d1, d2 : double;
   a,b, res : integer;
begin
  avalue := plusepsilon(98.103);
....
(Es gibt natürlich weitere, weniger "mathematische" Lösungen... )
Michael Gasser

Geändert von Michael II ( 8. Okt 2023 um 22:11 Uhr)
  Mit Zitat antworten Zitat
 


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 21:52 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