Kiểm tra sự bằng nhau của hai số float: Ví dụ thực tế


8

Khi nào nó thường có ý nghĩa trong lập trình để kiểm tra sự bằng nhau của hai số dấu phẩy động?

I E

a == b 

trong đó cả a & b là phao.

Ấn tượng ngây thơ của tôi là người ta sẽ luôn kiểm tra sự khác biệt so với một số epsilon khoan dung.

Tôi có lầm không? Có thể kiểm tra sự bình đẳng của phao có ý nghĩa trong các bối cảnh nhất định?

Bất kỳ ví dụ từ tự nhiên? tức là từ các cơ sở mã thực tế hoặc các ứng dụng hiện có trên git, v.v.

Tái bút Tôi mặc nhiên cho rằng sử dụng toán tử đẳng thức trên phao thực sự có ý nghĩa trong một số bối cảnh; mặt khác tại sao hầu hết các ngôn ngữ lập trình sẽ cho phép nó.


1
Vì đây là về các vấn đề thực tế với các thuật toán số, tôi đang chuyển sang Khoa học tính toán .

Có thể giúp biết vấn đề nào bạn đang cố gắng giải quyết bằng cách đặt câu hỏi cụ thể này? meta.stackexchange.com/q/66377
Kirill

1
@Krill Vấn đề là sự tò mò. Tôi đã biết lời khuyên khi KHÔNG nên sử dụng nó. Nhưng nếu toán tử vẫn được phép thì phải có trường hợp thực sự đúng khi sử dụng nó. Nhưng những trường hợp ue không rõ ràng. Vì vậy, tôi muốn biết. Và các câu trả lời đưa ra một số ví dụ tốt.
tò mò_cat

Câu trả lời:


5

Ấn tượng ngây thơ của tôi là người ta sẽ luôn kiểm tra sự khác biệt so với một số epsilon khoan dung.

Việc triển khai ý tưởng không ngây thơ này có lẽ nên tận dụng toán tử so sánh đẳng thức để xử lý các trường hợp đặc biệt quan trọng mà tiêu chuẩn IEEE 754 dự tính (số nguyên, số không chuẩn hóa ...).

Hãy xem làm thế nào tôi nên làm so sánh dấu phẩy động? :

...

if (a == b)  // shortcut, handles infinities
  return true;

