public static double perceivedLoudness(double L_G, double L_ETQ, double a0) {
double t1 = 1d + 1 / 4d * Math.pow(10d, 0.1d * (L_G - a0 - L_ETQ));
double t2 = Math.pow(t1, 0.25);
return 0.064d * Math.pow(10, 0.025 * L_ETQ) * (t2 - 1);
}
以下是改进版本:
public static double perceivedLoudness(double L_G, double L_ETQ, double a0) {
double x = L_G - a0 - L_ETQ;
double t1 = 0.25 * Math.exp(0.230259 * x) + 1;
double t2 = Math.sqrt(Math.sqrt(t1));
return ltqFactors[(int)L_ETQ] * (t2 - 1);
}
对ltqFactors的查找就是这样的。 ltqValues从给定的ltq函数中保持20点,大约应该是足够的。
for( int i = 0; i < etqValues.length; ++i) {
ltqFactors[(int)etqValues[i]] = 0.064d * Math.exp(etqValues[i] * 0.05756462732485114210d);
}
编辑:经过更多文件的测试运行后,我达到了~100%的速度:
到目前为止,谢谢!
Edit2:我不知道接受哪个答案。 :( 通过一些其他改进(主要是查找表),9000个声音文件的处理时间从4:30min降至3:28min。
我会保持这个问题,看看是否有其他想法,但接受一个答案。
编辑:我现在有点沮丧。我使用JFace treeviewer让用户浏览结果,它需要更多的时间来更新计算本身。 :/答案 0 :(得分:23)
你的功能似乎是分析的,我建议用插值方法完全替换它。这样,您就可以将对Math.Pow
的昂贵调用减少到一些算术运算。
这种情况下最好的应该是有理函数逼近。你的函数可能在复平面上有极点,这通常会使多项式插值失败。
请注意,您有两个变量:L_G - a0 - L_ETQ
和L_ETQ
。插值应仅在一个变量中执行。
我会将t2
的有理函数逼近作为L_G - a0 - L_ETQ
的函数。看看Numerical Recipes的实现技巧。
另外,对于最后一部分,请替换
Math.pow(10, 0.025 * L_ETQ);
通过
Math.exp(L_ETQ * 0.05756462732485114210d)
(exp(L_ETQ * 0.025 * log(10))
)。
所以你应该对一些算术运算和指数运算很好。
编辑:
See a graph of t2
as a function of L_G - a0 - L_ETQ
.
编辑: 取代
double t1 = 1d + 1 / 4d * Math.pow(10d, 0.1d * (L_G - a0 - L_ETQ));
double t2 = Math.pow(t1, 0.25);
通过
double x = L_G - a0 - L_ETQ;
double t1 = 0.25 * Math.exp(0.230259 * x) + 1;
double t2 = Math.sqrt(Math.sqrt(t1));
你应该获得更多%。在这一点上,理性近似可能是过度工程:你有两个exp,两个sqrt。
答案 1 :(得分:3)
数学并不会立即看起来像是可以重新排序以避免任何重复计算,因此采用的方法取决于此函数的使用方式以及所需的准确结果。
最好的方法是避免重新计算同一组输入值的值。您的代码可以保存相同输入值的计算结果吗?如果没有,你可以有一个值的缓存,但要注意双打可以有很多值,你可能想要将双打折叠成一个已知的间隔(例如从0到1折叠成0到99之间的整数)。
答案 2 :(得分:3)
我猜是
double t2 = Math.sqrt(Math.sqrt(t1));
比
快double t2 = Math.pow(t1, 0.25);
答案 3 :(得分:2)
在浏览你引用的那篇论文时,似乎L_ETQ和a0只是声音频率(Bark)的函数。
所以,至少你可以想出一个给定频率的各种计算结果表。例如,缓存以下结果:
.064 * Math.pow(10, 0.025 * L_ETQ)
按频率。 [也可以缓存(a0 + L_ETQ)* .1]
此外,可能是次要影响,如果有的话,但我会将1/4转换为0.25。
答案 4 :(得分:1)
答案 5 :(得分:1)
答案 6 :(得分:1)
答案 7 :(得分:0)
答案 8 :(得分:0)
我会take some stackshots against it,以消除猜测。 这样我就可以确定在其他地方没有采取时间,比如读取数据并将其转换为浮点数,或打开/关闭文件。 当我确定这个例程占用了大部分时间时,我很确定它几乎会花费所有时间来调用Math函数,并将L_ETQ转换为整数。有可能记住那些数学函数。然后,正如亚历山大所说,你可以通过插值来完成所有这些。
问题是,你可能有不止一件事要优化。如果这需要180秒,如果50%,比如那个时间,这个例程在堆栈上,那么如果你将时间缩短一半,你将时间减少了45秒到135秒。但是,现在这个例程只在堆栈上持续45/135秒或1/3。这意味着其他一些东西正在使用其他2/3或90秒,我敢打赌,你可以优化一些东西。如果你可以将那些减少到45秒,那么总数减少到90,并且数学例程所占的百分比回升到50%,所以也许你可以从中挤出更多。就是这样。每当你减少其中的一部分时,其他部分的百分比会增加,所以你可以一遍又一遍地追踪它们,直到你真的尽可能地挤压它。