• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

【Delphi】玩转浮点数转整数

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

Delphi中提供了三个函数:

Trunc: 将浮点数的整数部分返回。
Round: 将浮点数四舍五入后返回整数部分。
Int: 将浮点数的小数部分去掉,返回只保留了整数部分的Extended型。

在D2007 + Win7 + Intel平台下测试, 由于Int返回的并非整型,我们把它排除掉。测试结果是 Round 性能高出Trunc好几倍。

为什么Trunc慢了呢,查看了System中的ASM代码,Trunc有11行指令,Round则只有5行。

出于好奇,通过网络研究下Trunc的算法,知道了在 IEEE 754 里规定双精度浮点数是 64 位,而其中符号位占 1 位,指数部分是 11 位,那么尾数部分就是 52 位,那么 1 * 2^52 = $10000000000000。设要取整的浮点数为V, 那么通过符点数运算的对阶法, PInteger(V + $10000000000000 的结果)^ 就是计算结果了。

于是有了下面的函数:

function MyTrunc(const V: Double): Integer; inline;
var
  D: Double;
begin
  if V > 0 then
    D := V - 0.499999999999 + $18000000000000
  else
    D := V + 0.499999999999 + $18000000000000;
  Result := PInteger(@D)^;
end;

再来测试看看:

procedure TForm1.Button6Click(Sender: TObject);
const
C = 100000000;
var
u: Extended;
I: Integer;
v, v1, v2: Integer;
t, t1, t2: Int64;
begin
u := Now;

t := GetTimestamp;
for I := 0 to C - 1 do
v := Trunc(u);
t := GetTimestamp - t;

t1 := GetTimestamp;
for I := 0 to C - 1 do
v1 := Round(u);
t1 := GetTimestamp - t1;

t2 := GetTimestamp;
for I := 0 to C - 1 do
v2 := MyTrunc(u);
t2 := GetTimestamp - t2;

ShowMessage(Format('Trunc: %dms, Round: %dms, MyTrunc: %dms'#13'%d, %d, %d',
[t, t1, t2, v, v1, v2]));
end;

 

// 注: GetTimestamp 为高精度计时器返回单位为ms(与QWorker中的返回0.1ms有所不同),可换成GetTickCount。

测试结果如下:

 

哈哈,居然成了最快的了。

要注意的是, MyTrunc 我这里并没有像System的Trunc那样写汇编代码,一是那样不能inline了,二是通过观测编译结果发现已经是很简单的几行指令了。

通过对MyTrunc简单个修改下,成了MyRound:

 

function MyRound(const V: Double): Integer; inline;
var
  D: Double;
begin
  D := V + $18000000000000;
  Result := PInteger(@D)^;
end;

 

参考资料:

http://www.360doc.com/content/14/0308/22/3520047_358884576.shtml

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap