Làm thế nào nguy hiểm để so sánh các giá trị dấu phẩy động?


391

Tôi biết UIKitsử dụng CGFloatvì hệ thống tọa độ độc lập độ phân giải.

Nhưng mỗi khi tôi muốn kiểm tra xem ví dụ frame.origin.x0nó làm cho tôi cảm thấy bị bệnh:

if (theView.frame.origin.x == 0) {
    // do important operation
}

Không phải là CGFloatdễ bị dương tính giả khi so sánh với ==, <=, >=, <, >? Đó là một điểm nổi và họ có vấn đề không chính xác: 0.0000000000041ví dụ.

Objective-Cxử lý nội bộ này khi so sánh hoặc có thể xảy ra rằng một origin.xcái mà đọc là 0 không so sánh với 0là đúng?

Câu trả lời:


466

Trước hết, các giá trị dấu phẩy động không phải là "ngẫu nhiên" trong hành vi của chúng. So sánh chính xác có thể và có ý nghĩa trong nhiều công dụng trong thế giới thực. Nhưng nếu bạn sẽ sử dụng dấu phẩy động, bạn cần lưu ý về cách thức hoạt động của nó. Erring về phía giả định điểm nổi hoạt động như số thực sẽ giúp bạn mã nhanh chóng bị phá vỡ. Erring về phía giả định kết quả dấu phẩy động có fuzz ngẫu nhiên lớn liên quan đến chúng (giống như hầu hết các câu trả lời ở đây gợi ý) sẽ giúp bạn mã có vẻ hoạt động lúc đầu nhưng cuối cùng lại có lỗi lớn và trường hợp góc bị hỏng.

Trước hết, nếu bạn muốn lập trình với dấu phẩy động, bạn nên đọc phần này:

Những gì mọi nhà khoa học máy tính nên biết về số học dấu phẩy động

Vâng, đọc tất cả của nó. Nếu đó là một gánh nặng quá lớn, bạn nên sử dụng số nguyên / điểm cố định cho các tính toán của mình cho đến khi bạn có thời gian để đọc nó. :-)

Bây giờ, với những gì đã nói, các vấn đề lớn nhất với các so sánh điểm nổi chính xác được đưa ra:

  1. Thực tế là có rất nhiều giá trị bạn có thể viết trong nguồn hoặc đọc bằng scanfhoặc strtod, không tồn tại dưới dạng giá trị dấu phẩy động và được chuyển đổi âm thầm thành xấp xỉ gần nhất. Đây là những gì câu trả lời của dem9733 đã nói về.

  2. Thực tế là nhiều kết quả được làm tròn do không có đủ độ chính xác để thể hiện kết quả thực tế. Một ví dụ dễ dàng mà bạn có thể thấy điều này là thêm x = 0x1fffffey = 1dưới dạng nổi. Ở đây, xcó 24 bit độ chính xác trong lớp phủ (ok) và ychỉ có 1 bit, nhưng khi bạn thêm chúng, các bit của chúng không ở các vị trí chồng chéo và kết quả sẽ cần 25 bit chính xác. Thay vào đó, nó được làm tròn (đến 0x2000000trong chế độ làm tròn mặc định).

  3. Thực tế là nhiều kết quả được làm tròn do cần vô số vị trí cho giá trị chính xác. Điều này bao gồm cả hai kết quả hợp lý như 1/3 (mà bạn quen thuộc với số thập phân có vô số vị trí) nhưng cũng là 1/10 (cũng mất vô số vị trí trong nhị phân, vì 5 không phải là lũy thừa 2), cũng như các kết quả không hợp lý như căn bậc hai của bất cứ thứ gì không phải là một hình vuông hoàn hảo.

  4. Làm tròn đôi. Trên một số hệ thống (đặc biệt là x86), các biểu thức dấu phẩy động được đánh giá với độ chính xác cao hơn các loại danh nghĩa của chúng. Điều này có nghĩa là khi một trong các loại làm tròn ở trên xảy ra, bạn sẽ có hai bước làm tròn, đầu tiên là làm tròn kết quả cho loại có độ chính xác cao hơn, sau đó làm tròn đến loại cuối cùng. Ví dụ, hãy xem xét những gì xảy ra trong số thập phân nếu bạn làm tròn 1,49 đến một số nguyên (1), so với những gì xảy ra nếu bạn làm tròn số đó đến một vị trí thập phân (1,5) sau đó làm tròn kết quả đó thành một số nguyên (2). Đây thực sự là một trong những lĩnh vực khó xử lý nhất ở điểm nổi, vì hành vi của trình biên dịch (đặc biệt đối với các trình biên dịch lỗi, không tuân thủ như GCC) là không thể đoán trước.

  5. Chức năng siêu việt ( trig, exp, log, vv) không được chỉ định để có kết quả chính xác tròn; kết quả chỉ được xác định là chính xác trong một đơn vị ở vị trí chính xác cuối cùng (thường được gọi là 1ulp ).

