我有以下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毫秒。
答案 0 :(得分:3)
您的代码是并行化的简单目标。你可以:
ForkJoin
为您处理许多方面; parallelStream
处理任务。 我的选择肯定会排在第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 ) )
简化版本,每个步骤都有说明:
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()
方法中使用它们,这将减少数组访问次数。
除此之外,如果你能说出你想做什么,我们或许可以帮助你。