Làm thế nào để tính toán hàm Sin nhanh hơn và chính xác hơn?


8

Tôi muốn tính toán y(n)=32677Sin(45/1024•n), ysố nguyên ở đâu và nnằm trong khoảng từ 0 đến 2048. Làm cách nào tôi có thể thực hiện quy trình này nhanh hơn và chính xác hơn? Bây giờ tôi muốn cho bạn thấy một câu trả lời tham khảo: Kể từ Sin(a+b)=Sin(a)Cos(b)+Cos(a)Sin(b)Cos(a+b)=Cos(a)Cos(b)-Sin(a)Cos(b). Vì vậy, tôi có thể lưu trữ Sin(45/1024•1)và chỉ Cos(45/1024•1). Sau đó sử dụng công thức này:

Sin(45/1024•2)=Sin(45/1024•1+45/1024•1), Cos(45/1024•2)=Cos(45/1024•1+45/1024•1), Sin(45/1024•n)=Sin(45/1024•(n-1)+45/1024•1), Cos(45/1024•n)=Cos(45/1024•(n-1)+45/1024•1), Cách này có thể nhanh hơn mà không cần lưu trữ mảng lớn.


Câu hỏi này phù hợp với các lập trình viên, giả sử ý định là tìm hiểu về các thuật toán và / hoặc cấu trúc dữ liệu phù hợp từ góc độ của các mối quan tâm về công nghệ phần mềm.
Thomas Owens

8
45 đó là một chút nghi ngờ; nó làm tôi nghĩ rằng bạn muốn sin(x)nơi xcó độ. Nếu đó là trường hợp, bạn cần lưu ý rằng đối số cho các hàm trig thường là bằng radian. Đối số là radian trong C ++, đó là cách câu hỏi này được gắn thẻ.
David Hammen

Tại sao bạn cần câu hỏi này trả lời? Ứng dụng là gì?
GlenPeterson

Làm thế nào chính xác để bạn cần kết quả là?
dan04

@ dan04 Vì y là số nguyên nên tôi cần chính xác là số nguyên.
LaiJong

Câu trả lời:


18

Nếu ntrong khoảng từ 0 đến 2048, bạn có thể tính toán trước các giá trị, lưu trữ sau đó trong một mảng. y(n)sẽ trở thành values[n].


+1 và bạn có thể nội suy cho bất kỳ giá trị nào ở giữa (nếu đó là một khả năng).
Daniel B

1
Đó là một tùy chọn khả thi, mặc dù tôi vẫn cấu hình nó để đảm bảo rằng nó hiệu quả hơn so với tính toán nó (ví dụ: fsincó thể sử dụng FPU và thân thiện với bộ đệm hơn so với một số mảng).
Benjamin Bannier

Làm thế nào về việc không lưu trữ giá trị [n]?
LaiJong

3
Các hàm lượng giác rất chậm để tính toán khi đang bay. Tôi khá chắc chắn rằng mọi triển khai nhanh đều sử dụng các giá trị được tính toán trước. Vì sin () và cos () là định kỳ, bạn chỉ cần lưu trữ 90 độ đầu tiên. Bạn có thể trả về -sin () hoặc sin (90 - góc) hoặc -sin (90 - góc) tùy thuộc vào góc phần tư. Bạn cũng có thể định nghĩa cos () theo nghĩa sin (). Nếu bạn biết phạm vi có thể của các giá trị đầu vào, bạn có thể tính toán trước và chỉ lưu trữ các giá trị bạn cần cho chương trình của mình. Nếu không, nội suy giữa một số giá trị giới hạn có thể là tùy chọn nhanh nhất của bạn.
GlenPeterson

1
@Glen: Giá trị Sin nằm trong khoảng -1 đến 1, vì vậy nó thực sự sẽ phù hợp với 16 bit không dấu.
vartec

1

Tính toán bảng tại thời gian biên dịch thay vì thời gian chạy.

Bạn đang thực hiện bảng 2048 phần tử gồm các giá trị nguyên được chia tỷ lệ 16 bit.

Viết một tập lệnh Matlab giá rẻ, với một bản in cung cấp một dòng dữ liệu phù hợp với ngôn ngữ lập trình cuối cùng của bạn. Cắt và dán kết quả vào mã nguồn của bạn, dưới dạng bảng dữ liệu không đổi và thực hiện tra cứu bảng trong thời gian chạy. Điều này đẩy thời gian tính toán ban đầu vào chu kỳ xây dựng, thay vì thời gian khởi động chương trình.


Bao nhiêu thời gian chạy này tiết kiệm so với chi phí lập trình viên thêm?
JBRWilkinson

Nhanh chóng và hèn hạ. Đẹp.
lượng

1

Với dạng của hàm, câu trả lời tự nhiên là thuật toán CORDIC . Đó là một cách tiếp cận sạch sẽ hơn nhiều so với sự cố trong câu hỏi. Mặt khác, bảng mà nó cần là rất xa, nhỏ hơn nhiều so với bảng mà người khác đã đề xuất.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.