将float 32精确地转换为unsigned short或unsigned char

时间:2013-01-08 11:05:07

标签: c casting char unsigned short

首先对不起,如果这是重复的,我找不到任何主题回答我的问题。

我正在编写一个小程序,用于将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)

,我们可以通过相同的方式得到短整数

然后我最终想到了有序的抖动,尤其是拜耳的抖动。 要转换为uint8_t,我想我可以使用4x4矩阵和8 * 8矩阵进行无符号短路。

我还想到了一个查找表来加速这个过程,这样:

uint16_t LUT[0x10000] // 2^16 values contained

并存储2 ^ 16个与浮点相对应的无符号短值。 同样的表也可以用于uint8_t,因为它之间存在隐式转换 unsigned short< - > unsigned int

但是这样的查找表不会在内存中占据巨大的位置吗?如何填写这样的表格?!

现在我很困惑,你最好的是什么? 谢谢你的帮助!

在顺风回答之后编辑:现在让我说我也想同时进行基本的颜色空间转换,即在转换为U8 / U16之前,进行颜色空间转换(浮动),然后将其缩小为U8 / U16。在这种情况下,不会使用更高效的lut吗?是的,我仍然有问题索引lut ..

3 个答案:

答案 0 :(得分:1)

我看到它的方式,查找表无济于事,因为为了索引它,你需要将float转换为某种整数类型。赶上22。

该表需要0x10000 * sizeof(uint16_t)字节,即128 KB。现代标准不是很多,但另一方面缓存是宝贵的。但是,正如我所说的那样,该表并没有给解决方案增加太多,因为你需要将float转换为整数才能进行索引。

你可以将一个由浮点的原始位索引的表重新解释为整数,但这必须是32位,这将变得非常大(大约8 GB)。

进行您概述的直接运行时转换。

答案 1 :(得分:0)

坚持乘法 - 它会正常工作。

实际上,所有现代CPU都有适应这些内容的向量指令(SSE,AVX,...),因此您可能会考虑编程。或者使用自动矢量化代码的编译器(如果可能)(Intel C,也是GCC)。即使在表查找是一种可能的解决方案的情况下,这通常也会更快,因为您不会受到内存延迟的影响。

答案 2 :(得分:-1)

首先,应该注意float具有24位精度,这不能适合16位int甚至8位。其次,float的范围要大得多,不能存储在任何intlong 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方法很容易超越,因为并行化表格查找起来要困难得多