Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi runden bis auf 2 stellen hinterm komma, 0 nicht wegschneiden (https://www.delphipraxis.net/100374-runden-bis-auf-2-stellen-hinterm-komma-0-nicht-wegschneiden.html)

agm65 27. Sep 2007 08:34


runden bis auf 2 stellen hinterm komma, 0 nicht wegschneiden
 
ich nochmal schnell.. :)..

folgendes:

Delphi-Quellcode:
(code von [url]http://forum.dsdt.info/[/url])

uses Math;

function RundeAufStelle(zahl: double; stellen: integer): double;
var multi: double;
begin
  multi:=IntPower(10, stellen);
  zahl:=round(zahl*multi);
  result:=zahl/multi;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Label1.Caption:=FloatToStr(RundeAufStelle(1023.23483, 2));
end;
rundet diese zahl bis auf 2 stellen hinterm komma...wenn die zahl jetzt aber nach dem runden so aussieht: 1023.60
wird die 0 abgeschnitten wie kann ich das verhindern ?

marabu 27. Sep 2007 08:37

Re: runden bis auf 2 stellen hinterm komma, 0 nicht wegschne
 
Hallo Peter,

das ist kein Rundungs- sondern ein Anzeigeproblem.

So geht es:

Delphi-Quellcode:
Format('%.2f', [1.60]);
Grüße vom marabu

SirThornberry 27. Sep 2007 08:38

Re: runden bis auf 2 stellen hinterm komma, 0 nicht wegschne
 
das du 0 abgeschnitten wird hat nichts mit dem runden zu tun sonder mit deiner wandlung zum String. FloatToStr zeigt eben so viele Stellen hinter dem Komma an bis eine 0 kommt. Wenn dir das nicht zusagt musst du die Ausgabe formatieren (zum Beispiel mit FormatFloat)

agm65 27. Sep 2007 08:50

Re: runden bis auf 2 stellen hinterm komma, 0 nicht wegschne
 
sauber jungs das läuft !...ich bedanke mich !

peschai 27. Sep 2007 09:16

Re: runden bis auf 2 stellen hinterm komma, 0 nicht wegschne
 
Hallo

Zusatzhinweis: Dein codebeispiel ist gefährlich! was glaubst du passiert, wenn man 32000 Stellen angibt ? Solltest du eventuell abfangen ...

Sourcemaker 27. Sep 2007 13:17

Re: runden bis auf 2 stellen hinterm komma, 0 nicht wegschne
 
Hallo,

Du denkst auch daran das Round das sogenannte Bankers´s Rounding durchführt und nicht
kaufmännisch rundet ?

Beispiel:
Mit Deiner Funktion gerundet ergibt 0,425 0,42 anstatt wie kaufmännisch zu erwarten 0,43.

Links zu dem Thema:
Runden ohne Ecken
Rundung - Wikipedia


Grüße

Frank

marabu 27. Sep 2007 13:54

Re: runden bis auf 2 stellen hinterm komma, 0 nicht wegschne
 
Hallo Frank,

Zitat:

Zitat von Sourcemaker
... Du denkst auch daran das Round das sogenannte Bankers´s Rounding durchführt und nicht kaufmännisch rundet? ...

wer behauptet denn sowas? die FPU ist auf rmNearest eingestellt, was dem half-up mode entsprechen sollte.

Zitat:

Zitat von Sourcemaker
... Mit Deiner Funktion gerundet ergibt 0,425 0,42 anstatt wie kaufmännisch zu erwarten 0,43 ...

Das Ergebnis ist 0.42 - aber nicht aufgrund eines Banker's Rounding:

Delphi-Quellcode:
var
  d: Double;
begin
  d := 0.425; // 0,424999999999999989
  ShowMessage(Format('%.18f', [d]));
end;
Hier liegt kein Rundungs- sondern ein Abbildungsproblem vor.

Freundliche Grüße

Sourcemaker 27. Sep 2007 14:34

Re: runden bis auf 2 stellen hinterm komma, 0 nicht wegschne
 
Hallo Marabu,

das behauptet die Delphi-Hilfe.

Delphi-Quellcode:
Caption := FormatFloat('#0.0000',Round(0.425));
Und das ist der entsprechende Code der ausreichend formatiert seien dürfte.
Und da ich SetRoundMode nicht verändert habe dürfte zumindest in der Standardeinstellung
von Delphi dieses Verhalten vorliegen.

Alternative Standardfunktion ist Delphi´s SimpleRoundTo welches in der Delphi7 Version aber
auch (wie in der Hilfe beschrieben) nicht kaufmännisch rundet sondern bei negativen Zahlen
ein anderes Verhalten aufweist: 0,425 -> 0,43 -0,425 -> -0,42

Dagegen rechnet die gleiche Funktion in Delphi 2007:

0,425 -> 0,43 -0,425 -> -0,43

Schaut man sich den Quellcode in der Unit Math an sieht man die entsprechenden Unterschiede.
Spaßiger weise haben das die Borländer allerdings die Hilfe nicht entsprechend angepaßt
(zumindest in der SP1 nicht).

Die genannten Links belegen übrigens das von mir beschrieben Verhalten.

Grüße

Frank

Sidorion 27. Sep 2007 15:34

Re: runden bis auf 2 stellen hinterm komma, 0 nicht wegschne
 
Dass die Borländer ein setsames Verhältnis zur Mathematik haben, sieht man schon bei Mod.
Hier kommt bei negativen Dividend ein negativer Rest raus und der auch noch Betragsmäßig falsch.

3_of_8 27. Sep 2007 15:39

Re: runden bis auf 2 stellen hinterm komma, 0 nicht wegschne
 
Dafür können die Borländer nichts, da musst du dich schon bei Intel beschweren, die ihren x86er so gebaut haben.

marabu 27. Sep 2007 18:14

Re: runden bis auf 2 stellen hinterm komma, 0 nicht wegschne
 
Hallo,

Zitat:

Zitat von 3_of_8
... da musst du dich schon bei Intel beschweren, die ihren x86er so gebaut haben. ...

die FPU ist historisch gesehen ein x87, aber ich weiß was du meinst.

Zitat:

Zitat von Sidorion
Dass die Borländer ein seltsames Verhältnis zur Mathematik haben, sieht man schon bei Mod.
Hier kommt bei negativen Dividend ein negativer Rest raus und der auch noch Betragsmäßig falsch.

Die MOD Operation bedarf stets der Definition - und es gibt mehr als eine Definition. Borland hat eine Definition gewählt und veröffentlicht: x mod y = x - (x div y) * y. Was ist daran seltsam?

Zitat:

Zitat von Sourcemaker
... das behauptet die Delphi-Hilfe.

Die Behauptung habe ich gelesen. Abgeshen davon, dass deine Code-Zeile das Ergebnis 0.0000 liefert und somit nicht zur Erhellung der Problematik beiträgt, müsste nach deiner Argumentation 0.435 auf zwei Nachkommastellen gerundet 0.44 ergeben - das Eregbnis von RoundTo(0.435, -2) ist aber 0.43:

Delphi-Quellcode:
var
  d: Double;
begin
  d := 0.435; // 0,434999999999999998
  ShowMessage(Format('%.18f', [d]));
end;
Bei der Geschichte mit dem Banker's Rounding wird immer so getan, als ob das Verfahren auf Zahlen im Dezimalsystem ausgeführt würde, die FPU arbeitet aber mit dem dualen System. Und der IEEE Standard 754 spricht auch nicht vom Banker's Rounding:

Aus der HP 9000 Technical Documentation
The default rounding mode is round to nearest. The four rounding modes are:

Round To Nearest

Round to the representable value closest to the true value. If two representable values are equally close to the true value, choose the one whose least significant bit is 0. ...

Mir ist bewusst, dass es Zahlenbeispiele gibt, welche die Verwendung des Sinnbildes rechtfertigen, aber man sollte dabei aufpassen, dass man den Gültigkeitsbereich nicht verlässt. Für Round(10.5) und Round(11.5) wird tatsächlich zur nächsten geraden Zahl gerundet, aber wie man sieht gilt das nicht mehr, wenn RoundTo(value, digit) mit digit = -2 verwendet wird. Hier sei kurz angemerkt, dass RoundTo() sich auf Round() abstützt und die FPU das letzte Wort hat - da ist kein weiterer Pascal Code beteiligt, als der zur Skalierung innerhalb von RoundTo().

Ich erinnere mich an eine Fundstelle (Crawford & Gelsinger: Programming the 80386), wo der von Intel implementierte default rounding mode ohne weitere Erklärungen als "round towards nearest or even" bezeichnet wurde. Die Original Intel Referenz habe ich gerade nicht griffbereit, aber ich vermute, dass es interessant wäre darin zu lesen.

Freundliche Grüße

3_of_8 27. Sep 2007 22:53

Re: runden bis auf 2 stellen hinterm komma, 0 nicht wegschne
 
Mein Post war eine Antwort auf Sidorion mit seinem mod, da hat die FPU nichts damit zu tun.

Progman 28. Sep 2007 06:48

Re: runden bis auf 2 stellen hinterm komma, 0 nicht wegschne
 
Hinweis:

Delphi-Quellcode:
myStr := FloatToStrF(myFloat, ffFixed, 8, 2); //die 2 steht für die Nachkommastellen, gerundet wird automatisch

alzaimar 28. Sep 2007 06:54

Re: runden bis auf 2 stellen hinterm komma, 0 nicht wegschne
 
Hmmm. Interessante Diskussion. Ich verwende einfach:

Delphi-Quellcode:
Function Aufrunden (Const aValue : Extended; aDecimals : Byte) : Extended;
Var
  aDivider : Extended;

Begin
  aDivider := Power (10,aDecimals);
  If aValue>0 Then
    Result := Trunc (aValue*aDivider + 0.5) / aDivider
  else
    Result := Trunc (aValue*aDivider - 0.5) / aDivider;
End;
Das macht dann, unanhängig von Borland, Borländern, Wikis, Intels, FPU's und deren Befindlichkeiten, stehts das Gleiche.

@Progman: Komisch, FloatToStrF(0.435, ffFixed, 8, 2) liefert 0.44... :shock:

Progman 28. Sep 2007 07:00

Re: runden bis auf 2 stellen hinterm komma, 0 nicht wegschne
 
ist doch mathematisch korrekt, die 5 wird aufgerundet

alzaimar 28. Sep 2007 07:10

Re: runden bis auf 2 stellen hinterm komma, 0 nicht wegschne
 
Alter ist DAS früh! :oops:

bit4bit 28. Sep 2007 23:23

Re: runden bis auf 2 stellen hinterm komma, 0 nicht wegschne
 
@alzaimar

Deine Funktion führt reproduzierbar und portabel eine kaufmännische Rundung aus.

Der Name "Aufrunden" verwirrt da dann doch ein wenig, oder ?



bit4bit

Thomas Feichtner 23. Aug 2010 11:57

AW: Re: runden bis auf 2 stellen hinterm komma, 0 nicht wegschne
 
Zitat:

Zitat von alzaimar (Beitrag 681334)
Hmmm. Interessante Diskussion. Ich verwende einfach:

Delphi-Quellcode:
Function Aufrunden (Const aValue : Extended; aDecimals : Byte) : Extended;
Var
  aDivider : Extended;

Begin
  aDivider := Power (10,aDecimals);
  If aValue>0 Then
    Result := Trunc (aValue*aDivider + 0.5) / aDivider
  else
    Result := Trunc (aValue*aDivider - 0.5) / aDivider;
End;

Mit dieser Funktion habe ich auch nicht immer den richtigen Wert (xRound(2.51 * (100 - 74.5) / 100, 4)) bekommen

jetzt habe ich die Funktion ein wenig umgebaut. Bis jetzt funktionierts.
Delphi-Quellcode:
function xRound(e: Extended; d: Integer ): Extended;
var
  nWert1: Extended;
  nTemp1: Currency;
begin
  nWert1 := e;
  { Zuerst Zahl multiplizieren, damit diese als Currency arbeiten kann
    damit bei xRound(2.51 * (100 - 74.5) / 100, 4) = 0.6401 auskommt und nicht
    0.64 }
  nTemp1 := e * IntPower(10, d - 1);
  if nTemp1 < 0.0 then
    nTemp1 := Trunc(nTemp1 * IntPower(10, 1) - 0.5 ) / IntPower(10, 1)
  else
    nTemp1 := Trunc(nTemp1 * IntPower(10, 1) + 0.5 ) / IntPower(10, 1);
  nWert1 := nTemp1 / IntPower(10, d - 1);
  { Jetzt normal runden -> sollte nicht mehr nötig sein }
  if nWert1 < 0.0 then
    Result := Trunc(nWert1 * IntPower(10, d) - 0.5 ) / IntPower(10, d)
  else
    Result := Trunc(nWert1 * IntPower(10, d) + 0.5 ) / IntPower(10, d);
end;


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