2015-01-21 23 views
12

che sto cercando di Grok con Julia di @evalpoly macro. Funziona quando fornisco manualmente i coefficienti, ma sono stato in grado di decifrare come fornire questi tramite una serieJulia macro @evalpoly con varargs

julia> VERSION 
v"0.3.5" 

julia> @evalpoly 0.5 1 2 3 4 
3.25 

julia> c = [1, 2, 3, 4] 
4-element Array{Int64,1}: 
1 
2 
3 
4 

julia> @evalpoly 0.5 c 
ERROR: BoundsError() 

julia> @evalpoly 0.5 c... 
ERROR: BoundsError() 

julia> @evalpoly(0.5, c...) 
ERROR: BoundsError() 

Qualcuno mi può punto nella giusta direzione su questo?

Aggiunto dopo aver visto le grandi risposte a questa domanda

C'è una sottigliezza che non avevo visto fino a quando ho giocato con alcune di queste risposte. Il z argomento @evalpoly può essere una variabile, ma i coefficienti sono presumibilmente letterali

julia> z = 0.5 
0.5 

julia> @evalpoly z 1 2 3 4 
3.25 

julia> @evalpoly z c[1] c[2] c[3] c[4] 
ERROR: c not defined 

Guardando l'uscita della espansione di questo ultimo comando, si può vedere che è effettivamente il caso che z è assegnato ad una variabile nell'espansione ma che i coefficienti sono inseriti letteralmente nel codice.

julia> macroexpand(:@evalpoly z c[1] c[2] c[3] c[4]) 
:(if Base.Math.isa(z,Base.Math.Complex) 
     #291#t = z 
     #292#x = Base.Math.real(#291#t) 
     #293#y = Base.Math.imag(#291#t) 
     #294#r = Base.Math.+(#292#x,#292#x) 
     #295#s = Base.Math.+(Base.Math.*(#292#x,#292#x),Base.Math.*(#293#y,#293#y)) 
     #296#a2 = c[4] 
     #297#a1 = Base.Math.+(c[3],Base.Math.*(#294#r,#296#a2)) 
     #298#a0 = Base.Math.+(Base.Math.-(c[2],Base.Math.*(#295#s,#296#a2)),Base.Math.*(#294#r,#297#a1)) 
     Base.Math.+(Base.Math.*(#298#a0,#291#t),Base.Math.-(c[1],Base.Math.*(#295#s,#297#a1))) 
    else 
     #299#t = z 
     Base.Math.+(Base.Math.c[1],Base.Math.*(#299#t,Base.Math.+(Base.Math.c[2],Base.Math.*(#299#t,Base.Math.+(Base.Math.c[3],Base.Math.*(#299#t,Base.Math.c[4])))))) 
    end) 

risposta

8

Non credo che cosa si sta cercando di fare è possibile, perché @evalpoly è una macro - che significa che genera il codice a tempo di compilazione. Ciò che sta generando è un'implementazione molto efficiente del metodo di Horner (nel caso dei numeri reali), ma per farlo è necessario conoscere il grado del polinomio. La lunghezza di c non è noto al momento della compilazione, in modo che non (e non può) lavoro, mentre quando si forniscono i coefficienti direttamente ha tutto ha bisogno.

Il messaggio di errore non è molto buono anche se, quindi se è possibile, si potrebbe presentare un problema nella pagina Julia Github?

UPDATE: In risposta alla aggiornamento alla domanda, sì, il primo argomento può essere una variabile. Si può pensare a come questo:

function dostuff() 
    z = 0.0 
    # Do some stuff to z 
    # Time to evaluate a polynomial! 
    y = @evalpoly z 1 2 3 4 
    return y 
end 

sta diventando

function dostuff() 
    z = 0.0 
    # Do some stuff to z 
    # Time to evaluate a polynomial! 
    y = z + 2z^2 + 3z^3 + 4z^4 
    return y 
end 

eccezione, non quello, perché il suo utilizzo Horners regola, ma qualunque cosa. Il problema è, esso non può generare l'espressione in fase di compilazione senza conoscere il numero di coefficienti. Ma non ha bisogno di sapere cosa sia lo z.

+1

[PR # 7186] (https://github.com/JuliaLang/julia/pull/7186) sarebbe permettere questo attraverso una versione di funzione. Sembra che potrebbe usare un po 'di supporto - aggiungere un commento che esprima il tuo desiderio di vederlo in base! –

+0

Ian, grazie per la tua opinione. Lo apprezzo certamente perché mi aiuta a macinare le macro di Julia in generale, non solo questo particolare problema. Proverò a dare seguito al tuo suggerimento per aggiungere il problema nei prossimi giorni. –

+0

Ho aggiornato per il tuo aggiornamento, fammi sapere se è chiaro. – IainDunning

7

macro in Julia vengono applicate ai loro argomenti. Per fare in modo che funzioni, è necessario assicurarsi che c sia espanso prima che venga valutato @evalpoly. Questo funziona:

function f() 
    c=[1,2,3,4] 
    @eval @evalpoly 0.5 $(c...) 
end 

Qui, @eval valuta il suo argomento, e si espande $(c...). Successivamente, @evalpoly vede cinque argomenti.

Come scritto, questo probabilmente non è efficiente poiché @eval viene chiamato ogni volta che viene chiamata la funzione f. È necessario spostare la chiamata alla @eval al di fuori della definizione della funzione:

c=[1,2,3,4] 
@eval begin 
    function f() 
     @evalpoly 0.5 $(c...) 
    end 
end 

Ciò richiede @eval quando f è definito. Ovviamente, al momento è necessario conoscere c.Quando viene effettivamente chiamato il numero f, non viene più utilizzato lo c; viene utilizzato solo mentre è in corso la definizione di f.

4

Erik e Iain hanno fatto un ottimo lavoro nel spiegare perché @evalpoly non funziona e come costringerlo a funzionare. Se si desidera solo per valutare il polinomio, però, la soluzione più semplice è probabilmente solo utilizzare Polynomials.jl:

julia> using Polynomials 
     c = [1,2,3,4] 
     polyval(Poly(c), 0.5) 
3.25