Horner rule

 macro horner(x, p...)
     ex = p[end]
     for i = length(p)-1:-1:1
         ex = :($(p[i]) + $x * $ex)
     end
     ex
 end

I was looking at this https://github.com/JuliaLang/julia/pull/2987/commits/9c24795ac2918df7b8cba9bb129db8c535d321e8
and just want to know what

  1. : infront of the bracket is for
  2. $ is supposed to do?
    I mean in principle I could have also written it without : and $, but maybe they have some nice features ?

See https://docs.julialang.org/en/stable/manual/metaprogramming/#Interpolation-1

1 Like

https://docs.julialang.org/en/latest/manual/metaprogramming/

would be a good start. And please quote your code (```).

3 Likes

I dont see a difference. Did the quoting work for you?

Maybe not belonging to the topic, but why do people like to write long numbers like
0.10501_31152_37334_38116e-3

Does it nothing but a better overview of the number?

Thx for the answers btw!

Yes, just for readability. (You should keep one thread to one topic though).

1 Like

This uses metaprogramming to “unroll” the expression. Use @macroexpand to see the result.

julia> @macroexpand(ans)
ERROR: UndefVarError: @macroexpand not defined

???

Please quote your code – this has been requested repeatedly by multiple people.

I did…but it does not work.

I used blockquote only for the code.

https://discuss.atom.io/t/quoting-code-as-code/8140

1 Like

@macroexpand works since Julia 0.6. You feed it the macro code directly.
It is strongly recommended to upgrade to Julia 0.6.

julia> @macroexpand Base.Math.@horner(5, 1, 2, 3, 4)
quote
    #19#t = 5
    (Base.Math.muladd)(#19#t, (Base.Math.muladd)(#19#t, (Base.Math.muladd)(#19#t, 4, 3), 2), 1)
end

Sorry, but I don’t quite get what you mean:
While Base.Math.@horner(5, 1, 2, 3, 4)
just runs the macro and gives me 586
pretyping @macroexpand then tells me
(Base.Math.muladd)
What does this tell me?

That’s a problem with the syntax highlighting. It’s giving you
(Base.Math.muladd)(#19#t, (Base.Math.muladd)(#19#t, (Base.Math.muladd)(#19#t, 4, 3), 2), 1)
which is the code that the macro is producing.

 macro horner(x, p...)
     ex = p[end]
     for i = length(p)-1:-1:1
         ex = :($(p[i]) + $x * $ex)
     end
     ex
 end

Wouldnt I expect it to show me this code? Maybe with numbers inserted?

What does #19#t stand for? (I guess the variable 5, but why is it called this way?)

It would really help if you read the documentation first, working through it carefully, then asked questions to fill in the holes.

2 Likes

I am reading, but maybe you could show me the one crucial line telling me in https://docs.julialang.org/en/stable/manual/metaprogramming/#Interpolation-1 what the major advantage is doing it this way and not the “normal”

It just says it’s powerful…ok
but why? I dont yet see it…

1 Like

What would the “normal” way be? Try that, and compare it to what the macro does, e.g. in terms of speed.

macro horner01(x, p...)
    ex = p[end]
    for i = length(p)-1:-1:1
        ex = :($(p[i]) + $x * $ex)
    end
    ex
end

function horner02(x, p::Array)
    ex = p[end]
    for i = length(p)-1:-1:1
        ex = ((p[i]) + x * ex)
    end
    ex
end

setprecision(10^8)
x=big(9528)/10000

@time @horner01(x,4,3,2,1);
@time horner02(x,[4,3,2,1]);

So here it is not faster…Why should it be faster?

BTW: if I change function to macro it does not like this p::Array, why?

Also it is telling me

WARNING: Method definition @horner01(ANY<:Any, Any…) in module Main at C:\Users\Diger\Documents\Julia\various math problems\compare horner.jl:2 overwritten at C:\Users\Diger\Documents\Julia\various math problems\compare horner.jl:2.
WARNING: Method definition horner02(Any, Array{Int64, 1}) in module Main at C:\Users\Diger\Documents\Julia\various math problems\compare horner.jl:10 overwritten at C:\Users\Diger\Documents\Julia\various math problems\compare horner.jl:10.

even though I renamed the functions?!

1 Like
julia> using BenchmarkTools

julia> f(x) = Base.Math.@horner(x, 4, 3, 2, 1)
f (generic function with 1 method)

julia> @btime f(0.2)
  1.847 ns (0 allocations: 0 bytes)
4.688

julia> v = [4., 3., 2., 1.]
4-element Array{Float64,1}:
 4.0
 3.0
 2.0
 1.0

julia> function horner02(x, p::Array)
           ex = p[end]
           for i = length(p)-1:-1:1
               ex = ((p[i]) + x * ex)
           end
           ex
       end
horner02 (generic function with 1 method)

julia> @btime horner02(0.2, $v)
  12.850 ns (0 allocations: 0 bytes)
4.688
1 Like

I’m actually not really worried about 1ns or even 1000ns, but when I goes in the seconds range I’m…
So repeating your first function

f(x) = Base.Math.@horner(x, 4, 3, 2, 1);
@time f(x);

where x is the bigfloat I defined before.
This gives me sth like 4.2s as does the other.

Why do you prefer working with some external benchmarking package, rather than using what comes with julia?