首先对不起,如果这是重复,我找不到任何主题回答我的问题。
我正在编写一个小程序,用于将32位浮点值转换为short int(16位)和unsigned char(8位)值。这是用于HDR图像的目的。
从here我可以得到以下功能(没有夹紧):
static inline uint8_t u8fromfloat(float x)
{
return (int)(x * 255.0f);
}
我想,以同样的方式,我们可以通过乘以(pow( 2,16 ) -1)
得到短的int
但后来我最终想到了有序的抖动,尤其是拜耳的抖动。要转换为uint8_t,我想我可以使用4x4矩阵和8 * 8矩阵进行无符号短路。
我还想到了一个查找表来加速这个过程,这样:
uint16_t LUT[0x10000] // 2^16 values contained
并存储2 ^ 16个与浮点相对应的无符号短值。同样的表也可以用于uint8_t,因为unsigned short < - > unsigned int之间的隐式转换
但是这样的查找表难道不会在内存中占据巨大的位置吗?那怎么会像这样填满一张桌子?!
现在我很困惑,你最好的是什么?谢谢你的帮助 !
在uwind回答之后编辑:现在让我们说我也想同时进行基本颜色空间转换,即在转换为U8 / U16之前,进行颜色空间转换(浮动),然后将其缩小为U8 / U16 。在这种情况下,不会使用更高效的lut吗?是的,我仍然有问题索引lut ..
.
我看到它的方式,查找表将无济于事,因为为了索引它,您需要将float转换为某种整数类型。赶上22。
该表需要0x10000 * sizeof(uint16_t)字节,即128 KB。现代标准不是很多,但另一方面缓存是宝贵的。但是,正如我所说,该表并没有给解决方案增加太多,因为你需要将float转换为整数才能进行索引。
您可以将由浮点的原始位索引的表重新解释为整数,但这必须是32位,这将变得非常大(大约8 GB)。
转到您概述的直接运行时转换。
只要保持乘法 - 它会正常工作。
实际上,所有现代CPU都有适应这些内容的向量指令(SSE,AVX,...),所以你可能会考虑编程。或者使用自动矢量化代码的编译器(如果可能)(Intel C,也是GCC)。即使在表查找是一种可能的解决方案的情况下,这通常也会更快,因为您不会受到内存延迟的影响。
首先,应该注意的是float
具有24位精度,无法适应16位int
甚至8位。其次,浮动范围更大,不能存储在任何int
或long long int
所以你的问题标题实际上是不正确的,无法将任何浮点数精确地转换为short或char。您希望将0到1之间的浮点值映射到8位或16位int范围。
对于上面使用的代码,它可以正常工作。但是,值255极不可能返回,因为它只需要1.0作为输入,否则诸如254.99999之类的值最终会被截断为254.您应该舍入值而不是
return (int)(x * 255.0f + .5f);
或者更好,使用链接中提供的代码进行更均衡的分发
static inline uint8_t u8fromfloat_trick(float x)
{
union { float f; uint32_t i; } u;
u.f = 32768.0f + x * (255.0f / 256.0f);
return (uint8_t)u.i;
}
使用LUT不会更快,因为16位值的表太大而无法放入缓存中,实际上可能会大大降低性能。上面的代码片段只需要2个浮点指令,或者只需要1个FMA。 SIMD将进一步提高4-32倍(或更高)的性能,因此LUT方法很容易超越,因为并行化表格查找起来要困难得多