2011-07-15 24 views
10

Tôi phải đánh giá một số lượng lớn các biểu thức có chứa các biến và tôi đang nghĩ đến việc viết một trình thông dịch nhỏ để biên dịch nhanh và nhỏ. Tuy nhiên tôi không có kinh nghiệm với chủ đề này và có một vài câu hỏi.Trình thông dịch tùy chỉnh cho các biểu thức toán học

Giả sử chúng tôi có tệp có biểu thức toán học và tập hợp các đối tượng có giới hạn. Các tập tin có thể trông giống như:

expr[x,y,z] = 2*x*y + x^2 + 28/14*z*(x*y^2 + 15*z) + ... 

Tôi muốn phân tích này bằng cách nào đó để tôi có thể đánh giá các biểu thức về số trong ứng dụng của tôi bằng cách đơn giản gọi một hàm expr(float x, float y, float z). Không được sửa số tham số (EDIT: mỗi biểu thức sẽ có định nghĩa riêng với số tham số thích hợp hoặc sẽ chấp nhận một mảng) và lồng vào dấu ngoặc đơn sẽ được phép giữ các tệp đầu vào hợp lý nhỏ.

Vì biểu thức là tất cả các loại đa thức, tôi có thể nghĩ cấu trúc dữ liệu trông như thế nào, nhưng việc phân tích cú pháp có vẻ khó khăn. Tôi đã tìm thấy một số câu trả lời cho một số câu hỏi tương tự ở đây trên SO, ví dụ bằng cách sử dụng Lua.

Câu hỏi lớn nhất, tuy nhiên, là hình phạt hiệu suất sẽ là khi tạo và gọi các đối tượng đó so với việc biên dịch trực tiếp các biểu thức này từ mã C được tạo tự động.

Cảm ơn trước!

CHỈNH SỬA: Vui lòng xem xét ví dụ về expr() ở trên chỉ như vậy. Tôi đoán cách tốt nhất là để có các đối tượng của một lớp templated giữ hệ số và quyền hạn của các biến trong mảng thưa thớt.

+0

"kêu gọi một hàm expr (float x, float y, nổi z) Số lượng các thông số không nên cố định." - bạn đã có một chút của một vấn đề ở đó, sau đó, vì số lượng tham số trong C hoặc gọi hàm C++ * là * cố định. Ngay cả với varargs, nơi callee có thể đối phó với các số khác nhau, người gọi phải sửa số ở thời gian biên dịch. Bạn có lẽ sẽ cần phải vượt qua một mảng thay thế. –

+0

@Steve Jessop: Đã sửa lỗi, tôi biết điều này. – bbtrb

+0

Tại sao bạn không viết biểu thức hàm của bạn dưới dạng hàm C và biên dịch/chạy nó? –

Trả lời

6

Hiệu suất là một vấn đề về độ dài của chuỗi. Các ngôn ngữ được phiên dịch khá nhiều luôn chậm hơn mã C đã biên dịch để đánh giá các biểu thức số học. Nhưng không phải là nhiều chương trình dành phần lớn thời gian của họ làm số học, vì vậy phần lớn thời gian không quan trọng. Nó cũng làm cho một sự khác biệt cho dù bạn phân tích cú pháp biểu thức mỗi khi bạn đánh giá nó hoặc (có vẻ như nhiều khả năng từ những gì bạn nói), phân tích nó thành một số hình thức trung gian. Không thể nói từ những gì bạn đã nói, cho dù điều đó có quan trọng với bạn hay không, hoặc bạn sẽ viết một thông dịch viên nhanh như thế nào, nhưng tôi sẽ không mong đợi nó tốt hơn 10 lần chậm hơn, theo thời gian đã đánh giá các biểu thức có liên quan. Những nỗ lực đầu tiên diễn giải đã tồi tệ hơn nhiều.

