前段时间写过一篇 blog: _ftol 的优化。 今天在读 lua 5.1 的 source 的时候,发现一个更加有趣的技巧。把 double 转成 int 居然可以这样的简单。
union luai_Cast { double l_d; long l_l; };
#define lua_number2int(i,d) { volatile union luai_Cast u; \
u
.l_d = (d) + 6755399441055744.0; (i) = u.l_l; }
这个宏神奇的在正数和负数的双精度浮点数时都可以正确工作,以四舍五入方式转换为 32 位整数。
这个数字是 1.5*2^52 :) 小于 2^31 的数字在和这个magic number 相加的时候,按浮点加法的规则(以科学计数法记数),和一定按幂大的一个对齐。而 1.5 是2进制的 1.1 在浮点标准中,小数点前的 1 是不需要记录的。这样,double 的前四字节就被空出来。而需要转换的整数将因为加法恰当的被置入对应的位置。
这个技巧并不总是适用,比如初始化 D3D9 以后,就会失效。因为 D3d 默认会调整浮点运算的精度。在低精度模式下,这个技巧显然不能工作。关于这一点的讨论可以参考MSDN 上的一个帖子

Posts 2
ftol()
Was this post helpful ?   


Hallo,
For optimization I have
an inlined version of ftol() as you can see below. This version works
normaly fine and very fast. But if I have started with direct3d my function
returns always 0! Where is the problem and what I have to do to let it work
under direct3d?
Thanks, Axel
inline long numeric::ftol(double x)
{
#ifdef __WINDOWS__
static const double magic = 6755399441055744.0; // 2^51 + 2^52
double tmp = x;
tmp += (x > 0) ? -0.499999999999 : +0.499999999999;
tmp += magic;
return *(long*)&tmp;
#else
return (long)x;
#endif
}

--------------------------------------------------------------------------------
Axel


     Report Abuse   



01 Nov 2005, 2:15 PM UTC
Jack Hoxley

ModeratorMVP
Posts 433 Answer Re: ftol()
Was this post helpful ?   


Direct3D changes the FPU flags when it starts up as an optimization... could well be interfering with your implementation
You can stop it from doing this (probably not worth it) by specifying D3DCREATE_FPU_PRESERVE in your CreateDevice call:
From this page in the documentation:
D3DCREATE_FPU_PRESERVE
Forces Direct3D to not change the floating-point unit (FPU) control word, running the pipeline using the precision of the calling thread. Without this flag, Direct3D defaults to setting the FPU to single-precision round-to-nearest mode. Using this flag with the FPU in double-precision mode will reduce Direct3D performance.

Warning Portions of Direct3D assume FPU exceptions are masked. Unmasking such exceptions may lead to undefined behavior.
hth
Jack