Delphi 的四舍五入跟我们平常所认识的四舍五入不一样。它用的是银行家算法-也就是四舍六入,而五入不入取决后面跟的一位
数是奇数还是偶数,如果是奇数则进,如果是偶数则舍。简单说是奇进偶不进。
举例: 123.3359保留两位小数,如果是平常四舍五入123.3359 = 123.34,如果是银行家算法123.34;结果是一样;
123.3358保留两位小数,如果是平常四舍五入123.3358= 123.34,如果是银行家算法123.33;结果不一样;
在以前开发的系统时做薪资结算,就遇到这样的问题。无论是Round 还是FormatFloat都用的银行算法,偏偏会计用四舍五入,所以两边一对总是差了一分钱。为这一分钱足足整了三个月都没搞定,百度、Google问的人多,解决问题的少。在“床上等你”发贴也没搞定,看来这个问题虽然看似简单,但好像大多数没搞定。后来还是一个偶然的机会改进了一个Delphi四舍五入函数才解决。
原理: SimpleRoundTo是一个四舍五入的函数,应用效果入下:
SimpleRoundTo(1234567, 3) 1234000
SimpleRoundTo(1.234, -2) 1.23
SimpleRoundTo(1.235, -2) 1.24
SimpleRoundTo(-1.235, -2) -1.23
SimpleRoundTo对于正数四舍五入没问题上,但是遇到负数就是直接舍去了。注意第四个impleRoundTo(-1.235, -2) -1.23,实际
应该是-1.24。所以对SimpleRoundTo函数进行了改进。如果是正数则直接用SimpleRoundTo函数,如果负数先取绝对值,然后使用SimpleRoundTo函数,然后再取反。
如果还有那位大神有更简洁、更高效、更好用的写法,欢迎跟贴。
使用方法: 1.235保留两位小数 SimpleRoundEx(1.235, -2) = 1.24;
-1.235保留两位小数 SimpleRoundEx(-1.235, -2) = -1.24
//四舍五入
function SimpleRoundEx(const AValue: Double; const ADigit: Integer): Double;
//四舍五入
function TBaseForm.SimpleRoundEx(const AValue: Double;
const ADigit: Integer): Double;
begin
if (Sign(AValue) = 1) or (Sign(AValue) = 0) then
begin
Result := SimpleRoundTo(AValue, ADigit);
end
else
begin
Result := SimpleRoundTo(Abs(AValue), ADigit) * (-1);
end;
end;
_________________________________________________________________________________________________
鉴于有同学说这个方法不靠谱,这是里再提供一种方法(注:是从网上搬来的,具体地址没记住)
class function TNewDcFunc.RoundFloat(f:double;i:integer):double;
var
s:string;
ef:extended;
begin
s:='#.'+ StringOfChar('0',i);
ef:=StrToFloat(FloatToStr(f));//防止浮点运算的误差
result:=StrToFloat(FormatFloat(s,ef));
end;