if (a == 0 || b == 0 || diff < Float.MIN_NORMAL) {
  // a or b is zero or both are extremely close to it
  // relative error is less meaningful here

...


Đôi khi thực sự có một câu trả lời đúng và bạn muốn có sự bình đẳng chính xác. Kiểm tra tính đúng đắn của việc triển khai là một ví dụ điển hình (ví dụ: Chỉ có bốn tỷ tỷ nổi vì vậy hãy kiểm tra tất cả! ).


Không phải phép thử cho a == 0 bên trong mệnh đề OR được dự phòng bởi diff <Float.MIN_NORMAL?
tò mò_cat

3

Một ví dụ rõ ràng ==là ok, là khi ablà cùng một số a=c; b=c, ví dụ, để kiểm tra xem abcó được khởi tạo theo cùng một cách không. Tất nhiên, |a-b| < epsiloncũng sẽ làm việc ở đây. Vấn đề duy nhất là, nhỏ như thế nào epsilon?

Ngoài ra, a == bsẽ biên dịch thành một hướng dẫn trong khi |a-b| < epsilonsẽ mất khá nhiều.


Cảm ơn! Khi nào một người, trong một tình huống mã hóa điển hình, muốn biết liệu a và b có được khởi tạo theo cùng một cách không? Bạn có thể đăng bất kỳ đoạn mã nào bằng cách này không? Ý tôi là không thể chỉ kiểm tra nguồn & nói?
tò mò_cat

1
@cpered_cat giả sử bạn đang tạo một trò chơi như minecraft, với một lưới các ô, giả sử các ô này có tọa độ nổi, vì bất kỳ lý do gì, và chúng được khởi tạo trong một vòng lặp rõ ràng như thế nào for x in [0..n] step w: for y in [0..n] step w: add_tile(x, y). Trong trường hợp đó t1.x == t2.xlà một cách hoàn toàn an toàn để kiểm tra nếu hai gạch nằm trong một mặt phẳng. Bạn chỉ cần |a-b|<epsilonkhi ablà kết quả của các tính toán khác nhau được cho là có cùng giá trị. Nhưng rất thường xuyên bạn có kết quả của một tính toán được lưu trữ trong hai biến hoặc ghi đè lên các biến bằng hằng.
Karolis Juodelė

Ví dụ rất hay! Cảm ơn. Hãy làm cho nó thêm ý nghĩa hơn. Trường hợp sử dụng âm thanh thực sự đầu tiên tôi đã thực sự! Bạn nên thêm nó vào câu trả lời của bạn!
tò mò_cat

2

Một ví dụ cực đoan: IBM là công ty đầu tiên xây dựng bộ xử lý với hướng dẫn nhân thêm hợp nhất. Sử dụng hướng dẫn đó, họ đã tạo ra một phương pháp rất nhanh để tính căn bậc hai theo tiêu chuẩn IEEE-754. Phương pháp này không thành công cho một giá trị đầu vào duy nhất 1 ≤ x <4: Nếu x là số lớn nhất có thể biểu thị dưới dạng số dấu phẩy động nhỏ hơn 4, thì kết quả sẽ được làm tròn không chính xác.

Vì vậy, ở đâu đó trong quá trình thực hiện, họ kiểm tra xem x có bằng một giá trị cụ thể đó không. Họ muốn nhận ra giá trị đó, và không phải bất kỳ ai khác.


Cảm ơn! Giá trị đó là gì, ý tưởng nào? Tôi không thể tìm thấy bất kỳ tài liệu tham khảo để đọc về điều này. Bạn có thể gửi bất kỳ liên kết?
tò mò_cat

2

Ấn tượng ngây thơ của tôi là người ta sẽ luôn kiểm tra sự khác biệt so với một số epsilon khoan dung. Tôi có lầm không? Có thể kiểm tra sự bình đẳng của phao có ý nghĩa trong các bối cảnh nhất định?

Không có một công thức nấu ăn độc đáo. Trong bài viết này có một điều trị toàn diện, nơi bạn có thể tìm thấy một câu trả lời hoàn chỉnh với kỹ thuật và mã.

Tóm lại, chủ yếu có 3 trường hợp:

  • so sánh với không
  • so sánh với số không
  • so sánh hai số tùy ý

Ý tưởng của bạn để sử dụng so sánh với dung sai là tốt cho một số trường hợp, nhưng cũng có một kỹ thuật dựa trên Đơn vị ở vị trí cuối cùng ( ULP ), được mô tả trong bài viết

Tôi mặc nhiên cho rằng sử dụng toán tử đẳng thức trên phao thực sự có ý nghĩa trong một số bối cảnh; mặt khác tại sao hầu hết các ngôn ngữ lập trình sẽ cho phép nó.

Như trên, có những tình huống bạn có thể sử dụng nó, nhưng được cảnh báo. Ví dụ, trình biên dịch gcc có cảnh báo:

warning: comparing floating point with == or != is unsafe

Cập nhật

Tôi thêm một số cân nhắc ở trên lập luận này, họ cũng không liên quan chặt chẽ đến vụ án a == b.

Bình đẳng với biểu thức

Xem xét trường hợp:

a + b == c 

a b c

mộtb==cftôi(ftôi(một)+ftôi(b))==ftôi(c)
  • ftôi(x)x

|mộtmột+b|errmột+|bmột+b|errb
errx= =|x-ftôi(x)||x|

Vì vậy, trong trường hợp này có sử dụng ==là tinh tế hơn.

Chuyển trong các môi trường khác nhau

Khi chúng tôi chuyển mã trong các môi trường khác nhau (máy khác nhau), chúng tôi có thể nhận được một số kết quả khác nhau (ví dụ: thử suy nghĩ để kiểm tra đơn vị). Ngoài ra trong trường hợp sử dụng ==là tinh tế.


Ah! Vì vậy, nó tạo ra một cảnh báo. Cảm ơn. Vì vậy, ấn tượng của tôi bây giờ là trong 99% trường hợp mã hóa, so sánh đẳng thức float là một lỗi nhưng nó vẫn được phép đối với những trường hợp rất ít trong đó có thể có ý nghĩa.
tò mò_cat

1
@cantly_cat Vâng, tôi đồng ý với bạn. Tôi thêm một số lưu ý.
Mauro Vanzetto

0

"Ấn tượng ngây thơ" của bạn không phải là "ấn tượng ngây thơ" - đó là kết quả của việc đọc về số học dấu phẩy động và chỉ hiểu được một nửa. "Ấn tượng ngây thơ" sẽ là ấn tượng rõ ràng rằng để tìm hiểu xem a và b có bằng nhau không, bạn hỏi xem chúng có bằng nhau không.

Có rất nhiều tình huống mà tất cả những gì bạn cần biết là liệu hai số dấu phẩy động có bằng nhau hay không. Có rất nhiều tình huống mà bạn biết rằng không có lỗi làm tròn hoặc không có biến thể do lỗi làm tròn. Giống như chuyển đổi số thập phân thành dấu phẩy động, điều này sẽ mang tính quyết định trong bất kỳ triển khai lành mạnh nào.

Đây là một điểm tốt: Ai đó đã tuyên bố rằng với bất kỳ hai số dấu phẩy động a, b, kết quả của (b + a + b) và (b + b + a) là như nhau và bạn muốn kiểm tra xác nhận đó. Hãy thử làm điều đó mà không so sánh hai số dấu phẩy động cho đẳng thức.

Đây là một cách tốt hơn: Cố gắng tạo một tập hợp các số dấu phẩy động.


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.