2011-09-11 43 views
9

tôi phải thực hiện asin, acos và atan trong môi trường nơi tôi đã chỉ sau công cụ toán học:xấp xỉ hàm lượng giác ngược

  • sin
  • cosin
  • số điểm
  • tiểu điểm cố định số học (nổi không có sẵn)

Tôi cũng đã có chức năng căn bậc hai hợp lý.

Tôi có thể sử dụng chúng để thực hiện các hàm lượng giác ngược hiệu quả hợp lý không?

Tôi không cần độ chính xác quá lớn (các số dấu phẩy động có độ chính xác rất hạn chế), xấp xỉ cơ bản sẽ thực hiện.

Tôi đã một nửa quyết định đi tra cứu bảng, nhưng tôi muốn biết nếu có một số tùy chọn neater (không cần hàng trăm dòng mã chỉ để thực hiện toán học cơ bản).

EDIT:

Để xóa mọi thứ lên: Tôi cần phải chạy hàng trăm chức năng lần mỗi khung ở 35 khung hình mỗi giây.

+0

có thể trùng lặp của [Hàm lượng giác hoạt động như thế nào?] (Http://stackoverflow.com/questions/345085/how-do-trigonometric-functions-work) –

+0

Bản sao được đề xuất là nhiều hơn về cách các hàm lượng giác hoạt động (giống như Đó là về các hàm lượng giác ngược – Teepeemm

Trả lời

2

Bạn có cần một độ chính xác lớn cho arcsin(x) chức năng? Nếu không, bạn có thể tính toán arcsin trong N nút và giữ giá trị trong bộ nhớ. Tôi đề nghị sử dụng aproximation dòng. nếu x = A*x_(N) + (1-A)*x_(N+1) thì x = A*arcsin(x_(N)) + (1-A)*arcsin(x_(N+1)) trong đó arcsin(x_(N)) được biết.

+0

Vâng, đó là bảng tra cứu tôi đã nói về trong OP. không thấy lý do tại sao tôi sẽ tính toán rằng trong thời gian chạy, tôi sẽ simoly nướng các giá trị vào chương trình, do đó, việc tính toán asin thực tế sẽ chỉ là một nội suy giữa hai giá trị. –

2

bạn có thể muốn sử dụng xấp xỉ: sử dụng infinite series cho đến khi giải pháp đủ gần cho bạn.

ví dụ:
arcsin(z) = Sigma((2n!)/((2^2n)*(n!)^2)*((z^(2n+1))/(2n+1))) trong đó n trong [0, vô cực)

1

Có lẽ một số loại brute force thông minh như rapson newton.

Vì vậy, để giải quyết asin() bạn đi với gốc nhanh nhất trên tội lỗi()

+0

và bạn có thể chọn điểm bắt đầu từ một bảng tra cứu nhỏ để tăng tốc độ tính toán –

8

Trong điểm cố định e nvironment (S15.16) Tôi đã sử dụng thành công thuật toán CORDIC (xem Wikipedia để mô tả chung) để tính toán atan2 (y, x), sau đó bắt nguồn từ asin() và acos() từ đó sử dụng các định danh chức năng nổi tiếng liên quan đến hình vuông root:

asin(x) = atan2 (x, sqrt ((1.0 + x) * (1.0 - x))) 
acos(x) = atan2 (sqrt ((1.0 + x) * (1.0 - x)), x) 

Hóa ra việc tìm mô tả hữu ích về phép lặp CORDIC cho atan2() trên số double khó hơn tôi tưởng. Các trang web sau đây dường như có chứa một mô tả đầy đủ chi tiết, và cũng thảo luận về hai cách tiếp cận thay thế, xấp xỉ và tra cứu bảng đa thức:

http://ch.mathworks.com/examples/matlab-fixed-point-designer/615-calculate-fixed-point-arctangent

+0

Từ wikip edia, CORDIC thậm chí không sử dụng chức năng trig (gọn gàng!); Tôi tưởng tượng những gì bạn đã làm là một tìm kiếm; cho sin(), cos() có vẻ như Newton-Raphson hoặc một số như vậy sẽ tốt hơn? (Yêu cầu ít lần lặp hơn, mặc dù chi phí của các lần lặp lại sẽ khác nhau.) – petrelharp

+0

Lý do tôi đề nghị xem xét CORDIC là vì nó chỉ yêu cầu số học điểm cố định. Việc sử dụng phổ biến nhất của CORDIC có lẽ là để thực hiện sin/cos, đó là cách tôi lần đầu tiên học về nó (năm 1987).Nhưng một vài hàm khác có thể được tính bằng CORDIC, chẳng hạn như atan2. Vì tôi không có bất kỳ mã nào nằm xung quanh để tính toán atan2 với CORDIC, tôi đã cố gắng tìm một trang web có đủ chi tiết để ai đó có thể dựa vào việc triển khai nó. Liên kết tôi đăng ở trên là trang tốt nhất mà tôi có thể tìm thấy thông qua một công cụ tìm kiếm trong không gian vài phút. – njuffa

0

Sử dụng một xấp xỉ đa thức. Phù hợp với hình vuông nhỏ nhất là dễ nhất (Microsoft Excel có nó) và xấp xỉ Chebyshev là chính xác hơn.

Câu hỏi này đã được bảo hiểm trước đây: How do Trigonometric functions work?

1

Bạn có thể dễ dàng thêm mã sau vào điểm cố định. Nó sử dụng một rational approximation để tính toán arctangent chuẩn hóa cho khoảng [0 1) (bạn có thể nhân nó với Pi/2 để có được arctangent thực). Sau đó, bạn có thể sử dụng well known identities để có được vòng cung arcsin/arccos từ arctangent.

normalized_atan(x) ~ (b x + x^2)/(1 + 2 b x + x^2) 

where b = 0.596227 

Các lỗi tối đa là 0.1620º

#include <stdint.h> 
#include <math.h> 

// Approximates atan(x) normalized to the [-1,1] range 
// with a maximum error of 0.1620 degrees. 

float norm_atan(float x) 
{ 
    static const uint32_t sign_mask = 0x80000000; 
    static const float b = 0.596227f; 

    // Extract the sign bit 
    uint32_t ux_s = sign_mask & (uint32_t &)x; 

    // Calculate the arctangent in the first quadrant 
    float bx_a = ::fabs(b * x); 
    float num = bx_a + x * x; 
    float atan_1q = num/(1.f + bx_a + num); 

    // Restore the sign bit 
    uint32_t atan_2q = ux_s | (uint32_t &)atan_1q; 
    return (float &)atan_2q; 
} 

// Approximates atan2(y, x) normalized to the [0,4) range 
// with a maximum error of 0.1620 degrees 

float norm_atan2(float y, float x) 
{ 
    static const uint32_t sign_mask = 0x80000000; 
    static const float b = 0.596227f; 

    // Extract the sign bits 
    uint32_t ux_s = sign_mask & (uint32_t &)x; 
    uint32_t uy_s = sign_mask & (uint32_t &)y; 

    // Determine the quadrant offset 
    float q = (float)((~ux_s & uy_s) >> 29 | ux_s >> 30); 

    // Calculate the arctangent in the first quadrant 
    float bxy_a = ::fabs(b * x * y); 
    float num = bxy_a + y * y; 
    float atan_1q = num/(x * x + bxy_a + num); 

    // Translate it to the proper quadrant 
    uint32_t uatan_2q = (ux_s^uy_s) | (uint32_t &)atan_1q; 
    return q + (float &)uatan_2q; 
} 

Trong trường hợp bạn cần chính xác hơn, có một trật tự thứ 3 chức năng hợp lý:

normalized_atan(x) ~ (c x + x^2 + x^3)/(1 + (c + 1) x + (c + 1) x^2 + x^3) 

where c = (1 + sqrt(17))/8 

trong đó có một lỗi xấp xỉ tối đa 0,00811 º

1

Gửi câu trả lời của tôi ở đây other similar question.

nVidia có một số tài nguyên tuyệt vời, tôi đã sử dụng cho mục đích riêng, vài ví dụ của tôi: acosasinatan2 etc etc ...

Các thuật toán này tạo ra kết quả đủ chính xác. Dưới đây là một thẳng lên Python ví dụ với bản sao mã của họ dán vào:

import math 
def nVidia_acos(x): 
    negate = float(x<0) 
    x=abs(x) 
    ret = -0.0187293 
    ret = ret * x 
    ret = ret + 0.0742610 
    ret = ret * x 
    ret = ret - 0.2121144 
    ret = ret * x 
    ret = ret + 1.5707288 
    ret = ret * math.sqrt(1.0-x) 
    ret = ret - 2 * negate * ret 
    return negate * 3.14159265358979 + ret 

Và đây là kết quả để so sánh:

nVidia_acos(0.5) result: 1.0471513828611643 
math.acos(0.5) result: 1.0471975511965976 

Đó là khá chặt chẽ! Nhân với 57.29577951 để nhận kết quả theo độ, cũng từ công thức "độ" của chúng.

-1

Chỉ các hàm liên tục mới có thể xấp xỉ bằng đa thức. Và arcsin (x) bị gián đoạn tại điểm x = 1.same arccos (x) .Nhưng giảm phạm vi xuống khoảng 1, sqrt (1/2) trong trường hợp đó tránh tình trạng này. Chúng tôi có arcsin (x) = pi/2- arccos (x), arccos (x) = pi/2-arcsin (x) .bạn có thể sử dụng matlab cho minimax xấp xỉ. Chỉ có giá trị trong phạm vi [0, sqrt (1/2)] (nếu góc cho arcsin đó là yêu cầu lớn hơn sqrt (1/2) tìm hàm cos (x) .arctangent chỉ cho x < 1.arctan (x) = pi/2-arctan (1/x)

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