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
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von anse
anse

Registriert seit: 30. Okt 2006
Ort: Neuenkirchen
197 Beiträge
 
Delphi 11 Alexandria
 
#1

Nur x Nachkommastellen von Float

  Alt 2. Okt 2023, 18:05
Nabend zusammen,

es gibt ja System.Trunc, um den Integer Teil eines Floats zu bekommen.
Gibt es quasi als Gegenstück eine Funktion die nur die ersten Ziffern des Dezimalteils liefert?
Also z.B. sowas
Code:
GetDigits(10.234567, 3); => "234"
Meine Alternative funktioniert auch aber finde ich nicht schön:
  1. Integer-Teil vom Float subtrahieren: 10.234567 - 10 => 0.234567
  2. Ergebnis mit 1000 mulitiplizieren: => 234.567
  3. System.Trunc() darauf: => 234
Ansgar Becker
https://www.heidisql.com
Wenn du loslässt, hast du zwei Hände frei.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#2

AW: Nur x Nachkommastellen von Float

  Alt 2. Okt 2023, 18:29
Punkt 1 ließe sich auch durch Frac(x) ersetzen.
Wenn es Runden statt Abschneiden sein darf, dann wäre RoundTo eine Alternative. Theoretisch kann man vorher mit SetRoundMode einstellen, wie das erfolgen soll (damit ginge auch ein truncate), aber das ist natürlich nicht threadsicher.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
mmw
(Gast)

n/a Beiträge
 
#3

AW: Nur x Nachkommastellen von Float

  Alt 2. Okt 2023, 18:57
hallo,
evtl. so (Rohversion)
Delphi-Quellcode:
function GetDigits(Value:EXTENDED;digit:integer):Extended;

var
   value1,
   value2:extended;

begin
 value1:=0;
 value2:=0;
  value1:=frac(value);
  value2:=Power(10,digit);
 result:=trunc(value1*value2);
end;
Gruß
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#4

AW: Nur x Nachkommastellen von Float

  Alt 2. Okt 2023, 22:39
Da digit ein Integer ist, bietet sich auch IntPower an:
Delphi-Quellcode:
function GetDigits(const AValue: Double; Digits: Integer): Integer;
begin
  Result := Trunc(Frac(AValue)*IntPower(10, Digits));
end;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von anse
anse

Registriert seit: 30. Okt 2006
Ort: Neuenkirchen
197 Beiträge
 
Delphi 11 Alexandria
 
#5

AW: Nur x Nachkommastellen von Float

  Alt 3. Okt 2023, 14:10
Vielen Dank, das sieht schon eleganter/lesbarer aus!
Ansgar Becker
https://www.heidisql.com
Wenn du loslässt, hast du zwei Hände frei.
  Mit Zitat antworten Zitat
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
Andreas13

Registriert seit: 14. Okt 2006
Ort: Nürnberg
719 Beiträge
 
Delphi XE5 Professional
 
#7

AW: Nur x Nachkommastellen von Float

  Alt 8. Okt 2023, 10:57
Hallo Michael,
so einfach läßt sich das Problem der Rundungsfehler leider nicht lösen. Eigentlich gibt es überhaupt keine Lösung dafür. Denn es wird nicht nur abgerundet, sondern auch mal aufgerundet. Und dann müßte Dein plusepsilon ein minusepsilon sein.

Sorry, Deine Lösung ist nicht „mathematisch“, sondern willkürlich an diese eine Aufgabe zugeschnitten.

Was einzig alleine hilft, sind mehr, vieeeeeel mehr Stellen, also nicht Double, sondern Extended, quad precision, oder oft nur Multi-Precisions-Arithmetik (MPA) mit hunderten ... tausenden Nachkommastellen, wobei das Ergebnis am Ende aller Berechnungen auf das Zielformat gerundet wird.

Über diese Problematik haben sich schon viele Forscher den Kopf zerbrochen und zahlreiche gute Artikel und Fachbücher publiziert, ohne ein Patentrezept verkünden zu können...
Grüße, Andreas
Wenn man seinem Nächsten einen steilen Berg hinaufhilft, kommt man selbst dem Gipfel näher. (John C. Cornelius)
  Mit Zitat antworten Zitat
Michael II

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

AW: Nur x Nachkommastellen von Float

  Alt 8. Okt 2023, 14:35
