Einzelnen Beitrag anzeigen

Michael II

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

AW: Nur x Nachkommastellen von Float

  Alt 8. Okt 2023, 02: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 23:11 Uhr)
  Mit Zitat antworten Zitat