2012-03-23 33 views
5

Khi so sánh gấp đôi cho sự bình đẳng, chúng ta cần đưa ra một mức độ khoan dung, vì tính toán dấu phẩy động có thể đưa ra lỗi. Ví dụ:So sánh dấu chấm động của phép gán liên tục

double x; 
double y; 
x = f(); 
y = g(); 

if (fabs(x-y)<epsilon) { 
    // they are equal! 
} else { 
    // they are not! 
} 

Tuy nhiên, nếu tôi chỉ đơn giản gán một giá trị không đổi, mà không cần bất kỳ tính toán, tôi vẫn cần phải kiểm tra epsilon?

double x = 1; 
double y = 1; 

if (x==y) { 
    // they are equal! 
} else { 
    // no they are not! 
} 

Có phải là == so sánh đủ tốt không? Hoặc tôi cần phải làm lại fabs(x-y)<epsilon? Có thể giới thiệu lỗi khi chỉ định không? Tôi có quá hoang tưởng không?

Làm thế nào về đúc (double x = static_cast<double>(100))? Có phải đó sẽ giới thiệu lỗi dấu phẩy động không?

Tôi đang sử dụng C++ trên Linux, nhưng nếu nó khác ngôn ngữ, tôi cũng muốn hiểu điều đó.

+0

Cho dù bạn cần một epsilon phụ thuộc vào tình hình. Ví dụ. khi bạn cần một phương trình chuyển đổi ('a == b && b == c' ngụ ý' a == c'), thì bạn không thể sử dụng epsilon. BTW, 'double x = 1' đã có nghĩa là' double x = 1' có nghĩa là 'double x = static_cast (1)' – MSalters

Trả lời

3

Trên thực tế, nó phụ thuộc vào giá trị và thực hiện. Chuẩn C++ (dự thảo n3126) đã này nói trong 2.14.4 Floating literals:

Nếu giá trị thu nhỏ nằm trong khoảng giá trị biểu diễn cho loại hình của nó, kết quả là giá trị thu nhỏ lại nếu biểu diễn, khác biểu diễn lớn hơn hoặc nhỏ hơn giá trị gần nhất với giá trị được chia tỷ lệ, được chọn theo cách thức được triển khai.

Nói cách khác, nếu giá trị là chính xác biểu diễn (và 1, trong IEEE754, như là 100 trong dàn diễn viên tĩnh của bạn), bạn sẽ có được giá trị. Nếu không (chẳng hạn như với 0.1), bạn sẽ nhận được kết quả phù hợp do thực hiện xác định (a). Bây giờ tôi sẽ rất lo lắng về việc triển khai đã chọn một kết quả phù hợp khác nhau dựa trên cùng một mã thông báo nhập nhưng nó có thể là .


(a) Trên thực tế, đoạn có thể được đọc theo hai cách, hoặc là thực hiện là tự do lựa chọn một trong hai giá trị cận dưới cao hơn hoặc gần nhất bất kể trong số đó là thực sự là gần nhất, hoặc nó phải chọn gần nhất với giá trị mong muốn.

Nếu sau này, nó không thay đổi câu trả lời này vì tất cả những gì bạn phải làm là hardcode một giá trị dấu phẩy động chính xác ở giữa hai loại có thể biểu diễn và thực hiện lại một lần nữa. Ví dụ:

Ví dụ: nó có thể thay thế giữa mức cao hơn tiếp theo cao hơn và thấp hơn cho cùng một lý do làm tròn của ngân hàng được áp dụng - để giảm các lỗi tích lũy.

+0

Một số hiện thực dường như đánh giá 'float' literals bằng cách tìm giá trị' double' gần nhất với 'float', và sau đó làm tròn 'float'. Điều này đôi khi có thể gây ra 'float' literals có giá trị thực tế hơi cao hơn hoặc thấp hơn một' double' chính xác giữa hai giá trị 'float' liền kề được gán một giá trị không phải là gần nhất. – supercat

