簡體   English   中英

是否可以優化此功能?

[英]Is it possible to optimize this function?

經過剖析后,我發現這種方法占用了大部分計算時間。 我真的沒有看到優化的方法,因為它是一個可怕的功能。 (它是......)也許有人能給我一些好主意嗎?

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%:

  • 舊:6,2%,有7000000個電話
  • 新增:3,2%8000000電話。

謝謝你到目前為止!

Edit2:我不知道接受哪個答案。 :(與其他一些改進(主要是查找表)9000聲音文件的處理時間從4:30min下降到3:28min。

我將保持這個問題,看看是否有其他想法,但接受一個答案。

編輯:我現在有點沮喪。 我使用JFace treeviewer讓用戶瀏覽結果,它需要更多的時間來更新計算本身。 :/

你的函數似乎是解析的,我建議用插值方法完全替換它。 這樣,您就可以Math.Pow的昂貴調用減少到幾個算術運算。

在這種情況下,最好的應該是有理函數逼近。 你的函數可能在復平面上有極點,這通常會使多項式插值失效。

請注意,您有兩個變量: L_G - a0 - L_ETQL_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)) )。

所以你應該對一些算術運算和指數運算很好。

編輯: 查看t2的圖表作為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。

數學並不會立即看起來像是可以重新排序以避免任何重復計算,因此采用的方法取決於此函數的使用方式以及所需的准確結果。

最好的方法是避免重新計算同一組輸入值的值。 您的代碼可以保存相同輸入值的計算結果嗎? 如果沒有,你可以有一個值的緩存,但要注意雙打可以有很多值,你可能想要將雙打折疊成一個已知的間隔(例如從0到1折疊成0到99之間的整數)。

我猜

double t2 = Math.sqrt(Math.sqrt(t1));

比...更快

double t2 = Math.pow(t1, 0.25);

看一下你引用的那篇論文,似乎L_ETQ和a0只是聲音頻率(Bark)的函數。

因此,至少你可以得到一個表格,列出給定頻率的各種計算結果。 例如,緩存結果:

.064 * Math.pow(10, 0.025 * L_ETQ)

按頻率。 [還可以緩存(a0 + L_ETQ)* .1]

此外,可能是微小的影響,如果有的話,但我會將1/4轉換為0.25。

為程序可以處理的輸入范圍預先生成查找表。

它沒有比這更快! :)

根據輸入參數緩存輸出可能會有所幫助:

http://en.wikipedia.org/wiki/Memoization

這還沒有提到,所以我會。

您可能需要考慮從浮點數學轉換為整數。 操作速度要快得多。 由於添加和存儲浮點數,圖形傾向於使用整數數學而不是浮動。 你必須要進行轉換,但我相信你會獲得相當大的性能提升。 整數數學的唯一問題是你必須定義你願意接受多少精度。

  1. 嘗試緩存一些值(我猜L_G和L_ETQ不是那個變量,對吧?)
  2. 嘗試在體系結構相關代碼中實現並使用JNI。

我會采取一些反對意見 ,以消除猜測。 這樣我就可以確定在其他地方沒有采取時間,比如讀取數據並將其轉換為浮點數,或打開/關閉文件。 當我確定這個例程占用了大部分時間時,我很確定它幾乎會花費所有時間來調用Math函數,並將L_ETQ轉換為整數。 有可能記住那些數學函數。 然后,正如亞歷山大所說,你可以用插值來完成所有這些工作。

問題是,你可能有不止一件事要優化。 如果這需要180秒,如果50%,比如那個時間,這個例程在堆棧上,那么如果你將時間縮短一半,你將時間減少了45秒到135秒。 但是,現在這個例程只在堆棧上持續45/135秒或1/3。 這意味着其他一些東西正在使用其他2/3或90秒,我敢打賭,你可以優化一些東西。 如果你可以將那些減少到45秒,那么總數減少到90,並且數學例程所占的百分比回升到50%,所以也許你可以從中擠出更多。 就是這樣。 每次你削減它的一部分,其他部分的百分比增加,所以你可以一遍又一遍地追逐它們,直到你真的盡可能地擠壓它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM