2015-01-21 14 views
12

Tôi đang cố gắng sử dụng macro @evalpoly của Julia. Nó hoạt động khi tôi cung cấp các hệ số theo cách thủ công, nhưng tôi không thể tìm ra cách cung cấp các hệ số này thông qua một mảngMacro Julia @evalpoly với 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() 

Ai đó có thể chỉ cho tôi đúng hướng?

gia tăng sau khi nhìn thấy câu trả lời tuyệt vời cho câu hỏi này

Có một sự tinh tế đến rằng tôi đã không nhìn thấy cho đến khi tôi chơi với một số trong những câu trả lời. Các z lập luận để @evalpoly có thể là một biến, nhưng các hệ số được dự kiến ​​sẽ là các chữ

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 

Nhìn vào kết quả của việc mở rộng lệnh cuối cùng này, người ta có thể thấy rằng nó thực sự là trường hợp đó z được gán đến một biến trong phần mở rộng nhưng các hệ số được chèn vào đúng theo mã.

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) 

Trả lời

8

Tôi không tin những gì bạn đang cố gắng làm là có thể, bởi vì @evalpoly là một vĩ mô - đó có nghĩa là nó tạo ra mã tại thời gian biên dịch. Những gì nó được tạo ra là một thực hiện rất hiệu quả phương pháp của Horner (trong trường hợp số thực), nhưng để làm như vậy nó cần phải biết mức độ đa thức. Độ dài c không được biết tại thời gian biên dịch, vì vậy nó không (và không thể) làm việc, trong khi khi bạn cung cấp các hệ số trực tiếp, nó có mọi thứ cần thiết.

Thông báo lỗi không tốt lắm, vì vậy nếu có thể, bạn có thể gửi một vấn đề trên trang Julia Github?

CẬP NHẬT: Để trả lời cập nhật cho câu hỏi, có, đối số đầu tiên có thể là một biến. Bạn có thể nghĩ về nó như thế này:

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 

đang trở thành

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 

trừ, không phải là, bởi vì nó sử dụng Horners quy tắc, nhưng bất cứ điều gì. Vấn đề là, nó không thể tạo ra biểu thức đó tại thời gian biên dịch mà không biết số lượng hệ số. Nhưng nó không cần phải biết những gì z là ở tất cả.

+1

[PR # 7186] (https://github.com/JuliaLang/julia/pull/7186) sẽ cho phép điều này thông qua một phiên bản chức năng. Có vẻ như nó có thể sử dụng một số hỗ trợ - thêm một bình luận thể hiện mong muốn của bạn để xem nó trong cơ sở! –

+0

Ian, cảm ơn vì sự thấu hiểu của bạn. Tôi chắc chắn đánh giá cao nó vì nó giúp tôi grok Julia macro nói chung, không chỉ vấn đề cụ thể này. Tôi sẽ cố gắng theo dõi đề xuất của bạn để thêm sự cố trong vài ngày tới. –

+0

Tôi đã cập nhật cho bản cập nhật của bạn, hãy cho tôi biết nếu nó rõ ràng. – IainDunning

7

Macro trong Julia được áp dụng cho đối số của chúng. Để thực hiện công việc này, bạn cần đảm bảo rằng c được mở rộng trước khi @evalpoly được đánh giá. Đây hoạt động:

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

Ở đây, @eval đánh giá đối số của nó, và mở rộng $(c...). Sau đó, @evalpoly thấy năm đối số.

Khi được viết, điều này có thể không hiệu quả kể từ khi @eval được gọi mỗi khi hàm f được gọi. Bạn cần phải di chuyển các cuộc gọi đến @eval bên ngoài định nghĩa hàm:

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

này gọi @eval khi f được định nghĩa. Rõ ràng, c phải được biết tại thời điểm này.Bất cứ khi nào f thực sự được gọi, c không được sử dụng nữa; nó chỉ được sử dụng trong khi f đang được xác định.

4

Erik và Iain đã thực hiện một công việc tuyệt vời để giải thích lý do tại sao @evalpoly không hoạt động và cách ép buộc nó hoạt động. Nếu bạn chỉ muốn đánh giá các đa thức, tuy nhiên, các giải pháp đơn giản nhất có lẽ là chỉ để sử dụng Polynomials.jl:

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