Khi bạn đang viết mã dấu phẩy động, bạn cần ghi nhớ những gì bạn đang làm với các con số có thể khiến kết quả không chính xác và so sánh tương ứng. Thông thường, sẽ rất hợp lý khi so sánh với "epsilon", nhưng epsilon đó phải dựa trên độ lớn của các số bạn đang so sánh , không phải là hằng số tuyệt đối. (Trong trường hợp một epsilon không đổi tuyệt đối sẽ hoạt động, điều đó cho thấy mạnh mẽ rằng điểm cố định, không phải điểm nổi, là công cụ phù hợp cho công việc!)

Chỉnh sửa: Cụ thể, kiểm tra epsilon tương đối cường độ sẽ trông giống như:

if (fabs(x-y) < K * FLT_EPSILON * fabs(x+y))

Trong trường hợp FLT_EPSILONlà hằng số từ float.h(thay thế nó bằng DBL_EPSILONcho doubles hoặc LDBL_EPSILONcho long doubles) và Klà một hằng số mà bạn chọn như vậy mà các lỗi tích lũy của tính toán của bạn được chắc chắn bao quanh bởi Kcác đơn vị ở vị trí cuối cùng (và nếu bạn không chắc chắn bạn đã nhận lỗi tính toán ràng buộc đúng, làm cho Kmột vài lần lớn hơn những gì tính toán của bạn nói nó phải như vậy).

Cuối cùng, lưu ý rằng nếu bạn sử dụng điều này, một số chăm sóc đặc biệt có thể cần thiết gần bằng 0, vì FLT_EPSILONkhông có ý nghĩa đối với các biến dạng. Một sửa chữa nhanh chóng sẽ là làm cho nó:

if (fabs(x-y) < K * FLT_EPSILON * fabs(x+y) || fabs(x-y) < FLT_MIN)

và thay thế tương tự DBL_MINnếu sử dụng gấp đôi.


25
fabs(x+y)là vấn đề nếu xy(có thể) có dấu hiệu khác nhau. Tuy nhiên, một câu trả lời tốt chống lại làn sóng so sánh tôn giáo hàng hóa.
Daniel Fischer

27
Nếu xycó dấu hiệu khác nhau, nó không có vấn đề. Phía bên tay phải sẽ "quá nhỏ", nhưng vì xycó dấu hiệu khác nhau, dù sao họ cũng không nên so sánh bằng nhau. (Trừ khi chúng quá nhỏ đến mức không bình thường, nhưng sau đó trường hợp thứ hai bắt được nó)
R .. GitHub DỪNG GIÚP ICE

4
Tôi tò mò về tuyên bố của bạn: "đặc biệt đối với các trình biên dịch lỗi, không tuân thủ như GCC". Là GCC thực sự có lỗi và cũng không phù hợp?
Nicolás Ozimica

3
Vì câu hỏi được gắn thẻ iOS, nên đáng chú ý rằng các trình biên dịch của Apple (cả bản dựng gcc và gcc của Apple) đã luôn sử dụng FLT_EVAL_METHOD = 0 và cố gắng hoàn toàn nghiêm ngặt về việc không mang độ chính xác vượt mức. Nếu bạn tìm thấy bất kỳ vi phạm về điều đó, xin vui lòng gửi báo cáo lỗi.
Stephen Canon

17
"Trước hết, các giá trị dấu phẩy động không phải là" ngẫu nhiên "trong hành vi của chúng. So sánh chính xác có thể và có ý nghĩa trong nhiều cách sử dụng trong thế giới thực." - Chỉ hai câu và đã kiếm được +1! Đó là một trong những sai lầm đáng lo ngại nhất mà mọi người mắc phải khi làm việc với các điểm nổi.
Christian Rau

36

