将范围-1到1的浮点数转换为短的快速方法?
Posted
技术标签:
【中文标题】将范围-1到1的浮点数转换为短的快速方法?【英文标题】:Fast way of converting float of range -1 to 1 to short? 【发布时间】:2010-08-12 09:26:59 【问题描述】:我需要将 1024+ 个连续的 4 字节浮点数(范围 -1 到 1)重复转换为 2 字节短字节(范围 -32768 到 32767)并写入磁盘。
目前我使用循环来执行此操作:
short v = 0;
for (unsigned int sample = 0; sample < length; sample++)
v = (short)(inbuffer[sample * 2] * 32767.0f);
fwrite(&v, 2, 1, file);
这可行,但浮点计算和循环很昂贵。有什么办法可以优化吗?
【问题讨论】:
警告:如果 -1.0 转换为 -32768 而 0.0 转换为 0,则 +1.0 应转换为 +32768,它不在short
范围内。
也许 OP 的意思是“从 -1 到但不包括 1”。即便如此,浮点舍入错误也可能造成麻烦。也许最好将计算暂时保存在int
中,然后在将其存储在float
之前检查其值。
好点,-32767 到 32767 应该没问题。
这个问题是一个完美的例子,说明了为什么问题应该包含完整的上下文。
【参考方案1】:
short v = 0;
for (unsigned int sample = 0; sample < length; sample++)
v = (short)(inbuffer[sample * 2] * 32767.0f);
// The problem is not here-------^^^^^^^^^^^
fwrite(&v, 2, 1, file);
// it is here ^^^^^^^
典型的 Mac(objective-c 标签,或者我们在这里谈论的是 iphone?)每秒可以进行 十亿 次浮点乘法。然而 fwrite 是一个库调用,它遵循一些间接将其数据写入某个缓冲区并可能刷新它。最好批量填充自己的缓冲区:
short v[SZ] = 0;
// make sure SZ is always > length, or allocate a working buffer on the heap.
for (unsigned int sample = 0; sample < length; sample++)
v[sample] = (short)(inbuffer[sample * 2] * 32767.0f);
fwrite(v,sizeof(v),1,file);
【讨论】:
【参考方案2】:我原以为重复调用fwrite
将是昂贵的部分。怎么样:
short outbuffer[length]; // note: you'll have to malloc this if length isn't constant and you're not using a version of C that supports dynamic arrays.
for (unsigned int sample = 0; sample < length; sample++)
outbuffer[sample] = (short)(inbuffer[sample * 2] * 32767.0f);
fwrite(outbuffer, sizeof *outbuffer, length, file);
【讨论】:
即使他有动态数组,在您不知道大小限制的上下文中使用它们也不是一个好主意。当心堆栈溢出。【参考方案3】:我想,循环的瓶颈可能不是浮点转换,而是将输出写入文件 - 尝试将文件输出移到循环之外
short v = 0;
short outbuffer = // create outbuffer of required size
for (unsigned int sample = 0; sample < length; sample++)
outbuffer[sample] = (short)(inbuffer[sample * 2] * 32767.0f);
fwrite(outbuffer, 2, sizeof(outbuffer), file);
【讨论】:
【参考方案4】:你可以试试这样的:
out[i] = table[((uint32_t *)in)[i]>>16];
其中table
是一个查找表,它将IEEE 浮点数的高16 位映射到您想要的int16_t
值。但是,这将失去一些精度。您需要保留并使用 23 位(1 个符号位、8 个指数位和 14 个尾数位)以获得全精度,这意味着一个 16 MB 的表,这会破坏缓存的一致性,从而降低性能。
您确定浮点转换很慢吗?只要您以这种方式使用fwrite
,您在fwrite
上花费的CPU 时间是浮点运算的50-100 倍。如果您处理此问题并且代码仍然太慢,您可以使用添加魔术偏差并读取尾数位以转换为int16_t
的方法,而不是乘以 32767.0。这可能会也可能不会更快。
【讨论】:
以上是关于将范围-1到1的浮点数转换为短的快速方法?的主要内容,如果未能解决你的问题,请参考以下文章