使用Math函数优化此Java代码的建议

时间:2014-03-19 08:30:37

标签: java

我有以下java代码。我正在尝试优化功能

        while(pStart < audio.length) {

        int pEnd = Math.round(pStart + winSize*Fs);

        int windowEnd = Math.min(pEnd, audio.length);
        double[] window = new double[fftSize*2];

        for(int i = pStart; i < windowEnd; i++) {
            window[(i-pStart)*2] = audio[i];
        }

        fft.complexForward(window);

        double fftVal;
        for(int i = 0; i < fftSize/2; i++) {

            fftVal = Math.sqrt((window[i*2] * window[i*2])  + (window[i*2+1] * window[i*2+1] ));

            powerAll[i][index] = 20 * Math.log10(
                    Math.abs(fftVal) / (windowEnd - pStart));
        }
        index++;


        pStart = pStart + windowSlide;


    }

根据跟踪文件计时:

总计2500毫秒 fft~500 ms 自我~900毫秒 第二个循环~900毫秒

所以,我的重点是优化第二个for循环,就像现在一样。我无法改变fft功能。

在同一个问题上,我不确定,为什么追踪报告&#34; self&#34;是900毫秒。

3 个答案:

答案 0 :(得分:3)

您的代码是并行化的简单目标。你可以:

  1. 手动完成,计算要传递给每个线程的子数组索引;
  2. 使用ForkJoin为您处理许多方面;
  3. 使用刚刚发布的Java 8并将其写为parallelStream处理任务。
  4. 我的选择肯定会排在第3位,如果没别的话,那就是它的乐趣。

    我花了一些时间来测量我的设置上的代码,使用jmh。 window数组的每个条目需要14纳秒。考虑到完成的计算量,我认为这已经是一个很好的结果,并且无法以任何显着的差距进行改进。

答案 1 :(得分:2)

通过应用日志函数的数学属性可以简化原始代码。

考虑从原始代码中提取的以下函数:

double original( double[] window, int i, int windowEnd, int pStart ) {
    double fftVal = Math.sqrt(
            ( window[ i * 2 ] * window[ i * 2 ] )
                    + ( window[ i * 2 + 1 ] * window[ i * 2 + 1 ] )
    );
    return 20 * Math.log10(
            Math.abs( fftVal ) / ( windowEnd - pStart ) );
}

基本上,我们在伪代码中有以下功能:

x = sqrt(w[2i]^2 + w[2i+1]^2)
return 20 * log( abs(x) / ( windowEnd - pStart ) )
  • abs不是必需的,因为sqrt()的值是非负的。
  • log(X / Y)== log(X) - log(Y)
  • log(sqrt(X))= 0.5 log(X)
  • log(windowEnd - pStart)可以预先计算并兑现

简化版本,每个步骤都有说明:

double variant( double[] window, int i, int windowEnd, int pStart ) {

    // w[2i]^2 + w[2i+1]^2
    double temp1 = window[ i * 2 ] * window[ i * 2 ]
            + window[ i * 2 + 1 ] * window[ i * 2 + 1 ];

    // apply log(sqrt(X)) == log(X^0.5) == 0.5 log(X)
    double temp2 = 0.5 * Math.log10( temp1 );

    // calculate the value of Math.log10( windowEnd - pStart )
    // (and cache it outside of the function) 
    double tempConst3 = Math.log10( windowEnd - pStart );

    // apply log(X/Y) == log(X) - log(Y)
    double temp4 = temp2 - tempConst3;

    return 20 * temp4;
}

答案 2 :(得分:0)

您可以执行的简单优化是将window[i*2]window[i*2+1]的值存储在变量中,并在sqrt()方法中使用它们,这将减少数组访问次数。

除此之外,如果你能说出你想做什么,我们或许可以帮助你。