Vì 0 có thể biểu diễn chính xác dưới dạng số dấu phẩy động IEEE754 (hoặc sử dụng bất kỳ triển khai số fp nào khác mà tôi từng làm việc) nên so sánh với 0 có thể an toàn. Tuy nhiên, bạn có thể bị cắn, nếu chương trình của bạn tính một giá trị (chẳng hạn như theView.frame.origin.x) mà bạn có lý do để tin là 0 nhưng tính toán của bạn không thể đảm bảo là 0.

Để làm rõ một chút, một tính toán như:

areal = 0.0

sẽ (trừ khi ngôn ngữ hoặc hệ thống của bạn bị hỏng) tạo ra một giá trị sao cho (areal == 0.0) trả về giá trị đúng nhưng một tính toán khác như

areal = 1.386 - 2.1*(0.66)

có thể không.

Nếu bạn có thể tự đảm bảo rằng các tính toán của bạn tạo ra các giá trị bằng 0 (và không chỉ là chúng tạo ra các giá trị phải bằng 0) thì bạn có thể tiếp tục và so sánh các giá trị fp với 0. Nếu bạn không thể tự đảm bảo mình ở mức độ yêu cầu , tốt nhất tuân theo cách tiếp cận thông thường của "bình đẳng chịu đựng".

Trong trường hợp xấu nhất, việc so sánh các giá trị fp bất cẩn có thể cực kỳ nguy hiểm: nghĩ hệ thống điện tử, hướng dẫn vũ khí, vận hành nhà máy điện, điều hướng phương tiện, hầu như bất kỳ ứng dụng nào trong đó tính toán đáp ứng thế giới thực.

Đối với Angry Birds, không quá nguy hiểm.


11
Trên thực tế, 1.30 - 2*(0.65)là một ví dụ hoàn hảo về một biểu thức rõ ràng ước tính thành 0,0 nếu trình biên dịch của bạn thực hiện IEEE 754, bởi vì các nhân đôi được biểu thị 0.651.30có cùng một ý nghĩa, và nhân với hai là rõ ràng chính xác.
Pascal Cuoq

7
Vẫn nhận được đại diện từ cái này, vì vậy tôi đã thay đổi đoạn ví dụ thứ hai.
Dấu hiệu suất cao

22

Tôi muốn đưa ra một chút câu trả lời khác với những người khác. Chúng rất tuyệt để trả lời câu hỏi của bạn như đã nêu nhưng có lẽ không phải vì những gì bạn cần biết hoặc vấn đề thực sự của bạn là gì.

Điểm nổi trong đồ họa là tốt! Nhưng hầu như không cần phải so sánh phao trực tiếp. Tại sao bạn cần phải làm điều đó? Đồ họa sử dụng float để xác định khoảng thời gian. Và so sánh nếu một float nằm trong một khoảng cũng được xác định bởi các float luôn được xác định rõ và chỉ cần nhất quán, không chính xác hoặc chính xác! Miễn là một pixel (cũng là một khoảng!) Có thể được chỉ định đó là tất cả các nhu cầu đồ họa.

Vì vậy, nếu bạn muốn kiểm tra xem điểm của bạn có nằm ngoài phạm vi [0 .. Băng thông [thì điều này là tốt. Chỉ cần chắc chắn rằng bạn xác định bao gồm nhất quán. Ví dụ: luôn xác định bên trong là (x> = 0 && x <width). Điều tương tự cũng xảy ra đối với các bài kiểm tra giao nhau hoặc nhấn.

Tuy nhiên, nếu bạn đang lạm dụng tọa độ đồ họa như một loại cờ nào đó, ví dụ như để xem cửa sổ có được neo hay không, bạn không nên làm điều này. Thay vào đó, sử dụng cờ boolean tách biệt với lớp trình bày đồ họa.


13

So sánh với số 0 có thể là một hoạt động an toàn, miễn là số 0 không phải là giá trị được tính toán (như đã lưu ý trong câu trả lời ở trên). Lý do cho điều này là số 0 là một số hoàn toàn có thể biểu thị trong dấu phẩy động.

Nói các giá trị đại diện hoàn hảo, bạn có được 24 bit phạm vi trong một khái niệm sức mạnh hai (độ chính xác đơn). Vì vậy, 1, 2, 4 là hoàn toàn có thể đại diện, như, 5, 0,25 và 0,125. Miễn là tất cả các bit quan trọng của bạn là 24 bit, bạn là vàng. Vì vậy, 10.625 có thể được trả lại chính xác.

Điều này là tuyệt vời, nhưng sẽ nhanh chóng sụp đổ dưới áp lực. Hai kịch bản nảy ra trong đầu: 1) Khi tính toán được tham gia. Đừng tin rằng sqrt (3) * sqrt (3) == 3. Nó sẽ không như vậy. Và nó có thể sẽ không nằm trong một epsilon, như một số câu trả lời khác cho thấy. 2) Khi có bất kỳ quyền lực nào của 2 (NPOT). Vì vậy, nó có vẻ lạ, nhưng 0,1 là một chuỗi vô hạn trong nhị phân và do đó, bất kỳ phép tính nào liên quan đến một số như thế này sẽ không chính xác ngay từ đầu.