0

Không nếu bạn gán literals họ nên được như vậy :)

Ngoài ra nếu bạn bắt đầu với cùng một giá trị và thực hiện thao tác tương tự, họ nên được như vậy.

Floating giá trị điểm đều là phòng không chính xác, nhưng các hoạt động nên tạo ra kết quả phù hợp :)

0

Cả hai trường hợp cuối cùng đều phải tuân theo các biểu diễn được xác định thực hiện.

Lưu trữ các giá trị dấu phẩy động và biểu diễn của chúng có thể có dạng - tải theo địa chỉ hoặc hằng số? tối ưu hóa bằng toán nhanh? chiều rộng đăng ký là bao nhiêu? là nó được lưu trữ trong một thanh ghi SSE? Nhiều biến thể tồn tại.

Nếu bạn cần hành vi và tính di động chính xác, không dựa vào hành vi được xác định thực hiện này.

0

IEEE-754, là một triển khai phổ biến tiêu chuẩn của các số dấu chấm động tuân theo, yêu cầu các hoạt động điểm động để tạo ra kết quả là giá trị thể hiện gần nhất với kết quả vô cùng chính xác. Vì vậy, sự không chính xác duy nhất mà bạn sẽ phải đối mặt là làm tròn sau mỗi thao tác bạn thực hiện, cũng như việc truyền các lỗi làm tròn từ các hoạt động được thực hiện trước đó trong chuỗi. Floats không phải là mỗi se không chính xác. Và bằng cách này, epsilon có thể và nên được tính toán, bạn có thể tham khảo bất kỳ cuốn sách số về điều đó.

Số dấu chấm động có thể đại diện cho các số nguyên chính xác đến độ dài của phần định trị của chúng. Vì vậy, ví dụ nếu bạn cast từ một int đến một double, nó sẽ luôn luôn là chính xác, nhưng để đúc thành một float, nó sẽ không còn chính xác cho các số nguyên rất lớn.

Có một ví dụ chính về việc sử dụng rộng rãi các số dấu phẩy động để thay thế cho số nguyên, đó là ngôn ngữ kịch bản LUA, không có kiểu số nguyên và số dấu phẩy động được sử dụng rộng rãi cho điều khiển luồng và logic v.v. Việc thực hiện và lưu trữ hình phạt từ việc sử dụng các số dấu phẩy động chỉ nhỏ hơn hình phạt của việc giải quyết nhiều loại tại thời gian chạy và làm cho việc triển khai thực hiện nhẹ hơn. LUA đã được sử dụng rộng rãi không chỉ trên PC, mà còn trên các bảng điều khiển trò chơi.

Hiện tại, nhiều trình biên dịch có một công tắc tùy chọn vô hiệu hóa tính tương thích IEEE-754. Sau đó thỏa hiệp được thực hiện. Các số không chuẩn hóa (các số rất nhỏ trong đó số mũ đã đạt đến giá trị nhỏ nhất có thể) thường được coi là số không, và xấp xỉ khi thực hiện công suất, logarit, sqrt và 1/(x^2) có thể được thực hiện, nhưng cộng/trừ, so sánh và phép nhân nên giữ lại các thuộc tính của chúng cho các số có thể được biểu diễn chính xác.

0

Câu trả lời dễ dàng: Đối với hằng số == là ok. Có hai trường hợp ngoại lệ mà bạn cần phải nhận thức:

Đầu tiên ngoại lệ:

0.0 == -0,0

Có một số không âm mà so sánh bình đẳng cho các tiêu chuẩn IEEE 754. Điều này có nghĩa 1/INFINITY == 1/vô cực mà phá vỡ f (x) == f (y) => x == y

Thứ hai ngoại lệ:

NaN = NaN

này là một cảnh báo đặc biệt của NotaNumber cho phép tìm hiểu xem một số có phải là NaN trên các hệ thống không có chức năng thử nghiệm không (Có, điều đó xảy ra).

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