ex = x - 2y ex = :(x - 2y) dump(ex) macro reverse(ex) if isa(ex, Expr) && ex.head == :call return Expr(:call, ex.args[1], reverse(ex.args[2:end])...) else return ex end end # equivalent to 3 - 1 @reverse 1 - 4 macro horner(x, c...) ex = esc(c[end]) for i = length(c)-1:-1:1 ex = :($(esc(c[i])) + t * $ex) end return Expr(:block, :(t = $(esc(x))), ex) end function my_erfinv(x::Float32) # specialized for single-precision args a = abs(x) if a >= 1.0f0 if x == 1.0f0 return inf(Float32) elseif x == -1.0f0 return -inf(Float32) end throw(DomainError()) elseif a <= 0.75f0 # Table 10 in Blair et al. t = x*x - 0.5625f0 return x * @horner(t, -0.13095_99674_22f2, 0.26785_22576_0f2, -0.92890_57365f1) / @horner(t, -0.12074_94262_97f2, 0.30960_61452_9f2, -0.17149_97799_1f2, 0.1f1) elseif a <= 0.9375f0 # Table 29 in Blair et al. t = x*x - 0.87890625f0 return x * @horner(t, -0.12402_56522_1f0, 0.10688_05957_4f1, -0.19594_55607_8f1, 0.42305_81357f0) / @horner(t, -0.88276_97997f-1, 0.89007_43359f0, -0.21757_03119_6f1, 0.1f1) else # Table 50 in Blair et al. t = 1.0f0 / sqrt(-log(1.0f0 - a)) return @horner(t, 0.15504_70003_116f0, 0.13827_19649_631f1, 0.69096_93488_87f0, -0.11280_81391_617f1, 0.68054_42468_25f0, -0.16444_15679_1f0) / (copysign(t, x) * @horner(t, 0.15502_48498_22f0, 0.13852_28141_995f1, 0.1f1)) end end @vectorize_1arg Real my_erfinv using PyCall @pyimport scipy.special as s x = rand(10^7); @time erfinv(x); @time s.erfinv(x); norm(erfinv(x) - s.erfinv(x)) / norm(erfinv(x))