2011-07-31 26 views
6

Giả sử rằng PI/2 không bao giờ được biểu diễn chính xác trong điểm trôi nổi, có an toàn khi giả định rằng cos (a) không bao giờ có thể trả về chính xác không?Có thể cos (a) bằng 0 ở điểm động

Nếu đây là trường hợp, sau đó các pseudo-code sau sẽ chẳng được vào khối (và nó có thể được gỡ bỏ một cách an toàn):

... 
y = h/cos(a); 
if (!isfinite(a)) 
{ 
    // handle infinite y 
} 
+0

Đôi khi hệ thống có thể buộc nó không khi 'a' là aprox. bằng 'pi/2'. – ja72

Trả lời

4

Zero là một trong nhiều giá trị có thể được biểu diễn chính xác. Nhiều hệ thống có một bảng tra cứu các giá trị chung của sin và cos, vì vậy không thể tưởng tượng được rằng chính xác số không có thể được trả về.

Nhưng bạn an toàn hơn bằng cách sử dụng đồng bằng so sánh, trước khi thực hiện việc phân chia:

if (Abs(cos(a)) < 0.0000001) 
{ 

} 
+2

Một trong số "một số"? Tôi không nghĩ rằng tôi sẽ sử dụng thuật ngữ "vài" cho (2^64 - 2^53). –

+0

1/2, 1/4, 1/8, ..... –

+1

Mỗi giá trị dấu chấm động hữu hạn có thể được biểu diễn chính xác trong dấu phẩy động (gây sốc, tôi biết). Không chỉ 1/2, 1/4, mà còn là 0.333333333333333314829616256247390992939472198486328125 và 3.141592653589790007373494518105871975421905517578125. –

0

không, điều này không thể được đảm bảo, vì cos là chính nó tính với một lỗi, do đó, giá trị của nó có thể là một số không chính xác khá dễ dàng.

7

khác hơn không, giá trị chính xác gấp đôi mà đến gần nhất với một bội chính xác của π/2 là 6381956970095103 * 2^797 , tương đương với:

(an odd integer) * π/2 + 2.983942503748063...e−19 

Như vậy, đối với tất cả các giá trị tăng gấp đôi độ chính xác x, chúng tôi có các ràng buộc:

|cos(x)| >= cos(2.983942503748063...e−19) 

Lưu ý rằng đây là một ràng buộc về giá trị chính xác toán học, không phải trên giá trị trả về bởi hàm thư viện cos. Trên một nền tảng với một thư viện toán học chất lượng tốt, ràng buộc này là đủ tốt mà chúng ta có thể nói rằng cos(x) không phải là số không cho bất kỳ chính xác đôi x. Trong thực tế, nó chỉ ra rằng điều này không phải là duy nhất để tăng gấp đôi; thuộc tính này giữ cho tất cả các loại cơ bản IEEE-754, nếu cos được làm tròn thành thật.

Tuy nhiên, đó không phải là để nói rằng điều này không bao giờ có thể xảy ra trên một nền tảng đã thực hiện một cách ngoạn mục nghèo giảm đối số lượng giác.

Thậm chí quan trọng hơn, đó là quan trọng cần lưu ý rằng trong ví dụ của bạn y có thể vô hạn mà khôngcos(a) là zero:

#include <math.h> 
#include <stdio.h> 

int main(int argc, char *argv[]) { 
    double a = 0x1.6ac5b262ca1ffp+849; 
    double h = 0x1.0p1022; 
    printf("cos(a) = %g\n", cos(a)); 
    printf("h/cos(a) = %g\n", h/cos(a)); 
    return 0; 
} 

biên dịch và chạy:

scanon$ clang example.c && ./a.out 
cos(a) = -4.68717e-19 
h/cos(a) = -inf 
+0

Tôi đã có thể thích trả lời chính xác điều này, và bên cạnh nó cung cấp cho manh mối lý do tại sao một sự khoan dung như 0.0000001 âm thanh hoàn toàn tùy ý, nó thậm chí sẽ không ngăn chặn một tràn. Bảo vệ tràn phải giống như (abs (cos (x)) <1);) –

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