Delphi - RoundTo - 总是向下

Delphi - RoundTo - always down

我需要将浮点数舍入到小数点后两位,但总是向下舍入。现在我使用 RoundTo(number, -2),但它在数学上正确地进行了舍入,这对我的情况来说是不希望的行为。让原因,为什么我需要这样做,放在一边...

我最终用这个实现了它:

var a,b: currency;
    floatStr: string;
    format: TFormatSettings;
    localeDec: char;
begin


  format:= TFormatSettings.Create;
  localeDec:= format.DecimalSeparator;
  format.DecimalSeparator:= ',';
  System.SysUtils.FormatSettings:= format;

  a:= 2/30;
  floatStr:= floatToStr(a);
  b:= strToCurr(
      copy(floatStr, 1, ansiPos(',', floatStr) + 2)
  );
  showMessage(currToStr(b));

  format.DecimalSeparator := localeDec;
  System.SysUtils.FormatSettings:= format;

end;

但是,这个解决方案感觉不对。有没有一种 "mathematically clean" 方法可以做到这一点,而不会弄乱字符串和重置小数点分隔符等?我找了很多,都没找到。

您可以执行以下操作:

  1. 将值乘以 100。
  2. 截断为整数,趋近于零。
  3. 将值除以 100。

像这样:

function RoundCurrTo2dpTruncate(const Value: Currency): Currency;
begin
  Result := Trunc(Value*100) / 100;
end;

我假设四舍五入是指接近零。所以 0.678 向下舍入为 0.67,-0.678 向下舍入为 -0.67。但是,如果您想向 -∞ 舍入,则应将 Trunc 替换为 Floor

function RoundCurrTo2dpDown(const Value: Currency): Currency;
begin
  Result := Floor(Value*100) / 100;
end;

解决该问题的另一种方法是认识到 Currency 值只是一个隐式移位 10000 的 64 位整数。因此,与上面的代码不同,可以使用整数运算来执行整个操作它使用浮点运算。

来自documentation

Currency is a fixed-point data type that minimizes rounding errors in monetary calculations. It is stored as a scaled 64-bit integer with the 4 least significant digits implicitly representing decimal places. When mixed with other real types in assignments and expressions, Currency values are automatically divided or multiplied by 10000.

例如,您可以这样实现 RoundCurrTo2dpTruncate

function RoundCurrTo2dpTruncate(const Value: Currency): Currency;
begin
  PInt64(@Result)^ := (PInt64(@Value)^ div 100)*100;
end;

请注意,此处的算术运算已移位 10000。因此,乘以 100 已变为除以 100。依此类推。

您可以将 SetRoundMode 与旧 Delphi RoundTo

一起使用
SetRoundMode(rmDown);

function RoundTo(const AValue: Double; const ADigit: TRoundToRange): Double;
var
  LFactor: Double;
begin
  LFactor := IntPower(10, ADigit);
  Result := Round(AValue / LFactor) * LFactor;
end;

显然它在最近的版本中发生了变化