自己写一个软件渲染器的时候,无意中发现float转换int非常耗时,于是查阅文章,这才有了这个命题,以前不清楚还有这么个机制。网上看了很多文章,搜索到了一个数字6755399441055744,这个是double快速转换int的一个magic number。至于原理我一知半解,主要看效果。经测试,这个函数的效率比c++直接float转int高很多,记录下来以便备忘。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // // 将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; } |
1 |
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运算
}
sdragonx https://github.com/sdragonx
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现