Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to optimize this function?

after profiling a lot I found out that this method takes up most of the % of calculation time. I don't really see a way to optimize, since it is a horrible function. (it is...) Maybe someone can show me some nice idea or so?

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);
 }

Here is the improved version:

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);
 }

The lookup for ltqFactors goes this way. ltqValues hold 20 points from the given ltq function, that approx should be sufficiant.

for( int i = 0; i < etqValues.length; ++i) {
  ltqFactors[(int)etqValues[i]] = 0.064d * Math.exp(etqValues[i] * 0.05756462732485114210d);
  }

Edit: After more test runs with more files, I come up to a ~100% speed up:

  • Old: 6,2% with 7000000 calls
  • New: 3,2% 8000000 calls.

Thank you so far!

Edit2: I don't know which answer to accept. :( With some other improvements (mostly lookup tables) the processing time for 9000 sound files went down from 4:30min to 3:28min.

I will keep this question open to see if there are other ideas, but then accept one answer.

Edit: I'm kind of frustrated now. I use a JFace treeviewer to let the user browse the results, and it need more time to update than the calculations itself. :/

like image 395
InsertNickHere Avatar asked Jul 23 '10 08:07

InsertNickHere


People also ask

What does it mean to optimize a function?

Mathematically speaking, optimization is the minimization or maximization of a function subject to constraints on its variables.


1 Answers

Your function seems to be analytic, I would suggest replacing it entirely with an interpolation method. This way, you reduce the expensive calls to Math.Pow to a few arithmetical operations.

The best in this case should be rational function approximation. Your function is likely to have poles in the complex plane, this usually defeats polynomial interpolation.

Note that you have two variables: L_G - a0 - L_ETQ and L_ETQ. Interpolation should be performed in one variable only.

I'd go for rational function approximation of t2 as a function of L_G - a0 - L_ETQ. Take a look at Numerical Recipes for implementation techniques.

Also, for the last part, replace

Math.pow(10, 0.025 * L_ETQ); 

by

Math.exp(L_ETQ * 0.05756462732485114210d)

(which is exp(L_ETQ * 0.025 * log(10))).

So you should be fine with a handful of arithmetical operations and one exponential.

EDIT: See a graph of t2 as a function of L_G - a0 - L_ETQ.

EDIT: Replace

double t1 = 1d + 1 / 4d * Math.pow(10d, 0.1d * (L_G - a0 - L_ETQ)); 
double t2 = Math.pow(t1, 0.25);

by

double x = L_G - a0 - L_ETQ;
double t1 = 0.25 * Math.exp(0.230259 * x) + 1;
double t2 = Math.sqrt(Math.sqrt(t1));

and you should gain some more %. At this point, rational approximation may be overengineering: you have two exp, and two sqrt.

like image 136
Alexandre C. Avatar answered Oct 16 '22 22:10

Alexandre C.