Đối với biểu mẫu trung gian đó - nơi thông thường để bắt đầu là sử dụng thuật toán "shunting-yard" của Dijkstra để chuyển đổi biểu thức của bạn thành dạng Ba Lan ngược. Điều đó cung cấp cho bạn một chuỗi các "ký hiệu", "mã byte", gọi chúng là những gì bạn thích và dễ dàng viết một bộ đánh giá biểu thức cho biểu mẫu đó - mỗi toán tử chỉ bật các toán hạng từ một chồng, thực hiện lệnh op, sau đó đẩy kết quả vào ngăn xếp, cho đến khi giá trị cuối cùng của biểu thức là điều duy nhất còn lại ở cuối. Chữ số và tên biến số giống như "toán tử" không bật toán hạng và đẩy giá trị của chúng.

[Chỉnh sửa - tùy thuộc vào người dùng của bạn là ai, có thể chương trình của bạn lấy tệp văn bản đó, tạo chương trình C từ nó, chạy trình biên dịch rồi chạy chương trình kết quả (hoặc mở và gọi vào dll kết quả). Rõ ràng là dựa vào rất nhiều công cụ cụ thể của hệ thống (một trình biên dịch được cài đặt, cho một), và các biểu thức sẽ cần phải được đánh giá đủ lần mà chi phí biên dịch được khắc phục.]

+0

Cảm ơn bạn đã nhập. Vì vậy, đây là điểm: Các biểu thức bao gồm đôi khi hàng nghìn thuật ngữ (với tối đa 15 tham số) và nên được đánh giá lặp đi lặp lại cho các giá trị tham số khác nhau. Phân tích cú pháp chỉ nên thực hiện một lần. Suy nghĩ về đề xuất của bạn để đẩy và bật từ một ngăn xếp, tôi đoán câu hỏi của tôi là: Đây có phải là cách đúng để làm nếu các biểu thức luôn luôn đa thức? Sẽ có một hình phạt hiệu suất (ngoài việc phân tích ban đầu) ở tất cả nếu tôi muốn thực hiện điều này như trong EDIT thứ hai của tôi? – bbtrb

+0

@bbrtb: những gì được mô tả trong chỉnh sửa thứ hai của bạn thường sẽ có phần chậm hơn so với cùng một biểu thức được viết bằng C. Thứ nhất bởi vì có một số nguyên cần thiết để truy cập vào cấu trúc thưa thớt mà nói với bạn những quyền hạn và hệ số, thứ hai là vì trình biên dịch C đi kèm với kick-ass tối ưu hóa. Thật ví dụ đơn giản, nếu đa thức của bạn chứa lặp đi lặp lại phụ biểu sau đó tối ưu hóa C sẽ có khả năng phát hiện ra chúng và tránh việc trùng lặp, nhưng người đánh giá bạn viết mà phải mất một mảng của các hệ số sẽ có một thời gian khó khăn là bất cứ điều gì như vậy thông minh. –

+0

Tôi thấy, có vẻ như nó đáng để thử. Những gì tôi có thể làm để tối ưu hóa điều này với một số mở rộng là làm tổ các đối tượng đa thức. Các đầu vào tôi có là như trong bài viết của tôi, do đó, nó đã được đơn giản hóa vì nó được tạo ra với Mathematica. – bbtrb

0

Có một ví dụ đơn giản trong số Bison Manual.

+1

Điều này sẽ OP phân tích cú pháp đánh giá biểu thức khi nó phân tích cú pháp. Nếu OP phải đánh giá lại biểu thức, sử dụng kỹ thuật này sẽ buộc OP phải trả lại.Trong các chủ đề bình luận khác, anh nói anh không muốn làm điều đó. –

+0

Nếu OP muốn biên dịch biểu thức thành một số loại cây đối tượng, ví dụ cung cấp một điểm bắt đầu – doron

1

