代码之家  ›  专栏  ›  技术社区  ›  Durandal

性能:浮点到int转换,剪切结果到范围

  •  3
  • Durandal  · 技术社区  · 16 年前

    我正在用float做一些音频处理。结果需要转换回PCM样本,我注意到从float到int的转换非常昂贵。 更令人沮丧的是,我需要将结果压缩到一个短的范围内(从32768到32767)。 虽然我通常假设可以通过简单地将浮点转换为短来保证这一点,但在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的原始音频数据)。当将循环索引分配给sample来替换强制转换分配“int sample=(int)floatval”时,从运行时差异得出6%。

    • 编辑@ LeOrdkot:我知道Java中的截断,如原问题(f2i,i2s字节码序列)中所述。我只是尝试了CAST,因为我假设Java有一个F2S字节码,但不幸的是,它并没有(最初是从一个68 K汇编背景开始的,在这里,一个简单的“ft.w fp0,d0”会做我想要的)。

    5 回复  |  直到 14 年前
        1
  •  2
  •   Peter Lawrey    16 年前

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

    if (sample + 0x7fff8000 < 0x7fff0000)
        sample = sample < 0 ? -32768 : 32767;
    
        2
  •  1
  •   leopoldkot    16 年前

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

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

    请将此答案转换为评论。

        3
  •  0
  •   Chris Dodd    16 年前

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

        4
  •  0
  •   dash-tom-bang    16 年前

    这是python,但应该易于转换。我不知道浮点运算的开销有多大,但是如果你能把它保存在整数寄存器中,你可能会得到一些提升;这假设你可以把IEEE754位重新解释为一个in t(这就是我名字不好的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
    

    这种分支可能会杀死你,但也许这提供了一些有用的东西?这一轮接近零。

        5
  •  -1
  •   user207421    16 年前

    int sample=(int)floatval)&0xffff;