Approximate e^x

前端 未结 10 2081
一向
一向 2020-12-13 16:28

I\'d like to approximate the ex function.

Is it possible to do so using multiple splines type based approach? i.e between x1

相关标签:
10条回答
  • 2020-12-13 16:35

    This is not the smooth spline interpolation you requested but its computationally efficient:

    float expf_fast(float x) {
       union { float f; int i; } y;
       y.i = (int)(x * 0xB5645F + 0x3F7893F5);
       return (y.f);
    }
    

    Plot Output image

    0 讨论(0)
  • 2020-12-13 16:39

    First off, what is motivating this approximation? In other words, what exactly is wrong with the straightforward exp(x)?

    That said, a typical implementation of exp(x) is to

    • Find an integer k and floating point number r such that x=k*log(2) + r and r is between -0.5*log(2) and 0.5*log(2).
    • With this reduction, exp(x) is 2k*exp(r).
    • Calculating 2k is a snap.
    • The standard implementations of exp(x) use a Remes-type algorithm to come up with a minimax polynomial that approximates exp(r).
    • You could do the same, but use a reduced order polynomial.

    Here's the kicker: No matter what you do the odds are very high that your function will be much, much slower than just calling exp(). Most of the functionality of exp() is implemented in your computer's math coprocessor. Re-implementing that functionality in software, even with reduced precision, is going to be an order of magnitude slower than just using exp().

    0 讨论(0)
  • 2020-12-13 16:39

    Wolfram presents a few good ways of approximating it in terms of series etc:

    • Wolfram page for ex

    Wikipedias page on Taylor Series also shows an example of an expansion of ex around 0:

    0 讨论(0)
  • 2020-12-13 16:40

    Of course it is "possible". There are several issues.

    1. What is your requirement for the accuracy?

    2. Are you willing to use higher order splines?

    3. How much memory are you willing to spend on this? Linear function over small enough intervals will approximate the exponential function to any degree of accuracy needed, but it may require a VERY small interval.

    Edit:

    Given the additional information provided, I ran a quick test. Range reduction can always be used on the exponential function. Thus, if I wish to compute exp(x) for ANY x, then I can rewrite the problem in the form...

    y = exp(xi + xf) = exp(xi)*exp(xf)
    

    where xi is the integer part of x, and xf is the fractional part. The integer part is simple. Compute xi in binary form, then repeated squarings and multiplications allow you to compute exp(xi) in relatively few operations. (Other tricks, using powers of 2 and other intervals can give you yet more speed for the speed hungry.)

    All that remains is now to compute exp(xf). Can we use a spline with linear segments to compute exp(xf), over the interval [0,1] with only 4 linear segments, to an accuracy of 0.005?

    This last question is resolved by a function that I wrote a few years ago, that will approximate a function with a spline of a given order, to within a fixed tolerance on the maximum error. This code required 8 segments over the interval [0,1] to achieve the required tolerance with a piecewise linear spline function. If I chose to reduce the interval further to [0,0.5], I could now achieve the prescribed tolerance.

    So the answer is simple. If you are willing to do the range reductions to reduce x to the interval [0.0.5], then do the appropriate computations, then yes you can achieve the requested accuracy with a linear spline in 4 segments.

    In the end, you will always be better off using a hard coded exponential function though. All of the operations mentioned above will surely be slower than what your compiler will provide, IF exp(x) is available.

    0 讨论(0)
  • 2020-12-13 16:44

    If x is an integer, you can just multiply e by itself over and over again.

    If x is not an integer, you can calculate the efloor(x) using the above method and then multiply by a small correction term. This correction term can be easily calculated using a number of approximation methods. One such way is this:

    ef1 + f(1 + f/2(1 + f/3(1 + f/4))), where f is the fractional part of x

    This comes from the (optimized) power series expansion of ex, which is very accurate for small values of x. If you need more accuracy, just tack on more terms to the series.

    This math.stackexchange question contains some additional clever answers.

    EDIT: Note that there is a faster way of calculating en called exponentiation by squaring.

    0 讨论(0)
  • 2020-12-13 16:46

    http://martin.ankerl.com/2007/02/11/optimized-exponential-functions-for-java/ using Schraudolph's method (http://nic.schraudolph.org/pubs/Schraudolph99.pdf) in Java:

    public static double exp(double val) {
        final long tmp = (long) (1512775 * val) + (1072693248 - 60801);
        return Double.longBitsToDouble(tmp << 32);
    }
    

    and https://math.stackexchange.com/a/56064 (look for Pade approximant).

    0 讨论(0)
提交回复
热议问题