Bạn nói vấn đề là "biểu thức lớn phức tạp", và bạn lo lắng về hình phạt hiệu suất. Sau đó, bạn nên xem xét biên dịch chúng, không giải thích chúng. (trình thông dịch tốt có tốc độ chậm hơn 10 lần so với mã được biên dịch dưới dạng quy tắc chung; trình thông dịch lousy/ad hoc có xu hướng tồi tệ hơn đáng kể).

Các tuyến đường thường lệ cho điều này là để "biên dịch" các biểu thức bằng cách nào đó, trong đó bao gồm phân tích cú pháp xây dựng, máy phát điện mã, tối ưu hóa, vv

C trình biên dịch đã làm tất cả điều này. Vì vậy, tôi nghĩ bạn muốn được tốt hơn tắt dịch các biểu thức để C. Biên soạn họ là sau đó dễ dàng và thực hiện sẽ nhanh như chớp so với bất cứ điều gì bạn có thể hy vọng sẽ làm như thông dịch viên. Điều đó cũng có thể được thực hiện bằng cách sử dụng một trình phân tích cú pháp và cú pháp dịch hướng dịch đơn giản hơn nhiều.

Nhưng Nếu những biểu thức này được tạo ra bởi Mathematica, chúng sẽ có cấu trúc khá chuẩn nhưng không phức tạp. Trong trường hợp này, tôi đoán bạn có thể viết một dịch giả dựa trên regexp có thể ánh xạ các dạng Mathematica vào các hàm C mà không gặp nhiều rắc rối; Perl sẽ là lý tưởng cho việc này. Điều này mang lại cho bạn một giải pháp dễ thực hiện và rất nhanh.

Đối với những gì nó có giá trị, tôi tin rằng Mathematica có một tùy chọn để chuyển đổi biểu thức Mathematica trực tiếp vào C. Có vẻ rằng đó sẽ là giá trị kiểm tra ra, quá.

+0

Cảm ơn bạn đã nhập. Vấn đề là, tôi có 100 MB biểu thức được đánh giá nhiều lần cho các tham số khác nhau, do đó việc biên dịch trực tiếp không phải là cách để đi (tôi đã thử điều này và một trong các câu hỏi SO của tôi giải quyết vấn đề này trong một dự án liên quan) . Tôi biết rất khó để ước tính (và tôi chưa có thời gian để làm việc này), nhưng quy tắc ngón tay cái chậm hơn 10 lần cũng có thể đánh giá như tôi đã đề cập trong lần chỉnh sửa thứ hai (lặp lại lặp lại trên mảng thưa thớt) không? – bbtrb

+0

Bạn nói trình biên dịch trực tiếp không phải là cách để đi, nhưng bạn không đưa ra bất kỳ lý do gì khác ngoài lý do khác ngoài một tham chiếu mơ hồ đến một dự án khác mà tôi rõ ràng là không thuộc về. Nếu bạn mã hóa một thông dịch viên, bạn sẽ có một thông dịch viên. Trừ khi bạn viết mã thực sự tốt (tôi nhận được ấn tượng này không phải là một kỹ năng cụ thể mà bạn nghĩ rằng bạn có), bạn sẽ làm tồi tệ hơn so với 10x thông thường. –

+0

... Tôi đã xem các câu hỏi SO khác của bạn; rõ ràng nhất có liên quan là "tập tin đối tượng của tôi là> 2 Gb" nhưng bạn dường như đã nhận được xung quanh đó. Vậy vấn đề với giải pháp khác là gì? Tôi sẽ đồng ý với giọng của hầu hết các câu trả lời; Tôi nghĩ bạn nên xem xét lại cách bạn có số lượng lớn các chức năng khổng lồ như vậy ngay từ đầu. Không ai viết tất cả mã đó; nó đang được tạo ra bằng cách nào đó. Tôi nghĩ rằng bạn cần phải quay trở lại cách nó được tạo ra và xem xét lại tại sao nó được tạo ra theo cách đó; rõ ràng, nó làm cho vấn đề khó giải quyết hơn. –

Các vấn đề liên quan