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

问题描述 投票:0回答:3

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

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

.

c casting char unsigned short
3个回答
1
投票

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

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

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

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


0
投票

只要保持乘法 - 它会正常工作。

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


-1
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.