Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

Very Fast Sin Function for Java

0.00/5 (No votes)
3 Dec 2012CPOL1 min read 10.1K  
A very fast Sin function for Java
Shedding some light on high performance.

Copyright: Dr Alexander J Turner - all rights reserved.
 

Math.sin and the other transcendental functions in the JDKs java.lang.Math package tend to be very slow indeed. There are fast workarounds however.

The reason for the slowness is consistence. The library is designed to produce exactly the same results on all platforms. The results are standards compliant to the last binary bit. This is just great if that is what you need. However, for some applications, like audio synthesis for example, it is total overkill.

In DSP outboard processors, wavetables have been used for years. The idea being that is you pre-compute a set of values for a wave against phase angle. Then, when a value is required, it's offset into the pre-computed table is used to get the value straight away. Sonic-Field stores audio at float (32 bit floating point) precision. A table big enough to hold all the possible values for the sin function where the phase angle is a float is way to big to be practical. It turns out that we really do not require anything like as big a table as that. A relatively modest table with linear interpolation gives results which are within float rounding error of the Math.sin values. The results are plenty good enough for audio work:

C#
static double[]             table = null;
static double               step;
static double               invStep;
static int                  size  = 0;

static
{
    size = 10000;
    table = new double[size];
    step = 2d * Math.PI / size;
    invStep = 1.0f / step;
    for (int i = 0; i < size; ++i)
    {
        table[i] = Math.sin(step * i);
    }
}

/** Find a linear interpolation from the table
 * 
 * @param ang
 *            angle in radians
 * @return sin of angle a
 */
private final static double pi2   = PI * 2;

final public static double sin(double ang)
{
    double t = ang % pi2;
    int indexA = (int) (t / step);
    int indexB = indexA + 1;
    if (indexB >= size) return table[indexA];
    double a = table[indexA];
    return a + (table[indexB] - a) * (t - (indexA * step)) * invStep;
}

The above code is straight from Sonic Field (and is therefore AGPL v3.0). It creates a 10 thousand element table. I tried a bigger table but it did not improve the results noticeably though less did degrade the accuracy rapidly. I have not micro-benchmarked the code, but Sonic Field patches using this code show the functions using sin running up to 10 times faster than using the Math.sin function.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)