_ftol 的优化
_ftol 是什么? 当你写 C 程序的时候,(int)float_v 就会被编译器产生一个对 _ftol 这个 CRT 函数的调用。
上个世纪听一个做 3d 的朋友提起过,用 x87 指令实现的 _ftol 会很慢,一般用整数指令提供。当时提在心里,2000 年的时候在 RISC 上做开发 (ARM 指令集) 曾经写过一些整数模拟浮点的函数,曾经写过这个转换函数,日子久了,现在也找不回来代码。不过对浮点的 IEEE 标准还是比较清楚的。去年写过一篇 浮点数的精度控制问题 的帖子放在流言中。当时已经被骂过了。
今天工作时又遇到关于浮点数的问题,再写篇 blog 吧,或许还是找骂贴 :)
懒的重写 _ftol 的整数指令版本了,google 搜了下,发现果然有人也做过。http://www.flipcode.com/cgi-bin/fcarticles.cgi?show=64008
就是这么一个函数:
int ftol(float f) { int a = *(int*)(&f); int sign = (a>>31); int mantissa = (a&((1<<23)-1))|(1<<23); int exponent = ((a&0x7fffffff)>>23)-127; int r = ((unsigned int)(mantissa)<<8)>>(31-exponent); return ((r ^ (sign)) - sign ) &~ (exponent>>31); }当是效率比较高的。我想,日子已经过去这么久了。当初朋友跟我提这个事情的事情大约是 98,99 年。上面翻出来的老帖是 01 年的。我现在的机器不错,今年新买的 P4 双核的,还是测试一下比较放心。 注:这个函数不能直接替换 CRT 中的 _ftol , CRT 的 _ftol 并不通过堆栈传递参数。 马上随手写了下面的测试程序:
#include "stdio.h" #define RDTSC _asm _emit 0x0f _asm _emit 0x31 #pragma warning (push) #pragma warning (disable: 4035) inline unsigned __int64 timestamp() { __asm RDTSC } #pragma warning (pop) int int_chop (float f) { int a = *(int*)(&f); int sign = (a>>31); int mantissa = (a&((1<<23)-1))|(1<<23); int exponent = ((a&0x7fffffff)>>23)-127; int r = ((unsigned int)(mantissa)<<8)>>(31-exponent); return ((r ^ (sign)) - sign ) &~ (exponent>>31); } int test1(float f) { return int_chop(f); } int test2(float f) { return (int)f; } int test3(float x) { int t; __asm fld x __asm fistp t return t; } void test(int t,int (*f)(float)) { int i; for (i=0;i运行结果如下: ---timing 0--- use int 4449676 (int) 4583873 use x87 1491980 ---timing 1--- use int 6097315 (int) 4603592 use x87 1662360 ---timing 2--- use int 2427691 (int) 4532759 use x87 1445269compiler 内置的 _ftol 表现不怎么样,比整数版还是慢了一倍。那个浮点版本是做参考的,虽然快,但是语义和 C 语言要求的不太一样,依赖 rounding mode 的设置。所以不推荐使用。 关于 double 向 int 转换,参考另一篇 blog :double to int 神奇的 magic number
Comments
VC6->VC2005
可以用编译器选项
/QIfist
Posted by: ninja | (9) November 6, 2008 10:59 AM
我也写了一篇blog文章,讨论了各种浮点数取整的实现和速度对比:《代码优化-之-优化浮点数取整》
http://blog.csdn.net/housisong/archive/2007/05/19/1616026.aspx
Posted by: HouSisong | (8) May 19, 2007 10:09 AM
不太清楚情况,说几句.
程序员 也可以 对事情发表一些看法嘛. 我们对事,不对人. 为的是交换观点,解决问题,警诫自己.
至于别人怎样,就怎样去吧. 如果有些人想与真正的程序员划分界限,他们到头来害的是自己.
Posted by: sods | (7) March 1, 2006 02:35 PM
既然x87指令那么快为什么还要用软件方法呢?
Posted by: euclid | (6) February 17, 2006 01:19 PM
VS2005变慢的原因是因为VS2005传递参数用了浮点堆栈来设置参数的,多了2条浮点指令,而VS2003是直接push一个常数的。
还有一个奇怪的地方是我自己写了个转换函数,用了那个SSE指令转换,却得到了一个非常慢的结果,没暂时还没找到原因。
Posted by: analyst | (5) December 19, 2005 01:31 PM
vs2003 和 vs2005 是在同一台机器上测的吗? 怎么几个函数的速度差那么远? 除了 (int) 这个,另外两个都变慢了?
Posted by: Cloud
| (4)
December 19, 2005 12:32 PM
我用VS2003测得的结果是:
use int 1706568
(int) 3702616
use x87 1234884
用VS2005测得的结果是:
use int 2405772
(int) 2178028
use x87 2580324
VS2005使用了SSE指令优化取得了更快的结果。
Posted by: analyst | (3) December 19, 2005 12:45 AM
还有,如果你觉得刚才那个留言不方便发表,就不用发表了,你看到就可以了,你也不用猜我是谁,你猜不到的,呵呵,因为我是个潜水艇,只不过最近我也发生跟你一样的事情,深刻明白你的感受,所以来共鸣一下而已,哈哈
Posted by: 一个朋友(不方便留名字) | (2) December 17, 2005 08:27 PM
云飞兄,看到你的blog,感触万分,因为最近我也跟你犯了同样错误,不过你是因为失言得罪不少网友,我是因为失言得罪了一家大公司(因为这家大公司大家都知道,所以不便说出来),不过我马上醒悟,并且道歉了,你可能就比较困难拉,有时候想,我们做开发的,表达能力本来就有限,对这些事不是很了解,而且专工有专职,公关的事情有公关做,千万不要自做主张,踏这个混水呢,不过这个事情上说csdn的责任编辑则有点不厚道了,就算批驳你的文章也应该先提个醒,因为大家都知道你是不清楚事情内幕的,责任编辑觉得你说的地方有错也应该先告知你,先确认你是否理解无误才批驳.
名也不留拉,这个世界还是慎言好啊.毕竟我们不是表达能力和公关能力很强的人,我们是做开发的,说些开发外的话(特别是在公众场合),本是出与善意,也会被人误解,曲解(故意的也有,无意的也有,但是结果还是一样,被人利用了)
Posted by: 一个朋友(不方便留名字) | (1) December 17, 2005 08:23 PM