Как получить Delphi тип валюты, чтобы круглый, как Excel все время?

Я пытаюсь заставить Delphi округляться, как Excel, но я не могу. Вот код:

procedure TForm1.Button1Click(Sender: TObject);
var
 s : string;
 c : currency;
begin
 c := 54321.245;
 s := '';
 s := s + Format('Variable: %m',[c]);
 s := s + chr(13);
 s := s + Format('   Literal: %m',[54321.245]);
 ShowMessage(s);
end;

Delphi Rounding

Я использую переменную валюты, которая установлена в 54321.245, и когда я форматирую эту переменную, она округляется с помощью округления банкиров. Однако, когда я форматирую то же значение, что и литерал, он округляет так, как округляет Excel.

Я ожидал, что это круг $54,321.25 формирует ли он переменную валюты или литеральное значение. Как могу ли я убедиться, что Delphi округляет так же, как Excel каждый раз?

редактировать

The rounding I expect to see is as follows:  
54,321.245   = 54,321.25  
54,321.2449  = 54,321.24  
54,431.2499  = 54,421.25 

Я использую только литералы, чтобы показать различные способы раундов Delphi. Я ожидаю использовать переменные в фактическом коде.

Примечание:
Если я изменю переменную с валюты to продлен он правильно округляет

Edit #2

некоторые предположил, что у меня нет четкого понимания моих требований, это совершенно не так. У меня очень четкое понимание моих требований, я, очевидно, не очень хорошо их объясняю. Способ округления я хочу двух десятичных знаков. Когда деимальная часть имеет тысячные значения >= 0.005, я хочу, чтобы она округлилась до 0.01, тип валюты, предлагаемый Delphi, этого не делает. Я также попробовал этот пример с помощью Microsoft SQL с типом данных money (который, как я предполагал, был таким же, как Delphi's currency) и SQL rounds это тип денег, как я описал.

  • SQL деньги > = 0.005 = 0.01
  • Валюта Delphi >= 0.005: = 0.00

Edit #3
Хорошая Статья: http://rvelthuis.de/articles/articles-floats.html
Возможное Решение: http://rvelthuis.de/programs/decimals.html

изменить #4
Вот одно из решений от Обсуждение Embarcadero

function RoundCurrency(const Value: Currency): Currency;
var
  V64: Int64 absolute Result;
  Decimals: Integer;
begin
  Result := Value;
  Decimals := V64 mod 100;
  Dec(V64, Decimals);
  case Decimals of
    -99 .. -50 : Dec(V64, 100);
    50 .. 99 : Inc(V64, 100);
  end;
end;

3 ответов


Если я правильно вас понял, вы ищете это:

function RoundTo2dp(Value: Currency): Currency;
begin
  Result := Trunc(Value*100+IfThen(Value>0, 0.5, -0.5))/100;
end;

невозможно сделать RTL так, как вы хотите. Способ повлиять на округление в Delphi-использовать SetRoundMode, который устанавливает FPU conrol слово для округления, однако, насколько я могу судить, нет поддержки FPU для округления точного между вверх (чего обычно избегают, потому что это генерирует смещение для более высоких значений).

вы должны реализовать свою собственную функцию округления. Существует расширенное обсуждение в Delphi Округление нити на форумах Embarcadero, который включает в себя несколько решений.


вы можете получить контроль над тем, как delphi округления чисел по:

uses Math;
...

procedure TForm1.Button1Click(Sender: TObject);
var
s : string;
c : currency;
begin
 SetRoundMode(rmNearest);

 c := 54321.245;
 s := '';
 s := s + Format('Variable: %m',[c]);
 s := s + chr(13);
 s := s + Format('   Literal: %m',[54321.245]);
 ShowMessage(s);
end;

к сожалению, используя rmNearest, Delphi решает, что число 54321.245 ближе к 54321.24, чем 54321.25