Hallo Michael,
Denn es wird nicht nur abgerundet, sondern auch mal aufgerundet. Und dann müßte Dein plusepsilon ein minusepsilon sein
Es darf für positive Zahlen nie minusepsilon sein:
Wenn ein Dezimalbruch binär periodisch ist, dann wird das System beim Speichern von double wahrscheinlich entweder aufrunden, wenn das 53ste Bit=1 ist oder aber ab Bit 53 abschneiden (und damit abrunden). Das System speichert also entweder z1<z oder z2>z. Im Intervall ]z1,z2[ kann das Format nix speichern.
Es gibt also 2 Fälle.
1. Das System hat abgeschnitten oder abgerundet und speichert z1. Wir addieren Epsilon und landen bei z2>z und trunc() wird den erwarteten Wert ermitteln.
2. Das System hat aufgerundet und hat z2 gespeichert. Wir könnten also mit z2 weiterrechnen und trunc() wäre OK. z3:=plusepsilon(z2)=z2+Epsilon ist der nächstgrössere speicherbare Wert nach z2. Also z3>z2>z. Wenn die Stellengenauigkeit vom verwendeten Format gross genug ist für das gegebene Problem, dann fällt es nicht ins Gewicht, dass wir nicht mit z2 weiterrechnen. Wenn wir aber wie du schreibst abrunden würden, dann würden wir bei z1 := z2-Epsilon landen. Wir wissen aber z1<z und damit rechnen "wir" beim trunc() wieder falsch. Also keine gute Idee.
Michael Gasser

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

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

AW: Nur x Nachkommastellen von Float

  Alt 8. Okt 2023, 15:09
.

Sorry, Deine Lösung ist nicht „mathematisch“, sondern willkürlich an diese eine Aufgabe zugeschnitten.

Was einzig alleine hilft, sind mehr, vieeeeeel mehr Stellen, also nicht Double, sondern Extended, quad precision, oder oft nur Multi-Precisions-Arithmetik (MPA) mit hunderten ... tausenden Nachkommastellen, wobei das Ergebnis am Ende aller Berechnungen auf das Zielformat gerundet wird.

Über diese Problematik haben sich schon viele Forscher den Kopf zerbrochen und zahlreiche gute Artikel und Fachbücher publiziert, ohne ein Patentrezept verkünden zu können...
Du schreibst, die Lösung sei auf das Problem zugeschnitten. Dafür gebe ich dir 100 Punkte . Eine Lösung sollte auf die gestellte Aufgabe zugeschnitten sein. Die vorher angegebenen Vorschläge lieferten zwischen 123.000000 und 123.999999 in mindestens 496 Fällen nicht das korrekte Resultat.

Mit Willkür hat das nix zu tun. Aber du hast Recht, das ist 1. Semster Informatik Stoff und hat mit Mathe nicht viel zu tun - eher mit Rechnen.

Du schreibst Extended[/URL"]extended wäre besser. Mehr Binärstellen nützen leider nicht viel:
Dezimalbrüche, welche binär periodisch sind können in einem binären Format (wie von single, double, extended verwendet) nie genau gespeichert werden. Mit extended erhöhst du lediglich die Stellengenauigkeit (extended: floor(log(2^63)/log(10) - generell log(2^n)/log(2) = n*log(2)/log(10) - d.h. pro weiteres Bit für den fraction Teil gewinnst du ungefähr 0.301 Stellen). Wenn du für das in #1 geschilderte Problem als Input Zahlen mit vielen Stellen erwartest, dann nimm extended. Für die trunc()erei wirst du bei solchen Datentypen um das Epsilon nicht herumkommen.

Es gibt sicher Leute, welche das Speichern und das Rechnen mit solchen Daten als "Forschung" bezeichnen. Mich wundert heute nix mehr
Michael Gasser

Geändert von Michael II ( 8. Okt 2023 um 16:55 Uhr)
  Mit Zitat antworten Zitat
mmw
(Gast)

n/a Beiträge
 
#10

AW: Nur x Nachkommastellen von Float

  Alt 8. Okt 2023, 21:14
Hallo,

als Korrektur zu #3, (mit DOUBLE gab's Probleme)

Delphi-Quellcode:
function GetDigits(const AValue: Extended; Digits: Integer): Integer;

var
    value:Extended;
    value1:Real;

begin
   value:=frac(AValue)*intpower(10,digits);
   value1:=value;
   Result := trunc(value1);
end;

Gruß
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 17:16 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