Smi*_*ver 4 c++ floating-point packing mantissa ieee-754
以下是我要实现的目标:
我想这个问题包括两部分:
1)我可以简单地清除尾数的最低位吗?我试过这个,到目前为止它的确有效,但也许我在寻找麻烦......有点像:
float f;
int packed = (*(int*)&f) & ~3;
// later
f = *(float*)&packed;
Run Code Online (Sandbox Code Playgroud)
2)如果有1)失败的情况,那么实现这一目标的最快方法是什么?
提前致谢
sel*_*tze 10
实际上,您通过这些重新解释转换违反了严格的别名规则(C++标准的第3.10节).当您打开编译器优化时,这可能会在您的脸上爆炸.
C++标准,第3.10节第15段说:
如果程序试图通过不同于以下类型之一的左值访问对象的存储值,则行为未定义
- 对象的动态类型,
- 一个cv限定版本的动态类型的对象,
- 类似于对象的动态类型的类型,
- 与对象的动态类型对应的有符号或无符号类型的类型,
- 一种类型,是有符号或无符号类型,对应于对象动态类型的cv限定版本,
- 一种聚合或联合类型,包括其成员中的上述类型之一(包括递归地,子聚合或包含联合的成员),
- 一个类型,它是对象动态类型的(可能是cv限定的)基类类型,
- char或unsigned char类型.
具体来说,3.10/15不允许我们通过unsigned int类型的左值访问float对象.实际上我被这个咬了.我写的程序在启用优化后停止了工作.显然,GCC并没有指望float类型的左值为别名类型int的左值,这是3.10/15的公平假设.在利用3.10/15的as-if规则下,优化器对指令进行了调整,它停止了工作.
根据以下假设
你应该能够这样做:
/// returns a 30 bit number
unsigned int pack_float(float x) {
unsigned r;
std::memcpy(&r,&x,sizeof r);
return r >> 2;
}
float unpack_float(unsigned int x) {
x <<= 2;
float r;
std::memcpy(&r,&x,sizeof r);
return r;
}
Run Code Online (Sandbox Code Playgroud)
这不会受到"3.10违规"的影响,并且通常非常快.至少GCC将memcpy视为内在函数.如果您不需要使用NaN,无穷大或数量极大的函数,您甚至可以通过将"r >> 2"替换为"(r + 1)>> 2"来提高准确性:
unsigned int pack_float(float x) {
unsigned r;
std::memcpy(&r,&x,sizeof r);
return (r+1) >> 2;
}
Run Code Online (Sandbox Code Playgroud)
即使由于尾数溢出而改变指数也是如此,因为IEEE-754编码将连续的浮点值映射到连续的整数(忽略+/-零).这种映射实际上非常接近对数.
小智 8
盲目地丢弃浮点数的2个LSB可能会因少量不寻常的NaN编码而失败.
NaN编码为指数= 255,尾数!= 0,但IEEE-754没有说明应该使用哪个mantiassa值.如果尾数值<= 3,您可以将NaN变为无穷大!
| 归档时间: |
|
| 查看次数: |
2042 次 |
| 最近记录: |