Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Auf 2 stellen Runden (https://www.delphipraxis.net/102397-auf-2-stellen-runden.html)

Kuster Peter 27. Okt 2007 21:48


Auf 2 stellen Runden
 
Habe bisher mit Fox Pro gearbeitet und stehe auf dem Schlauch:


Runden: Ich will eine Zahl auf 2 Stellen runden, meine Test funktioniert nicht, es will einfach die Funktion roundto nicht akzeptieren:

Delphi-Quellcode:
var
  Form1: TForm1;
  rech1 : single;
  rech2 : single;
  rech3 : single;

implementation

{$R *.dfm} 

procedure TForm1.Button1Click(Sender: TObject);
begin
      rech1 := 8;
      rech2 := 9;
      rech3 := rech1 / rech2;
      label1.Caption := floattostr(roundto(rech3, -2));
end;
Peter

Dax 27. Okt 2007 21:50

Re: Auf 2 stellen Runden
 
Delphi ist nun mal nicht FoxPro.
Delphi-Quellcode:
function Round(e: Extended; precision: Integer): Extended;
var factor: Extended;
begin
  factor := Power(10, precision);
  Result := Round(e * factor) / factor;
end;

DP-Maintenance 27. Okt 2007 21:57

DP-Maintenance
 
Dieses Thema wurde von "Matze" von "Programmieren allgemein" nach "Sonstige Fragen zu Delphi" verschoben.
Delphi-Frage

Hawkeye219 27. Okt 2007 22:01

Re: Auf 2 stellen Runden
 
Hallo Peter,

du mußt die Unit Math in die USES-Anweisung aufnehmen, um die Funktion RoundTo nutzen zu können.

Gruß Hawkeye

Progman 27. Okt 2007 22:14

Re: Auf 2 stellen Runden
 
warum nimmst du nicht
Delphi-Quellcode:
FloatToStrF(Wert, ffFixed, 8, 2);
Das ergibt immer zwei korrekt gerundete Nachkommastellen.

eddy 28. Okt 2007 01:14

Re: Auf 2 stellen Runden
 
Hallo Leute,

mit dem Runden habe ich so meine Probleme.

Zum Beispiel wird aus 30,14500 beim runden immer 30,14000 statt 30,15000

aus 3,145 wird 3,15
aus 4,145 wird 4,14
... zum Testen jeweils um Eins erhöht
aus 31,145 wird 31,14
aus 32,145 wird 32,15


Hat jemand dafür eine Erklärung?


@Hawkeye:
Die Funktion RoundTo gibt es bei mir auch mit der Unit Math nicht.

mfg
eddy

Mackhack 28. Okt 2007 03:46

Re: Auf 2 stellen Runden
 
Ich glaube zu diesem Thema mit dem Kaufmännischen Rundungsverhalten von Delphi gabs schon mal min. einen Thread!

Versuch mal was zu finden mit der Suchfunktion!

grenzgaenger 28. Okt 2007 09:16

Re: Auf 2 stellen Runden
 
Zitat:

Zitat von eddy
Hallo Leute,

mit dem Runden habe ich so meine Probleme.

Zum Beispiel wird aus 30,14500 beim runden immer 30,14000 statt 30,15000

aus 3,145 wird 3,15
aus 4,145 wird 4,14
... zum Testen jeweils um Eins erhöht
aus 31,145 wird 31,14
aus 32,145 wird 32,15


Hat jemand dafür eine Erklärung?


@Hawkeye:
Die Funktion RoundTo gibt es bei mir auch mit der Unit Math nicht.

mfg
eddy

das ist das sogenannte Bankers Rounding, welches in der FPU implementiert ist, da die Round Funktion diese Funktion verwendet, wird es automatisch wie oben Formatiert. genaueres, in der OH.

bitsetter 28. Okt 2007 11:01

Re: Auf 2 stellen Runden
 
Zitat:

Zitat von eddy
Hallo Leute,

mit dem Runden habe ich so meine Probleme.


aus 31,145 wird 31,14

Hast du es schon mal mit
Delphi-Quellcode:
ShowMessage(Format('%.2f', [31.145]));
versucht?

Kuster Peter 28. Okt 2007 15:59

Re: Auf 2 stellen Runden
 
Hallo Leute

Aufgrund Euerer Antworten ist mir plötzlich eine Lösung eingefallen, die in allen Programmiersprachen funktioniert:

Klar Fox ist nicht Delphi, darum wechsle ich auch auf Delphi und verlasse das Fox, doch ich habe eine Lösung, die ich vom Fox her abgewandelt habe:

Beispiel:

Delphi-Quellcode:
var
  Form1: TForm1;
  rech1 : single;
  rech2 : single;
  rech3 : single;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
      rech1 := 8;
      rech2 := 9;
      rech3 := rech1 / rech2;
      label1.Caption := floattostr(round(rech3 * 100) / 100);
end;
Und wenn wir schon dabei sind, hier meine Lösung um auf 5 zu Runden, was man in der CH braucht:

Delphi-Quellcode:
var
  Form1: TForm1;
  rech1 : single;
  rech2 : single;
  rech3 : single;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
      rech1 := 2.75;
      rech2 := 55;
      rech3 := rech1 / rech2;
      label1.Caption := floattostr(round(rech3 * 20) / 20);
end;

Also vielen Dank für die Tipps, doch so unter uns, bin verdammt stolz, dass ich eine Lösung gefunden habe.

Peter

Kuster Peter 28. Okt 2007 16:13

Re: Auf 2 stellen Runden
 
Liebe Delphianer

Meine Antwort oben tönt beim Durchlesen etwas hochnäsig. Sorry, das will ich nicht, im Gegenteil, Eure Tipps sind echt gut und ich habe wieder viel gelernt, z.B. dass man Math in die Uses Anweisung einbeziehen muss etc. Alles Sachen, die mir in Zukunft helfen. Wirklich vielen Dank.

Stolz bin ich, weil ich eine Lösung gefunden habe, die einfach ist, die man ohne zusätzliche Anweisungen anwenden kann und die 100 % funktioniert und dass ich das erste Mal eine Lösung beisteuern konnte, auch wenn ich die Frage aufgeworfen habe, doch der Eddy hat das Problem auch.

Also meine Antwort nicht flasch verstehen.

Delphi gefällt mir immer besser und ich weine dem Fox bald keine Träne mehr nach!!

Ich wünsche allen eine schöne Woche.

Peter

grenzgaenger 28. Okt 2007 17:08

Re: Auf 2 stellen Runden
 
tja, für die 5 rappen rundung haste recht. aber das andere, kannst du dir sparen, das geht so..

Delphi-Quellcode:
CurrToStrF(12.355, ffFixed, 2)
PS: Peter, du verwendest auch das bankers rounding. kannst mal ausprobieren:
Delphi-Quellcode:
 writeln('Round 12.5: ', round(12.5));
 writeln('Round 13.5: ', round(13.5));
denke, da kommt 'n anderes ergebnis raus, wie du gerne möchtest

eddy 30. Okt 2007 11:22

Re: Auf 2 stellen Runden
 
Hallo Leute,

das Stichwort "bankers rounding" hat's gebracht, man muß eben wissen, wonach man suchen muß!

Allerdings kommt "bankers rounding" mit jedem Taschenrechner in Konflikt. Und auf einer Rechnung sollten die Zahlen nun mal stimmen und nicht von der Berechnung mit einem Taschenrechner abweichen. Egal welche logische oder historische Erklärung es für die Abweichung gibt.

Das mathematischen Runden liefert ein Ergebnis, das ein Taschenrechner auch her gibt.

Delphi-Quellcode:
//liefert auf nk-Stellen mathematisch gerundete Zahl r zurück
// MathRound <--> bankers rounding nur bei 0.005
function mround(r : double; nk : integer = 2) : double;
var
  diff,
  r2,
  multi: double;
begin
  r2 := abs(r);
  multi:=IntPower(10, nk);     // uses Math
  diff := Frac(r * multi);     // Nachkommaanteil von r
  // if diff = 0.5 versagt wg. exponentiell kleiner Abweichungen
  if round(diff * multi) / multi = 0.5
    then r2 := r2 + 0.01 / multi;
  if r >= 0
    then Result := round(r2 * multi) / multi
    else Result := -round(r2 * multi) / multi;
end;
mfg
eddy

Gorlo 12. Okt 2017 10:14

AW: Auf 2 stellen Runden
 
@eddy

Achtung diese Rundungsfunktion ist nicht das eine und nicht das andere. Sie funktioniert NICHT.

Sie ist bei zahlen mit mehr nachkommastellen als die auf der gerundet werden soll falsch.
Beispiel:
mround(0,014, 2) = 0,01
mround(0,01498, 2) = 0,02

PS: Ich kram diesen Thread deswegen wieder raus da er mir bei einer Suche nach Mathematischen runden in Delphi als erstes angezeigt wird und diese Funktion somit falsch verbreitet werden könnte.

sakura 12. Okt 2017 11:28

AW: Auf 2 stellen Runden
 
Liste der Anhänge anzeigen (Anzahl: 1)
Um das Ganze abzuschließen, hier sind gleich mehrere Annahmen falsch.

Beim Banker's Rounding gibt es eine weitere Regelung für den Fall 0.5.

Zusammengefasst:
  • Alle Fälle außer 0.5 verhalten sich identisch zum mathematischen Runden, welches auch in Delphi angewandt wird
  • 0.5 wird im normalen Banker's Rounding immer zur nächsten geraden Zahl gerundet
  • Alternativ wird 0.5 aufgerundet.
Folgender Code deckt genau dieses Verfahren ab, wobei der letzte Parameter für True die Rundung in Richtung gerade durchführt und bei False immer aufrundet.
Delphi-Quellcode:
function BankersRound(const aValue: Double; const aRoundTo: Integer = 2; const aApplyEvenRoundRule: Boolean = True): Double;
var
  PositiveValue,
  IsEven
    : Boolean;
  MultipliedValue,
  FracValue,
  ResolutionDirection
    : Double;
const
  DOUBLE_RESOLUTION = 1E-12;
begin
  if aValue = 0 then
    Exit(0);

  MultipliedValue := Abs(aValue) * IntPower(10, aRoundTo);
  FracValue := Frac(MultipliedValue);

  if not System.Math.SameValue(FracValue, 0.5, DOUBLE_RESOLUTION) then
    Exit(System.Math.RoundTo(aValue, 0 - aRoundTo));

  PositiveValue := aValue > 0;

  if aApplyEvenRoundRule then
  begin
    IsEven := Trunc(MultipliedValue) mod 2 = 0;

    if PositiveValue and IsEven then
      // > 0 and even
      ResolutionDirection := -1
    else if PositiveValue then
      // > 0 and odd
      ResolutionDirection := 1
    else if IsEven then
      // < 0 and even
      ResolutionDirection := 1
    else
      // < 0 and odd
      ResolutionDirection := -1
  end
  else
  begin
    if PositiveValue then
      ResolutionDirection := 1
    else
      ResolutionDirection := -1;
  end;

  Result := System.Math.RoundTo(aValue + ResolutionDirection * DOUBLE_RESOLUTION, -2);
end;
Das gesamte Beispiel inkl. Testfälle ist im Anhang.

...:cat:...

Gorlo 12. Okt 2017 14:45

AW: Auf 2 stellen Runden
 
Dazu nochmal begriff Klarstellung:
Banker's Rounding = Mathematisches Runden
Unser in der schule gelerntes Runden ist das Kaufmännische Runden.
(https://de.wikipedia.org/wiki/Rundung)

In Delphi(5-7) (andere Versionen kann ich gerade nicht nachschauen) nutzt die normale Rundungsfunktion leider das Banker's Rounding (Mathematische Runden).
Fakt ist ICH benötige das Kaufmännisches Runden (für Rechnungen (Einzelpreise 5 stellig da unter 1 Cent somit kein Currency möglich)) und das ist in Delphi(5-7) so nicht einfach möglich.
Auch aus dem Grund da die Double nicht genau genug sind.

Beispiel getestet in Delphi 6:
RoundTo(2194.825, -2) = 2194.82 | Benötigt wird aber 2194.83
Ich habe somit eine Funktion gebaut die mir den wegfallenden Dezimalwert in ein Integer umwandelt den ich dann auf 0-4 bzw. 5-9 prüfen kann. Diese Funktion prüfe ich gerade ob diese auch so funktioniert wie sie soll (was ohne Referenz schwer ist).


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:14 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