All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.barrybecker4.math.function.ErrorFunction.scala Maven / Gradle / Ivy

The newest version!
/* Copyright by Barry G. Becker, 2000-2018. Licensed under MIT License: http://www.opensource.org/licenses/MIT */
package com.barrybecker4.math.function

import com.barrybecker4.math.{MathUtil, Range}
import com.barrybecker4.math.interpolation.LinearInterpolator

/**
  * Gaussian error function
  * @author Barry Becker
  */
object ErrorFunction {

  private val MAX_ERROR_FUNCTION_TABLE_VALUE = 5.3

  /** The gaussian error function table.
    * See http://eceweb.uccs.edu/Wickert/ece3610/lecture_notes/erf_tables.pdf
    * for values of x  = 0.0, 0.1, ... MAX_ERROR_FUNCTION_TABLE_VALUE
    * Try plotting this in log scale to help understanding.
    */
  private val ERROR_FUNCTION = Array(
    0.0000000, 0.0563721, 0.11246296, 0.16800, 0.2227026, 0.27633, 0.3286268, 0.37938, 0.4283924, 0.47548, 0.5204999,
    0.56332, 0.6038561, 0.64203, 0.6778012, 0.71116, 0.7421008, 0.77067, 0.7969081, 0.82089, 0.8427007, 0.86244,
    0.883533, 0.89612, 0.910314, 0.92290, 0.9340079, 0.94376, 0.9522851, 0.95970, 0.9661051, 0.97162, 0.9763484,
    0.98038, 0.9837905, 0.98667, 0.9890905, 0.99111, 0.9927904, 0.99418, 0.99532213, 0.996258, 0.9970205, 0.99764,
    0.9981372, 0.99854, 0.9988568, 0.99911, 0.9993115, 0.99947, 0.9995901, 0.99969, 0.99976, 0.99982, 0.99987,
    0.9999, 0.99992, 0.99994, 0.99995887, 0.99996977878, 0.999977894, 0.999983, 0.999988, 0.999991, 0.9999931,
    0.9999957, 0.9999975, 0.9999980, 0.9999984, 0.99999870, 0.99999930, 0.99999970, 0.999999840, 0.999999901,
    0.9999999350, 0.999999860, 0.999999910, 0.999999931, 0.999999955, 0.999999971,
    //    4.0      4.05       4.1         4.15      4.2         4.25       4.3         4.35       4.4         4.45          4.5         4.55        4.6            4.65         4.7              4.75          4.8             4.85            4.9           4.95
    0.99999998453, 0.999999988, 0.999999993279, 0.999999995601, 0.99999999713, 0.99999999814275, 0.999999998802, 0.999999999231, 0.9999999995088, 0.99999999968776, 0.9999999998024914, 0.999999999875673, 0.9999999999221209, 0.999999999951454, 0.9999999999698866,
    0.9999999999814, 0.9999999999885819, 0.9999999999930206, 0.9999999999957546, 0.9999999999974303, 0.99999999999845, 0.9999999999988, 0.99999999999945, 0.9999999999996, 0.999999999999806, 0.9999999999996, 0.99999999999994)
  /** for values of x  = 0.0, 0.1, ... 1.0 */
  private val INVERSE_ERROR_FUNCTION = Array(0.0, 0.089, 0.18, 0.28, 0.379, 0.479, 0.596, 0.738, 0.91, 1.161, 3.28)
}

class ErrorFunction() extends InvertibleFunction {

  private val interpolator = new LinearInterpolator(ErrorFunction.ERROR_FUNCTION)
  private val inverseInterpolator = new LinearInterpolator(ErrorFunction.INVERSE_ERROR_FUNCTION)

  /** We expect x to be in the range approximately 0.0, 5.0.
    * Values outside of -MAX_ERROR_FUNCTION_TABLE_VALUE to MAX_ERROR_FUNCTION_TABLE_VALUE are
    * Currently just using simple linear interpolation.
    * We could improve by using quadratic interpolation.
    * @param x x value to get y for
    * @return error function value for x.
    */
  override def getValue(x: Double): Double = {
    val sign = if (x >= 0) 1.0
    else -1.0
    if (Math.abs(x) > ErrorFunction.MAX_ERROR_FUNCTION_TABLE_VALUE) {
      val v = 1.0 - (100.0 - Math.abs(x)) * MathUtil.EPS_MEDIUM
      if (x > 50) System.out.println("erf(" + x + ")=" + v) //NON-NLS
      assert(v > 0.0, " x=" + x + " v=" + v)
      return sign * v
    }
    sign * interpolator.interpolate(Math.abs(x) / ErrorFunction.MAX_ERROR_FUNCTION_TABLE_VALUE)
  }

  /** We expect x to be in the range [-1.0, 1.0].
    * Currently just using simple linear interpolation.
    * We could improve by using quadratic interpolation.
    * @param x inverse error function value for x.
    * @return inverse error function value for x.
    */
  override def getInverseValue(x: Double): Double = {
    assert(x >= -1.0 && x <= 1.0)
    val sign = if (x >= 0) 1.0
    else -1.0
    sign * inverseInterpolator.interpolate(Math.abs(x))
  }

  override def getDomain = Range(-5.0, 5.0)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy