[四舍五入]你一定认为没问题,但是...可能是个巨大Bug?

leemingsong 2002-03-15 12:13:55
********************************************************
四舍五入问题探讨
********************************************************
本人预进行精确到两位小数的四舍五入运算,遇到麻烦,问题报告如下
(x:double,s:double 或string)

1.用Round函数

测试数据如下
s:= Round(x*100)/100
x=1.005 s=1.00(有误)
x=10.005 s=10.01
x=100.005 s=100.00(有误)
...以下同...


2.用FormatFloat函数

测试数据如下
s:= FormatFloat('0.00',x);

x=1.005 s=1.00(有误)
x=10.005 s=10.01
x=100.005 s=100.01
x=1000.005 s=1000.01
x=10000.005 s=10000.00(有误)
...类推...
x=1000000000000.005 s=1000000000000.00(有误)

3.采用网友CherioBoy(冲锋不止) 的函数Round45

// 实数取四舍五入,使用 myCurrency:=Round45(myCurrency,2)
function Round45(GetOldCurr: Currency;Digits: integer=2): Currency;
var tmpCurr:Currency;
begin
tmpCurr:= GetOldCurr * (IntPower(10,Digits)); // 小数点右移digits位
if Abs(Frac(tmpCurr)) < 0.5 then
tmpCurr:= Int(tmpCurr) // 保留整数部分
else
if tmpCurr>0 then
tmpCurr:= Int(tmpCurr)+1
else tmpCurr:= Int(tmpCurr)-1; // 进位
Result:= tmpCurr /IntPower(10,Digits); // 小数点回移
end;

测试结果如下:
s:=Round45(x,2);

x=1.005 s=1.01
x=10.005 s=10.01
x=100.005 s=100.01
x=1000.005 s=1000.01
x=10000.005 s=10000.01
...类推...
x=1000000000000.005 s=1000000000000.00
以上都正确,但是继续测试该通用函数
s:= Round45(x,4) //精确到四位小数
x=1.00045 s=1.0004(有误)??????
x=1.000451 s=1.0005(正确)

(********************************************************
我的问题:
********************************************************)
1.哪里找真正的四舍五入函数啊,有谁可以告诉我???
2.这个问题仅仅是Delphi中存在吗???
3.那位网友也有类似的经历,您是怎么解决的
4.这是不是个Bug???
联系mail: leemingsong@sina.com

答谢!
********************************************************
...全文
61 45 打赏 收藏 转发到动态 举报
写回复
用AI写文章
45 条回复
切换为时间正序
请发表友善的回复…
发表回复
aliceZOOZ 2002-03-17
  • 打赏
  • 举报
回复
to 楼上的,我的程序就是这样的嘛
dolphi 2002-03-16
  • 打赏
  • 举报
回复
如果涉及敏感数据,不妨考虑以效率换安全。你把转换部分变成字符串,严格处理完后再转换为数值。
lygsee 2002-03-15
  • 打赏
  • 举报
回复
我常用
float s = Round(x*100+0.5)/100
来做
lygsee 2002-03-15
  • 打赏
  • 举报
回复
我常用float s = Round(x*100+0.5)/100;来做
leemingsong 2002-03-15
  • 打赏
  • 举报
回复
谢谢,我拿来调试一下
dancemaple 2002-03-15
  • 打赏
  • 举报
回复
function RoundTo(const AValue: Double; const ADigit: TRoundToRange): Double;
var
LFactor: Double;
begin
LFactor := IntPower(10, ADigit);
Result := Round(AValue / LFactor) * LFactor;
end;



另外,Round函数在Delphi的帮助中已经说得很明白,是四舍六入,五取双
leemingsong 2002-03-15
  • 打赏
  • 举报
回复
有谁能贴一下Delphi6.0中RoundTo的源代码吗???
Bellamy 2002-03-15
  • 打赏
  • 举报
回复
呵呵
leemingsong 2002-03-15
  • 打赏
  • 举报
回复
"加半取整"能具体解释一下吗?这样似乎只是把0.5这个问题转移了???
mingyeh 2002-03-15
  • 打赏
  • 举报
回复
用“加半取整”的方法如何?
  • 打赏
  • 举报
回复
转摘D6 帮助文档。

Rounds a floating-point value to a specified digit or power of ten using “Banker’s rounding”.

Unit
Math
leemingsong 2002-03-15
  • 打赏
  • 举报
回复
D5好像没有这个函数
  • 打赏
  • 举报
回复
我用的是D6,刚测试过一切正常。
leemingsong 2002-03-15
  • 打赏
  • 举报
回复
过一会儿再给分,我要知道个究竟
leemingsong 2002-03-15
  • 打赏
  • 举报
回复
RoundTo没有在math.pas文件中啊,我的是delphi5,不会delphi6才有吧
  • 打赏
  • 举报
回复
太小看 DELPHI 了吧。
  • 打赏
  • 举报
回复
RoundTo 在MATH单元中声明。手动添加即可。-N表示小数位数N。
leemingsong 2002-03-15
  • 打赏
  • 举报
回复
解决问题,将Round45的Currency改成Double类型就可以了。这里真是个好地方!!!给分啦

// 实数取四舍五入,使用 myCurrency:=Round45(myCurrency,2)
function Round45_EX(GetOldCurr: Double;Digits: integer=2): Double;
var tmpCurr:Double;
begin
tmpCurr:= GetOldCurr * (IntPower(10,Digits)); // 小数点右移digits位
if Abs(Frac(tmpCurr)) < 0.5 then
tmpCurr:= Int(tmpCurr) // 保留整数部分
else
if tmpCurr>0 then
tmpCurr:= Int(tmpCurr)+1
else tmpCurr:= Int(tmpCurr)-1; // 进位
Result:= tmpCurr /IntPower(10,Digits); // 小数点回移
end;
  • 打赏
  • 举报
回复
function RoundTo(const AValue: Double; const ADigit: TRoundToRange): Double;

注意类型匹配问题。

Expression Value

RoundTo(1234567, 3) 1234000
RoundTo(1.234, -2) 1.23
RoundTo(1.235, -2) 1.24
RoundTo(1.245, -2) 1.24
Detective 2002-03-15
  • 打赏
  • 举报
回复
leemingsong(陨石) 你不是已经解决了吗?“解决问题,将Round45的Currency改成Double类型就可以了。”

现在还有什么问题呢?你收到我发的消息了吧?
加载更多回复(25)

828

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 非技术区
社区管理员
  • 非技术区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