mollusk 0e4acfb8f2 fix incorrect folder name for julia-0.6.x
Former-commit-id: ef2c7401e0876f22d2f7762d182cfbcd5a7d9c70
2018-06-11 03:28:36 -07:00

135 lines
4.9 KiB
Julia

# Based on FreeBSD lib/msun/src/e_exp.c
# which is made available under the following licence
## Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. Permission
## to use, copy, modify, and distribute this software is freely granted,
## provided that this notice is preserved.
# Method
# 1. Argument reduction: Reduce x to an r so that |r| <= 0.5*ln(2). Given x,
# find r and integer k such that
# x = k*ln(2) + r, |r| <= 0.5*ln(2).
# Here r is represented as r = hi - lo for better accuracy.
#
# 2. Approximate exp(r) by a special rational function on [0, 0.5*ln(2)]:
# R(r^2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r^4/360 + ...
#
# A special Remez algorithm on [0, 0.5*ln(2)] is used to generate a
# polynomial to approximate R.
#
# The computation of exp(r) thus becomes
# 2*r
# exp(r) = 1 + ----------
# R(r) - r
# r*c(r)
# = 1 + r + ----------- (for better accuracy)
# 2 - c(r)
# where
# c(r) = r - (P1*r^2 + P2*r^4 + ... + P5*r^10 + ...).
#
# 3. Scale back: exp(x) = 2^k * exp(r)
# log(2)
const LN2 = 6.931471805599453094172321214581765680755001343602552541206800094933936219696955e-01
# log2(e)
const LOG2E = 1.442695040888963407359924681001892137426646
# log(2) into upper and lower
LN2U(::Type{Float64}) = 6.93147180369123816490e-1
LN2U(::Type{Float32}) = 6.9313812256f-1
LN2L(::Type{Float64}) = 1.90821492927058770002e-10
LN2L(::Type{Float32}) = 9.0580006145f-6
# max and min arguments for exponential fucntions
MAXEXP(::Type{Float64}) = 7.09782712893383996732e2 # log 2^1023*(2-2^-52)
MAXEXP(::Type{Float32}) = 88.72283905206835f0 # log 2^127 *(2-2^-23)
# one less than the min exponent since we can sqeeze a bit more from the exp function
MINEXP(::Type{Float64}) = -7.451332191019412076235e2 # log 2^-1075
MINEXP(::Type{Float32}) = -103.97207708f0 # log 2^-150
@inline exp_kernel(x::Float64) = @horner(x, 1.66666666666666019037e-1,
-2.77777777770155933842e-3, 6.61375632143793436117e-5,
-1.65339022054652515390e-6, 4.13813679705723846039e-8)
@inline exp_kernel(x::Float32) = @horner(x, 1.6666625440f-1, -2.7667332906f-3)
# for values smaller than this threshold just use a Taylor expansion
@eval exp_small_thres(::Type{Float64}) = $(2.0^-28)
@eval exp_small_thres(::Type{Float32}) = $(2.0f0^-13)
"""
exp(x)
Compute the natural base exponential of `x`, in other words ``e^x``.
"""
function exp(x::T) where T<:Union{Float32,Float64}
xa = reinterpret(Unsigned, x) & ~sign_mask(T)
xsb = signbit(x)
# filter out non-finite arguments
if xa > reinterpret(Unsigned, MAXEXP(T))
if xa >= exponent_mask(T)
xa & significand_mask(T) != 0 && return T(NaN)
return xsb ? T(0.0) : T(Inf) # exp(+-Inf)
end
x > MAXEXP(T) && return T(Inf)
x < MINEXP(T) && return T(0.0)
end
# This implementation gives 2.7182818284590455 for exp(1.0) when T ==
# Float64, which is well within the allowable error; however,
# 2.718281828459045 is closer to the true value so we prefer that answer,
# given that 1.0 is such an important argument value.
if x == T(1.0) && T == Float64
return 2.718281828459045235360
end
if xa > reinterpret(Unsigned, T(0.5)*T(LN2)) # |x| > 0.5 log(2)
# argument reduction
if xa < reinterpret(Unsigned, T(1.5)*T(LN2)) # |x| < 1.5 log(2)
if xsb
k = -1
hi = x + LN2U(T)
lo = -LN2L(T)
else
k = 1
hi = x - LN2U(T)
lo = LN2L(T)
end
else
n = round(T(LOG2E)*x)
k = unsafe_trunc(Int,n)
hi = muladd(n, -LN2U(T), x)
lo = n*LN2L(T)
end
r = hi - lo
# compute approximation on reduced argument
z = r*r
p = r - z*exp_kernel(z)
y = T(1.0) - ((lo - (r*p)/(T(2.0) - p)) - hi)
# scale back
if k > -significand_bits(T)
# multiply by 2.0 first to prevent overflow, which helps extends the range
k == exponent_max(T) && return y * T(2.0) * T(2.0)^(exponent_max(T) - 1)
twopk = reinterpret(T, rem(exponent_bias(T) + k, fpinttype(T)) << significand_bits(T))
return y*twopk
else
# add significand_bits(T) + 1 to lift the range outside the subnormals
twopk = reinterpret(T, rem(exponent_bias(T) + significand_bits(T) + 1 + k, fpinttype(T)) << significand_bits(T))
return y * twopk * T(2.0)^(-significand_bits(T) - 1)
end
elseif xa < reinterpret(Unsigned, exp_small_thres(T)) # |x| < exp_small_thres
# Taylor approximation for small x
return T(1.0) + x
else
# primary range with k = 0, so compute approximation directly
z = x*x
p = x - z*exp_kernel(z)
return T(1.0) - ((x*p)/(p - T(2.0)) - x)
end
end