float(double)快速转换int的方法

自己写一个软件渲染器的时候,无意中发现float转换int非常耗时,于是查阅文章,这才有了这个命题,以前不清楚还有这么个机制。网上看了很多文章,搜索到了一个数字6755399441055744,这个是double快速转换int的一个magic number。至于原理我一知半解,主要看效果。经测试,这个函数的效率比c++直接float转int高很多,记录下来以便备忘。

//
// 将64位浮点数转换为32位整数
// 小数部分将四舍五入到偶数
//
//用于double的magic number是1.5*2^52=6755399441055744.0
//对于double来说,相应的magic number就是1.5*2^36
//处理float的速度比汇编低1/3
//编译器优化情况下,比手写汇编快

inline int32_t f_toint(double x)
{
    x += 6755399441055744.0;
    return *(int32_t*)&x;
}

//四舍五入,处理的数据范围是-2^22 ~ 2^22-1, -4194304.0 ~ 4194303.0
inline int32_t f_toint32(float x)
{
    //取得符号位,设置掩码
    uint32_t n = ((*(uint32_t*)&x) & 0x80000000) ? 0xFFC00000 : 0;
    x += 12582912.0f;
    return ((*(uint32_t*)&x) & 0x3FFFFF) | n;
}
 
 

f_toint32的原型是csdn论坛一个网友说的回复:

inline long magic_f2l( float x )
{
    static long mask[] = { 0x0, 0xffc00000 };
    static float trunc[] = { -.5f, .5f };
    int s = ( *(unsigned long*)&x )>>31;
    x += trunc[s];
    x += 12582912.f;
    return (*(long*)&x) & 0x3fffff  | mask[s];
}
 
这个里面用到了12582912这个魔法数字,和double转换那个是一样的,都可以用这个函数得到:

double float_magic_number(int bits)
{
    return 1.5 * STD::pow(2.0, double(bits));
}

但magic_f2l()这个函数效率并没有double版本的那么好,原因估计是运算运算太多了,于是我精简了一下:

inline  long  magic_f2l(  float  x )
{
     static  long  mask[] = { 0x0, 0xffc00000 };
     static  float  trunc[] = { -.5f, .5f };
     int  s = ( *(unsigned  long *)&x )>>31;//这里得到float的符号位,如果是负数,最后结果就和0xFFC00000进行or运算。这里有个位移操作
     x += trunc[s];//这里有个加法和数组取值操作
     x += 12582912.f;
     return  (*( long *)&x) & 0x3fffff  | mask[s];//数组取值
}
 
经简化,完成如下函数,这个效率和double版本不相上下,稍微慢一丢丢(几个时钟周期),仍然把c++默认转换摔在后面。

inline int32_t f_toint32(float x)
{
//取得符号位,设置掩码
uint32_t n = ((*(uint32_t*)&x) & 0x80000000) ? 0xFFC00000 : 0;//一个三元操作符,直接储存掩码
x += 12582912.0f;//魔法数字加法
return ((*(uint32_t*)&x) & 0x3FFFFF) | n;//直接or运算
}

转载于:https://www.cnblogs.com/sdragonx/p/10933096.html

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值