性能:浮动到int cast和剪切结果到范围

时间:2010-05-27 16:05:27

标签: java performance floating-point

我正在使用float进行一些音频处理。结果需要转换回PCM样本,我注意到从float到int的转换是非常昂贵的。 更令人沮丧的是,我需要将结果剪辑到短路(-32768到32767)的范围内。 虽然我通常会明确地假设这可以通过简单地将float转换为short来确保,但这在Java中失败,因为在字节码级别它导致F2I后跟I2S。所以不是简单的:

int sample = (short) flotVal;

我需要诉诸这个丑陋的序列:

int sample = (int) floatVal;
if (sample > 32767) {
    sample = 32767;
} else if (sample < -32768) {
    sample = -32768;
}

有更快的方法吗?

(约占运行总时间的约6%似乎花费在铸造上,而乍一看似乎没有那么多6%,当我认为处理部分涉及大量矩阵乘法和IDCT时,它令人震惊)

  • 编辑上面的强制转换/剪辑代码(不出意料地)在循环体中,它从float []中读取浮点值并将它们放入byte []中。我有一个测试套件,可以测量几个测试用例的总运行时间(处理大约200MB的原始音频数据)。当通过将循环索引分配给样本来替换强制转换赋值“int sample =(int)floatVal”时,6%是从运行时差异中得出的结论。

  • 编辑@leopoldkot:我知道Java中的截断,如原始问题(F2I,I2S字节码序列)中所述。我只是简单地尝试了强制转换,因为我认为Java有一个F2S字节码,但遗憾的是它没有(最初来自68K汇编背景,其中一个简单的“fmove.w FP0,D0”就完全符合我的要求)

5 个答案:

答案 0 :(得分:2)

对于范围内的值,您可以将两个比较转换为一个。这可以使成本减半。目前,如果值太过负,则只执行一次比较。 (这可能不是你的典型案例)

if (sample + 0x7fff8000 < 0x7fff0000)
    sample = sample < 0 ? -32768 : 32767;

答案 1 :(得分:1)

当你将int转换为short时,你永远不会得到剪切功能,比特被截断然后被读作短。 例如。 (短)-40000变为25536,而不是你预期的-32768。

可能你必须编辑你的问题,如果你反汇编字节码,我相信你知道的。 此外,还有一个JIT编译器可以优化此代码(因为它经常被调用)到平台相关指令。

请将此回答转换为评论。

答案 2 :(得分:0)

float to int转换是你可以在x86处理器上执行的最慢的操作之一,因为它需要修改x87舍入模式(两次),这会对处理器进行序列化和刷新。如果你可以使用SSE指令而不是x87指令,你可以获得相当大的加速,但我不知道是否有办法在java中做到这一点。也许尝试使用x86_64 JVM?

答案 3 :(得分:0)

这是Python,但应该很容易转换。我不知道浮点运算的成本有多高,但如果你能将它保存在整数寄存器中,你可能会有一些提升;这假设您可以将IEEE754位重新解释为int。 (这就是我命名为float2hex的名字。)

import struct

def float2hex(v):
    s = struct.pack('f', v)
    h = struct.unpack('I', s)[0]
    return h

def ToInt(f):
    h = float2hex(f)
    s = h >> 31
    exp = h >> 23 & 0xFF
    mantissa = h & 0x7FFFFF
    exp = exp - 126
    if exp >= 16:
        if s:
            v = -32768
        else:
            v = 32767
    elif exp < 0:
        v = 0
    else:
        v = mantissa | (1 << 23)
        exp -= 24
        if exp > 0:
            v = v << exp
        elif exp < 0:
            v = v >> -exp

        if s:
            v = -v

    print v

这种分支可能会杀了你,但也许这提供了一些有用的东西?这个趋势为零。

答案 4 :(得分:-1)

int sample =((int)floatval)&amp; 0xFFFF的;