/* fast floating point exp function
 * must initialize table with buildexptable before using
 
Based on 
 A Fast, Compact Approximation of the Exponential Function
 Nicol N. Schraudolph 1999

Adapted to single precision to improve speed and added adjustment table to improve accuracy.
Alrecenk 2014

* i = ay + b
* a = 2^(mantissa bits) / ln(2)   ~ 12102203
* b = (exponent bias) * 2^ ( mantissa bits) ~ 1065353216
*/

package utils.math;
 
public class FastMath{

  public FastMath(){
    buildexptable(-10.0,10.0,0.0001);
  }
  
  private static float expadjust[] ;
  
  public float fastexp(float x){
    final int temp = (int)(12102203 * x + 1065353216) ;
    return Float.intBitsToFloat(temp)*expadjust[(temp>>15)&0xff] ;
  }
  
  public float fastexp(Double x){
    final int temp = (int)(12102203 * x + 1065353216) ;
    return Float.intBitsToFloat(temp)*expadjust[(temp>>15)&0xff] ;
  }
  //build correction table to improve result in region of interest
  //if region of interest is large enough then improves result everywhere
  private void buildexptable(double min, double max, double step){
    expadjust = new float[256];
    int amount[] = new int[256] ;
    //calculate what adjustments should have been for values in region
    for(double x=min; x < max;x+=step){
      double exp = Math.exp(x);
      int temp = (int)(12102203 * x + 1065353216) ;
      int index = (temp>>15)&0xff ;
        double fexp = Float.intBitsToFloat(temp);
      expadjust[index]+= exp/fexp ;
      amount[index]++;
    }
    //average them out to get adjustment table
    for(int k=0;k<amount.length;k++){
      expadjust[k]/=amount[k];
    }
  }
  
  public static void main(String[] args) {
    FastMath fm = new FastMath();
    Double d=0.01;
    float f=10;
    float retval=0;
    retval=fm.fastexp(d);
    System.out.println("retval: "+retval);
  }
}