(Ồ và câu hỏi ban đầu được đề cập so sánh với không. Đừng quên rằng -0.0 cũng là một giá trị dấu phẩy động hoàn toàn hợp lệ.)


11

['Câu trả lời đúng' bóng bẩy khi chọn K. Việc chọn Kkết thúc cũng giống như quảng cáo như chọn VISIBLE_SHIFTnhưng việc chọn Kít rõ ràng hơn vì không giống như VISIBLE_SHIFTnó không có căn cứ trên bất kỳ thuộc tính hiển thị nào. Do đó chọn chất độc của bạn - chọn Khoặc chọn VISIBLE_SHIFT. Câu trả lời này ủng hộ việc lựa chọn VISIBLE_SHIFTvà sau đó thể hiện sự khó khăn trong việc lựa chọn K]

Chính xác là do lỗi tròn, bạn không nên sử dụng so sánh các giá trị 'chính xác' cho các hoạt động logic. Trong trường hợp cụ thể của bạn về một vị trí trên màn hình hiển thị, có thể không có vấn đề gì nếu vị trí đó là 0,0 hoặc 0,0000000003 - sự khác biệt là vô hình trước mắt. Vì vậy, logic của bạn nên là một cái gì đó như:

#define VISIBLE_SHIFT    0.0001        // for example
if (fabs(theView.frame.origin.x) < VISIBLE_SHIFT) { /* ... */ }

Tuy nhiên, cuối cùng, "vô hình trước mắt" sẽ phụ thuộc vào thuộc tính hiển thị của bạn. Nếu bạn có thể giới hạn trên màn hình (bạn sẽ có thể); sau đó chọn VISIBLE_SHIFTlà một phần của giới hạn trên.

Bây giờ, 'câu trả lời đúng' nằm trên Kvì vậy hãy khám phá chọn K. "Câu trả lời đúng" ở trên cho biết:

K là hằng số bạn chọn sao cho sai số tích lũy của các tính toán của bạn chắc chắn bị ràng buộc bởi các đơn vị K ở vị trí cuối cùng (và nếu bạn không chắc chắn mình đã tính đúng ràng buộc tính toán, hãy làm cho K lớn hơn vài lần so với tính toán của bạn nói rằng nó nên được)

Vì vậy, chúng tôi cần K. Nếu việc nhận Kđược khó khăn hơn, ít trực quan hơn so với việc chọn của tôi VISIBLE_SHIFTthì bạn sẽ quyết định những gì phù hợp với bạn. Để tìm thấy Kchúng tôi sẽ viết một chương trình thử nghiệm xem xét một loạt các Kgiá trị để chúng tôi có thể thấy nó hoạt động như thế nào. Rõ ràng là nên chọn cách nào K, nếu 'câu trả lời đúng' có thể sử dụng được. Không?

Chúng tôi sẽ sử dụng, như chi tiết 'câu trả lời đúng':

if (fabs(x-y) < K * DBL_EPSILON * fabs(x+y) || fabs(x-y) < DBL_MIN)

Hãy thử tất cả các giá trị của K:

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

