Delphi Trunc函数精度的问题,能解答送200分

abcynic 2007-07-20 03:09:53
var
a , b, c ,d : Double;
i : Integer;
begin
a := 0.3;
b := 0.3;
c := 300000;

d := a * b * c;
i := Trunc(d);//26999不是 27000
Memo1.Lines.Add('d := a * b * c; i := Trunc(d)='+IntToStr(i));
i := Trunc(d * 10000);//269999999 不是 270000000
Memo1.Lines.Add('d := a * b * c; i := Trunc(d)='+IntToStr(i));
end;

怎么才能让Trunc得到我想要的精度?
尝试在trunc前加一个很小的值

d := d+ 1e-11;
i := Trunc(d);
有效
d := d+ 1e-12;
i := Trunc(d);
则仍然有刚才的问题。

其他语言,例如c、c#尝试同样数值的乘法并取整没有这种问题。
浮点数精度上有问题但总觉得round有差异是可以理解,怎么在delphi中一个很正常的数取整也有问题呢?
---
c中测试浮点数表示值
union D
{
double f ;
struct
{
unsigned char x1 ;
unsigned char x2 ;
unsigned char x3 ;
unsigned char x4 ;
unsigned char x5 ;
unsigned char x6 ;
unsigned char x7 ;
unsigned char x8 ;
} ;
} u,v ;
double a = 0.3;
double b = 0.3;
double c = 300000;
u.f=a*b*c;
printf("u.f=%30.20f\n",u.f);
printf( "%2x %2x %2x %2x %2x %2x %2x %2x\n",u.x8,u.x7,u.x6,u.x5,u.x4,u.x3,u.x2,u.x1) ;

u.f= 27000.00000000000000000000
40 da 5e 0 0 0 0 0

---
c#测试相关代码
double a = 0.3;
double b = 0.3;
double c = 300000;
double d = a * b * c;
this.textBox1.Text = Convert.ToInt32(Math.Truncate(d)).ToString();

能解答送200分
...全文
3608 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
justljm 2011-11-25
  • 打赏
  • 举报
回复
你怎么有这么多分?我怎么分老是上不去???这是为什么呢?
Kisber 2011-08-12
  • 打赏
  • 举报
回复
你应该用round()
hz_grape 2007-08-01
  • 打赏
  • 举报
回复
试试 i := Trunc(d+0.5);//26999不是 27000
虽然说这个方法有点投机取巧!
logne 2007-07-23
  • 打赏
  • 举报
回复
楼主用的delphi几呢
yzdiyu 2007-07-23
  • 打赏
  • 举报
回复
请把 Double换成
Extended类型
他的回答是对的吧。
abcynic 2007-07-23
  • 打赏
  • 举报
回复
参考了一些c的算法资料,决定用魔法数来取整,写了如下算法,能够解决当前面临的问题。不知道大家对这个算法的看法如何。

function MagicTrunc(Value: Extended): Int64;
var
MagicNumber : Double;
tmp : Double;
begin
MagicNumber := 6755399441055744.0;// 2^51 + 2^52 // (1<<51) | (1<<52)
tmp := Value;

//如果需要4舍5入取整就去掉
if (Value>0 ) then
begin
tmp := tmp - 0.499999999999;
end
else
begin
tmp := tmp + 0.499999999999;
end;
//如果需要4舍5入取整就去掉

tmp := tmp + MagicNumber;
Result := Trunc(tmp);
end;
gzmhero 2007-07-23
  • 打赏
  • 举报
回复
如何能看到d在内存中的存储格式,就像我在c中用共用体来查看一样,我想看到用来表示d的所有字节中的16进制。
------------------
程序执行,在程序中设置断点,看一下a,b,c的内存地址.$*******
然后View->Debug Window->Cpu,在右下角的框中点右键,Go to Address,输入刚才看到的变量的地址,就看到了内存中的该变量的16进制表达.
abcynic 2007-07-23
  • 打赏
  • 举报
回复
还有一点

d=a*b*c ;
trunc(d)=269999
如果写成
d = a * b;
d = d * c;

trunc(d) = 27000;
搞不明白,delphi的中间计算难度是用Extended?
abcynic 2007-07-23
  • 打赏
  • 举报
回复
Single明显精度不足,用Currency似乎可以。
但总觉得奇怪为什么c能用double处理好这个截位,delphi就不行呢?
另外请教gzmhero(hihihi),如何能看到d在内存中的存储格式,就像我在c中用共用体来查看一样,我想看到用来表示d的所有字节中的16进制。
ly_liuyang 2007-07-20
  • 打赏
  • 举报
回复
上面的正确
gzmhero 2007-07-20
  • 打赏
  • 举报
回复
在计算机中浮点数的表达是近似值,a*b*c是近似=27000,而这里刚好得到的是26999.999999999996362,所以出现了Trunc(d)=26999的情况,为避免这种情况出现,
特别是在金融等的计算上面,往往需要限定d的精度,否则会出现这种微小的误差,而这误差累积起来,就会出现大的bug。a,b,c可以是double,但是结果不能用高精度的类型,设置为低精度的Single或者Currency类型可以很好的来避免。
brightyang 2007-07-20
  • 打赏
  • 举报
回复
能解答送200分
brightyang 2007-07-20
  • 打赏
  • 举报
回复
请把 Double换成
Extended 类型

16,748

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 语言基础/算法/系统设计
社区管理员
  • 语言基础/算法/系统设计社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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