as most of you know, the Values class offers some static methods for faster calculations of the most commonly used math functions.
While there are fast implementations of the power function for the bases e, 2 and 10 (Fast[E|Ten|Two]ToTheX), which are somewhere between 2 to 6 times faster than Javas Math.pow function (depending on the input values), the Values class is missing a fast implementation of the logarithm.
Yes, there is the PercentToDecibels method, which can be "abused" to calculate a logarithm, but it isn't really faster than Javas Math.log function (actually it was slower in the tests I did). So I went into the deepest depths of the interwebs on the hunt for a fast logarithm implementation and I came across this. It's implemented in C, but I was up for the challenge to make this usable in Java for module development. So, long story short, this is what I came up with:
Code: Select all
public static float fastLog2(float x) {
if (x < 0.0f) {
return Float.NaN;
} else if (x == 0.0f) {
return Float.NEGATIVE_INFINITY;
}
int i = Float.floatToRawIntBits(x);
if ((i & 0x007FFFFF) == 0x0) { // mantissa is 0, so return unbiased exponent
return ((i >> 23) & 0xFF) - 127.0f;
}
float f = Float.intBitsToFloat((i & 0x007FFFFF) | 0x3F000000);
return i * 1.1920928955078125e-7f - 124.22551499f
- 1.498030302f * f
- 1.72587999f / (0.3520887068f + f);
}
public static float fasterLog2(float x) {
if (x < 0.0f) {
return Float.NaN;
} else if (x == 0.0f) {
return Float.NEGATIVE_INFINITY;
}
int i = Float.floatToRawIntBits(x);
if ((i & 0x007FFFFF) == 0x0) { // mantissa is 0, so return unbiased exponent
return ((i >> 23) & 0xFF) - 127.0f;
}
return i * 1.1920928955078125e-7f - 126.94269504f;
}
// for convenience
public static double fastLog2(double x) {
return (double)fastLog2((float)x);
}
public static double fasterLog2(double x) {
return (double)fasterLog2((float)x);
}
You can use the fastLog2 to convert Hz to volts (-0.25V = a0 = 55.0 Hz) with
Code: Select all
public static double HzToVolts(double hz) {
return fastLog2(hz / 55.0) - 0.25;
}
Code: Select all
public static final double TWENTY_OVER_LOG2_TEN = 6.0205999132796239042747778944898605353637;
public static double PercentToDecibels(double percent) {
if (percent <= 0.0) {
return Double.NEGATIVE_INFINITY;
} else if (percent == 1.0) {
return 0.0;
}
return TWENTY_OVER_LOG2_TEN * fastLog2(percent);
}
If anyone knows of a faster and/or more accurate implementation, please feel free to share it here.
Best regards,
Martin