使用数学函数优化此java代码的建议

使用数学函数优化此java代码的建议,java,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

我有以下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;


    }
while(pStart
根据跟踪文件进行计时:

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

现在,我的重点是优化第二个for循环。我不能改变fft函数


在同一个问题上,我不确定为什么跟踪程序报告“self”为900毫秒。

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


除此之外,如果你能说出你想做什么,我们可能会更好地帮助你。

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


除此之外,如果你能说出你想做什么,我们可能会更好地帮助你。

你的代码很容易成为并行化的目标。你可以:

  • 手工操作,计算要传递给每个线程的子数组索引
  • 使用
    ForkJoin
    ,它可以为您处理许多方面的问题
  • 使用刚刚发布的Java8,并将其作为
    parallelStream
    处理任务编写 我的选择当然是第三,如果没有别的,那就是为了好玩


    我花了一些时间在我的设置中使用jmh测量您的代码。
    窗口
    数组的每个条目需要14纳秒。考虑到所做的计算量,我认为这已经是一个很好的结果,并且不能有任何显著的改进。

    您的代码很容易成为并行化的目标。你可以:

  • 手工操作,计算要传递给每个线程的子数组索引
  • 使用
    ForkJoin
    ,它可以为您处理许多方面的问题
  • 使用刚刚发布的Java8,并将其作为
    parallelStream
    处理任务编写 我的选择当然是第三,如果没有别的,那就是为了好玩


    我花了一些时间在我的设置中使用jmh测量您的代码。
    窗口
    数组的每个条目需要14纳秒。考虑到所做的计算量,我认为这已经是一个很好的结果,并且不能有任何显著的改进。

    原始代码可以通过应用log函数的数学属性来简化

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

    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()的值是非负的
    • 对数(X/Y)==对数(X)-对数(Y)
    • 对数(sqrt(X))=0.5对数(X)
    • 日志(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;
    }
    

    原始代码可以通过应用log函数的数学特性来简化

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

    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()的值是非负的
    • 对数(X/Y)==对数(X)-对数(Y)
    • 对数(sqrt(X))=0.5对数(X)
    • 日志(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;
    }
    


    如果你陈述了你想做什么,那么提出解决方案就很容易了!大量的时间意味着什么?。除非fftVal真的是个大数字,否则就不应该是这样,除非笨重的含义已经改变了!是不是
    window[i*2]*window[i*2]
    和to do:
    Math.pow(window[i*2],2)
    一样?@Eldarion它在功能上是一样的,但可能快得多。您是否对FFT结果进行了预处理,而没有考虑到您正在测量的性能?因为我发现很难相信你发布的代码可以和FFT处理本身占用相同的时间顺序。如果你陈述你正在尝试做什么,那么提出解决方案就很容易了!大量的时间意味着什么?。除非fftVal真的是个大数字,否则就不应该是这样,除非笨重的含义已经改变了!是不是
    window[i*2]*window[i*2]
    和to do:
    Math.pow(window[i*2],2)
    一样?@Eldarion它在功能上是一样的,但可能快得多。您是否对FFT结果进行了预处理,而没有考虑到您正在测量的性能?因为我发现很难相信您发布的代码可以与FFT处理本身占用相同的时间顺序。JIT将处理减少的数组访问。JIT将处理减少的数组访问。谢谢,我看了java8。将尝试选项3。我编辑了这篇文章,包括完整的代码和计时汉克,我看了java8。将尝试选项3。我编辑了这篇文章,包括了完整的代码和计时,尽管这是一种新颖的方法,但是我最终使用了两个Math.log10调用,这是非常昂贵的。我测试了它,我的运行时间实际上增加了。我已经删除了abs函数。我已经两次提到可以缓存Math.log10(windowEn