将范围在-1到1之间的浮点数快速转换为短整型的方法?

3

我需要反复将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);
}

这个方法能够工作,但是浮点数的计算和循环操作比较耗费性能。是否有优化的方法?


2
警告:如果-1.0翻译为-32768,0.0翻译为0,则+1.0应该翻译为+32768,这不在“short”范围内。 - mouviciel
也许OP的意思是“从-1到但不包括1”。即便如此,浮点数舍入误差可能会引起问题。最好将计算暂时保存在“int”中,然后在将其存储在“float”之前检查其值。 - David
好的,-32767到32767应该没问题。 - Morrowless
2
这个问题是为什么问题应该包含完整上下文的完美例子。 - caf
4个回答

6
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);

即使他有动态数组,在不知道大小限制的情况下使用它们并不是一个好主意。要小心堆栈溢出。 - Jens Gustedt

2

我认为您的循环瓶颈可能不是浮点数转换,而是将输出写入文件 - 尝试将文件输出移出循环

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);

0
你可以尝试这样做:
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。这可能会更快,也可能不会。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接