Einzelnen Beitrag anzeigen

alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#4

Re: Nachkommastellen abschneiden OHNE Runden ??

  Alt 28. Nov 2009, 16:48
Zitat von bodenheim:
Zitat von DeddyH:
NeueZahl := trunc(Zahl * 100) / 100;
das klappt. Danke !!
...leider nicht, wenn man bereits mit vermeidlich auf zwei Stellen genauen Zahlen rumhantiert.
Beweis:
Delphi-Quellcode:
program FloatingPointTuecken;
{$APPTYPE CONSOLE}

uses
  SysUtils;

Var
  i : Integer;
  Beispiel,
  Abgerundet : Double;

  Function Abrunden (Zahl : Double) : Double;
  Begin
      Result := Trunc (Zahl * 100) / 100;
  End;

begin
  for i:=1 to maxint do begin
    Beispiel := i/100; // Klar, eine Zahlen auf 2 Stellen
    Abgerundet := Abrunden(Beispiel); // Sicherheitshalber abrunden
    if Abs (Beispiel - Abgerundet)>0.005 Then // Falls das nicht klappt, ...
      writeln(i,Beispiel,Abgerundet); // wundern!
  end;
end.

Abhilfe: Berücksichtigen der Rundungsfehler, indem wir 'fast aufrunden':
Delphi-Quellcode:
function KorrektesAbrunden(Zahl: Double): Double;
Const
  KorrekturDerSchutzStellen = 0.5 - 1E-16;

begin
  If Zahl < 0 then
    Result := Trunc(Zahl * 100 - KorrekturDerSchutzStellen) / 100
  Else
    Result := Trunc(Zahl * 100 + KorrekturDerSchutzStellen) / 100;
end;
Hier der komplette Testcode: Er testet alle Zahlen -maxint/100 .. +maxint/100;
Delphi-Quellcode:
program FloatingPointTuecken;
{$APPTYPE CONSOLE}
uses
  SysUtils;

type
  TAbrundenFunktion = function(Zahl: Double): Double;

function Abrunden(Zahl: Double): Double;
begin
  Result := Trunc(Zahl * 100) / 100;
end;

function KorrektesAbrunden(Zahl: Double): Double;
Const
  KorrekturDerSchutzStellen = 0.5 - 1E-16;

begin
  If Zahl < 0 then
    Result := Trunc(Zahl * 100 - KorrekturDerSchutzStellen) / 100
  Else
    Result := Trunc(Zahl * 100 + KorrekturDerSchutzStellen) / 100;
end;

function ZahlenUngleich(Zahl1, Zahl2: Double): Boolean;
begin
  Result := Abs(Zahl1 - Zahl2) > 0.005;
end;

procedure ZeigeFehler(Funktionsname : String; Zahl, Gerundet: Double);
begin
  Writeln('Die Funktion "',Funktionsname,'" funktioniert nicht korrekt.');
  Writeln('Beispiel:');
  Writeln(' Zahl : ', Zahl: 8: 2);
  Writeln(' Abgerundet : ', Gerundet: 8: 2);
  Writeln;
end;

procedure TesteKorrektesRundenMit(FunktionsName : String;
  EineAbrundenFunktion: TAbrundenFunktion);
var
  i: Integer;
  Beispiel,
    Abgerundet : Double;

begin
  for i := -maxint to maxint do begin
    Beispiel := i / 100;
    Abgerundet := EineAbrundenFunktion(Beispiel);
    if ZahlenUngleich(Beispiel, Abgerundet) then begin
      ZeigeFehler(Funktionsname, Beispiel, Abgerundet);
      Exit;
    end;
  end;
  Writeln('Die Funktion "',Funktionsname,'" funktioniert besser');
end;

begin
  TesteKorrektesRundenMit('Gängige Version', Abrunden);
  TesteKorrektesRundenMit('Korrigierte Version', KorrektesAbrunden);
  ReadLn;
end.
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat