Delphi 德尔福-四舍五入-始终向下

Delphi 德尔福-四舍五入-始终向下,delphi,rounding,Delphi,Rounding,我需要将浮点数四舍五入到小数点后两位,但总是向下。现在我使用roundTonNumber,-2,但它在数学上正确地进行了舍入,这对于我的情况来说是不希望的行为。让原因,为什么我需要这样做,放在一边 我最终通过以下方式实现了这一目标: var a,b: currency; floatStr: string; format: TFormatSettings; localeDec: char; begin format:= TFormatSettings.Create;

我需要将浮点数四舍五入到小数点后两位,但总是向下。现在我使用roundTonNumber,-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;

然而,这种解决方案感觉不太对。有没有一种数学上干净的方法可以做到这一点,而不会弄乱字符串和重置十进制分隔符等?我搜索了很多,但没有找到任何内容。

您可以执行以下操作:

将该值乘以100。 向零截断为整数。 将该值除以100。 像这样:

function RoundCurrTo2dpTruncate(const Value: Currency): Currency;
begin
  Result := Trunc(Value*100) / 100;
end;
我假设四舍五入意味着接近零。所以0.678四舍五入到0.67,-0.678到-0.67。然而,如果你想绕过去-∞ 然后你应该用地板来代替Trunc

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

从:

货币是一种定点数据类型,可将货币计算中的舍入误差降至最低。它存储为一个按比例缩放的64位整数,其中4个最低有效位隐式表示小数位数。当与赋值和表达式中的其他实数类型混合时,货币值将自动除以或乘以10000

例如,您可以像这样实现RoundCurrto2DPRuncate:

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

请注意,这里的算术已被移位10000。所以乘以100就变成了除以100。等等

您可以执行以下操作:

将该值乘以100。 向零截断为整数。 将该值除以100。 像这样:

function RoundCurrTo2dpTruncate(const Value: Currency): Currency;
begin
  Result := Trunc(Value*100) / 100;
end;
我假设四舍五入意味着接近零。所以0.678四舍五入到0.67,-0.678到-0.67。然而,如果你想绕过去-∞ 然后你应该用地板来代替Trunc

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

从:

货币是一种定点数据类型,可将货币计算中的舍入误差降至最低。它存储为一个按比例缩放的64位整数,其中4个最低有效位隐式表示小数位数。当与赋值和表达式中的其他实数类型混合时,货币值将自动除以或乘以10000

例如,您可以像这样实现RoundCurrto2DPRuncate:

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;

显然,它在最新版本中有所更改

您可以将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;

显然,它在最近的版本中发生了更改

我相信Int比Trunc好,因为Trunc可能会溢出。@user246408我实际上认为使用整数运算来完成整个操作更好。我相信Int比Trunc好,因为Trunc可能会溢出。@user246408我实际上认为最好完成整个操作使用整数运算。是的,我弄错了。不过,问题是关于货币。是的,这是不合适的。我只读了第一部分,将浮点数四舍五入到小数点后两位。这很公平。阿斯克有点困惑。货币是固定的。很抱歉给你们带来困惑,这是我做的各种实验得出的结论。我一直在使用各种类型的货币,但最终我会使用货币。是的,我弄错了。不过,问题是关于货币。是的,这是不合适的。我只读了第一部分,将浮点数四舍五入到小数点后两位。这很公平。阿斯克有点困惑。货币是固定的。很抱歉给你们带来困惑,这是我做的各种实验得出的结论。我一直在使用各种类型的货币,但最终我将使用货币。