void main (void)
{
  double x = 1e-13;
  double y = 0.0;

  double K = 1e22;
  int i = 0;

  for (; i < 32; i++, K = K/10.0)
    {
      printf ("K:%40.16lf -> ", K);

      if (fabs(x-y) < K * DBL_EPSILON * fabs(x+y) || fabs(x-y) < DBL_MIN)
        printf ("YES\n");
      else
        printf ("NO\n");
    }
}
ebg@ebg$ gcc -o test test.c
ebg@ebg$ ./test
K:10000000000000000000000.0000000000000000 -> YES
K: 1000000000000000000000.0000000000000000 -> YES
K:  100000000000000000000.0000000000000000 -> YES
K:   10000000000000000000.0000000000000000 -> YES
K:    1000000000000000000.0000000000000000 -> YES
K:     100000000000000000.0000000000000000 -> YES
K:      10000000000000000.0000000000000000 -> YES
K:       1000000000000000.0000000000000000 -> NO
K:        100000000000000.0000000000000000 -> NO
K:         10000000000000.0000000000000000 -> NO
K:          1000000000000.0000000000000000 -> NO
K:           100000000000.0000000000000000 -> NO
K:            10000000000.0000000000000000 -> NO
K:             1000000000.0000000000000000 -> NO
K:              100000000.0000000000000000 -> NO
K:               10000000.0000000000000000 -> NO
K:                1000000.0000000000000000 -> NO
K:                 100000.0000000000000000 -> NO
K:                  10000.0000000000000000 -> NO
K:                   1000.0000000000000000 -> NO
K:                    100.0000000000000000 -> NO
K:                     10.0000000000000000 -> NO
K:                      1.0000000000000000 -> NO
K:                      0.1000000000000000 -> NO
K:                      0.0100000000000000 -> NO
K:                      0.0010000000000000 -> NO
K:                      0.0001000000000000 -> NO
K:                      0.0000100000000000 -> NO
K:                      0.0000010000000000 -> NO
K:                      0.0000001000000000 -> NO
K:                      0.0000000100000000 -> NO
K:                      0.0000000010000000 -> NO

À, vậy K nên là 1e16 hoặc lớn hơn nếu tôi muốn 1e-13 là 'zero'.

Vì vậy, tôi muốn nói rằng bạn có hai lựa chọn:

  1. Thực hiện một tính toán epsilon đơn giản bằng cách sử dụng phán đoán kỹ thuật của bạn cho giá trị của 'epsilon', như tôi đã đề xuất. Nếu bạn đang làm đồ họa và 'zero' có nghĩa là 'thay đổi có thể nhìn thấy' hơn là kiểm tra tài sản hình ảnh của bạn (hình ảnh, v.v.) và đánh giá xem epsilon có thể là gì.
  2. Đừng thử bất kỳ tính toán dấu phẩy động nào cho đến khi bạn đọc tài liệu tham khảo câu trả lời không phải là hàng hóa (và nhận bằng tiến sĩ trong quá trình) và sau đó sử dụng phán đoán không trực quan của bạn để chọn K.

10
Một khía cạnh của tính độc lập với độ phân giải là bạn không thể biết chắc chắn "dịch chuyển hiển thị" là gì trong thời gian biên dịch. Những gì vô hình trên màn hình siêu HD rất có thể rõ ràng trên màn hình mông nhỏ. Ít nhất nên làm cho nó một chức năng của kích thước màn hình. Hoặc đặt tên cho cái gì đó khác.
Romain

1
Nhưng ít nhất, việc chọn shift dịch chuyển hiển thị 'dựa trên các thuộc tính hiển thị (hoặc khung) dễ hiểu - không giống như <câu trả lời đúng> Kkhó chọn và không trực quan để chọn.
GoZoner

5

Câu hỏi đúng: làm thế nào để so sánh các điểm trong Ca cao cảm ứng?

Câu trả lời đúng: CGPointEqualToPoint ().

Một câu hỏi khác nhau: Hai giá trị được tính có giống nhau không?

Câu trả lời được đăng ở đây: Họ không.

Làm thế nào để kiểm tra xem chúng có gần không? Nếu bạn muốn kiểm tra xem chúng có gần không, thì đừng sử dụng CGPointEqualToPoint (). Nhưng, đừng kiểm tra xem chúng có gần không. Làm điều gì đó có ý nghĩa trong thế giới thực, như kiểm tra xem liệu một điểm có nằm ngoài một đường thẳng hay nếu một điểm nằm trong một hình cầu.


4

Lần cuối cùng tôi kiểm tra tiêu chuẩn C, không có yêu cầu nào đối với các phép toán dấu phẩy động trên nhân đôi (tổng cộng 64 bit, mantissa 53 bit) phải chính xác hơn độ chính xác đó. Tuy nhiên, một số phần cứng có thể thực hiện các thao tác trong các thanh ghi có độ chính xác cao hơn và yêu cầu được hiểu là không có yêu cầu xóa các bit thứ tự thấp hơn (ngoài độ chính xác của các số được nạp vào các thanh ghi). Vì vậy, bạn có thể nhận được kết quả so sánh bất ngờ như thế này tùy thuộc vào những gì còn sót lại trong sổ đăng ký từ bất cứ ai ngủ ở đó cuối cùng.

