我需要将浮点数舍入到两位小数,但总是向下。现在我使用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;
但是,这个解决方案感觉不对。有没有"数学上干净"这样做的方法,没有弄乱字符串和重置小数分隔符等?我经常搜索,但没找到。
答案 0 :(得分:4)
您可以执行以下操作:
像这样:
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
值只是一个64位整数,隐式移位为10000.因此整个操作可以使用整数运算来执行,这与上面使用的代码不同浮点运算。
货币是一种定点数据类型,可最大限度地减少货币计算中的舍入误差。它存储为缩放的64位整数,其中4个最低有效位隐式表示小数位。当与赋值和表达式中的其他实际类型混合时,货币值将自动分割或乘以10000。
例如,你可以像这样实现RoundCurrTo2dpTruncate
:
function RoundCurrTo2dpTruncate(const Value: Currency): Currency;
begin
PInt64(@Result)^ := (PInt64(@Value)^ div 100)*100;
end;
请注意,此处算术已移位10000.因此乘以100已除以100.依此类推。
答案 1 :(得分:0)
您可以将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;
显然在最近的版本中已经改变了