Điều đó nói rằng, và mặc dù tôi đã nỗ lực để loại bỏ nó bất cứ khi nào tôi nhìn thấy nó, trang phục nơi tôi làm việc có rất nhiều mã C được biên dịch bằng gcc và chạy trên linux, và chúng tôi đã không nhận thấy bất kỳ kết quả bất ngờ nào trong một thời gian dài . Tôi không biết liệu điều này có phải là do gcc đang xóa các bit thứ tự thấp cho chúng tôi không, các thanh ghi 80 bit không được sử dụng cho các hoạt động này trên các máy tính hiện đại, tiêu chuẩn đã được thay đổi hoặc là gì. Tôi muốn biết nếu có ai có thể trích dẫn chương và câu thơ.


1

Bạn có thể sử dụng mã như vậy để so sánh float với zero:

if ((int)(theView.frame.origin.x * 100) == 0) {
    // do important operation
}

Điều này sẽ so sánh với độ chính xác 0,1, đủ cho CGFloat trong trường hợp này.


Truyền tới intmà không có bảo hiểm theView.frame.origin.xnằm trong / gần phạm vi intdẫn đến hành vi không xác định (UB) - hoặc trong trường hợp này, 1/100 phạm vi của int.
chux - Phục hồi lại

Hoàn toàn không có lý do để chuyển đổi sang số nguyên như thế này. Như chux đã nói, có tiềm năng cho UB từ các giá trị ngoài phạm vi; và trên một số kiến ​​trúc, điều này sẽ chậm hơn đáng kể so với việc chỉ tính toán trong dấu phẩy động. Cuối cùng, nhân với 100 như thế sẽ so sánh với độ chính xác 0,01 chứ không phải 0,1.
Sneftel

0
-(BOOL)isFloatEqual:(CGFloat)firstValue secondValue:(CGFloat)secondValue{

BOOL isEqual = NO;

NSNumber *firstValueNumber = [NSNumber numberWithDouble:firstValue];
NSNumber *secondValueNumber = [NSNumber numberWithDouble:secondValue];

isEqual = [firstValueNumber isEqualToNumber:secondValueNumber];

return isEqual;

}


0

Tôi đang sử dụng chức năng so sánh sau để so sánh một số vị trí thập phân:

bool compare(const double value1, const double value2, const int precision)
{
    int64_t magnitude = static_cast<int64_t>(std::pow(10, precision));
    int64_t intValue1 = static_cast<int64_t>(value1 * magnitude);
    int64_t intValue2 = static_cast<int64_t>(value2 * magnitude);
    return intValue1 == intValue2;
}

// Compare 9 decimal places:
if (compare(theView.frame.origin.x, 0, 9)) {
    // do important operation
}

-6

Tôi muốn nói điều đúng là khai báo mỗi số là một đối tượng và sau đó xác định ba điều trong đối tượng đó: 1) một toán tử đẳng thức. 2) một phương thức setAcceptableDifference. 3) giá trị của chính nó. Toán tử đẳng thức trả về true nếu chênh lệch tuyệt đối của hai giá trị nhỏ hơn giá trị được đặt là chấp nhận được.

Bạn có thể phân lớp đối tượng cho phù hợp với vấn đề. Ví dụ, các thanh kim loại tròn trong khoảng từ 1 đến 2 inch có thể được coi là có đường kính bằng nhau nếu đường kính của chúng khác nhau dưới 0,0001 inch. Vì vậy, bạn gọi setAcceptableDifference với tham số 0,0001, sau đó sử dụng toán tử đẳng thức một cách tự tin.


1
Đây không phải là một câu trả lời tốt. Đầu tiên, toàn bộ "đối tượng" không làm gì để giải quyết vấn đề của bạn. Và thứ hai, trên thực tế, việc thực hiện "bình đẳng" của bạn không thực sự đúng.
Tom Swirly

3
Tom, có lẽ bạn sẽ nghĩ lại về "đối tượng". Với các số thực, được biểu thị với độ chính xác cao, sự bình đẳng hiếm khi xảy ra. Nhưng ý tưởng về sự bình đẳng của một người có thể được điều chỉnh nếu nó phù hợp với bạn. Sẽ tốt hơn nếu có một toán tử "xấp xỉ bằng nhau", nhưng không có.
John White
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.