Hướng dẫn can we use == to compare two float values in python? - chúng ta có thể sử dụng == để so sánh hai giá trị float trong python không?

Số điểm nổi là một cách nhanh chóng và hiệu quả để lưu trữ và làm việc với các số, nhưng chúng đi kèm với một loạt các cạm bẫy chắc chắn đã khiến nhiều lập trình viên non trẻ phải trải qua-có lẽ một số lập trình viên có kinh nghiệm cũng vậy! Ví dụ kinh điển chứng minh những cạm bẫy của phao diễn ra như thế này:

>>> 0.1 + 0.2 == 0.3
False

Nhìn thấy điều này lần đầu tiên có thể mất phương hướng. Nhưng đừng ném máy tính của bạn vào thùng rác. Hành vi này là chính xác!

Bài viết này sẽ cho bạn thấy lý do tại sao các lỗi điểm nổi như ở trên là phổ biến, tại sao chúng có ý nghĩa và những gì bạn có thể làm để đối phó với chúng trong Python.

Máy tính của bạn là một kẻ nói dối (loại)

Bạn đã thấy rằng

>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
0 không bằng
>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
1 nhưng sự điên rồ không dừng lại ở đó. Dưới đây là một số ví dụ gây nhiễu hơn:

>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False

Vấn đề cũng không bị hạn chế trong so sánh bình đẳng,:

>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True

Vì vậy những gì đang xảy ra? Máy tính của bạn có nói dối bạn không? Nó chắc chắn trông giống như nó, nhưng có nhiều thứ đang diễn ra bên dưới bề mặt.

Khi bạn nhập số

>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
2 vào trình thông dịch Python, nó sẽ được lưu trữ trong bộ nhớ dưới dạng số điểm nổi. Có một chuyển đổi diễn ra khi điều này xảy ra.
>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
2 là số thập phân trong cơ sở 10, nhưng số điểm nổi được lưu trữ trong nhị phân. Nói cách khác,
>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
2 được chuyển đổi từ cơ sở 10 thành cơ sở 2.

Số nhị phân kết quả có thể không đại diện chính xác số cơ sở ban đầu 10.

>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
2 là một ví dụ. Biểu diễn nhị phân là \ (0,0 \ Overline {0011} \). Nghĩa là,
>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
2 là một số thập phân lặp lại vô hạn khi được viết bằng cơ sở 2. Điều tương tự xảy ra khi bạn viết phân số ⅓ như một số thập phân trong cơ sở 10. bạn kết thúc với số thập phân lặp lại vô hạn \ (0. \ Overline {33} \ ).

Bộ nhớ máy tính là hữu hạn, do đó, biểu diễn phân số nhị phân lặp lại vô hạn của

>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
2 được làm tròn thành một phần hữu hạn. Giá trị của số này phụ thuộc vào kiến ​​trúc của máy tính của bạn (32 bit so với 64 bit). Một cách để xem giá trị điểm nổi được lưu trữ cho
>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
2 là sử dụng phương thức
>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
9 cho phao để lấy tử số và mẫu số của biểu diễn điểm nổi:

>>> numerator, denominator = (0.1).as_integer_ratio()
>>> f"0.1 ≈ {numerator} / {denominator}"
'0.1 ≈ 3602879701896397 / 36028797018963968'

Bây giờ sử dụng

>>> numerator, denominator = (0.1).as_integer_ratio()
>>> f"0.1 ≈ {numerator} / {denominator}"
'0.1 ≈ 3602879701896397 / 36028797018963968'
0 để hiển thị phân số chính xác đến 55 số thập phân:

>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'

Vì vậy,

>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
2 được làm tròn đến một số lớn hơn một chút so với giá trị thực của nó.

Lỗi này, được gọi là lỗi biểu diễn điểm nổi, xảy ra thường xuyên hơn bạn có thể nhận ra.floating-point representation error, happens way more often than you might realize.

Muốn nhiều hơn như thế này?

Một email, mỗi thứ bảy, với một mẹo hành động. Luôn luôn dưới 5 phút thời gian của bạn.
Always less than 5 minutes of your time.

Lỗi đại diện thực sự phổ biến

Có ba lý do mà một số được làm tròn khi được biểu diễn dưới dạng số điểm nổi:

  1. Số lượng có nhiều chữ số quan trọng hơn các điểm nổi cho phép.
  2. Số lượng là phi lý.
  3. Số lượng là hợp lý nhưng có biểu diễn nhị phân không kết thúc.

Số điểm nổi 64 bit là tốt cho khoảng 16 hoặc 17 chữ số quan trọng. Bất kỳ số có chữ số quan trọng hơn được làm tròn. Các số phi lý, như π và E, không thể được biểu diễn bằng bất kỳ phân số chấm dứt nào trong bất kỳ cơ sở số nguyên nào. Vì vậy, một lần nữa, không có vấn đề gì, những con số phi lý sẽ được làm tròn khi được lưu trữ dưới dạng phao.

Hai tình huống này tạo ra một bộ số vô hạn không thể được biểu diễn chính xác dưới dạng số điểm nổi. Nhưng trừ khi bạn là một nhà hóa học đối phó với những con số nhỏ, hoặc một nhà vật lý liên quan đến số lượng lớn về mặt thiên văn, bạn không có khả năng gặp phải những vấn đề này.

Thế còn việc không kết thúc số hợp lý, như

>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
2 trong cơ sở 2? Đây là nơi bạn sẽ gặp phải hầu hết các tai ương dấu nổi của mình và nhờ vào toán học xác định liệu một phân số có chấm dứt hay không, bạn sẽ chống lại lỗi đại diện thường xuyên hơn bạn nghĩ.

Trong cơ sở 10, một phân số chấm dứt nếu mẫu số của nó là một sản phẩm có sức mạnh của các yếu tố chính là 10. Hai yếu tố chính của 10 là 2 và 5, do đó các phân số như ½, ¼, ⅕, và ⅒ tất cả chấm dứt, nhưng ⅓ , ⅐, và không. Tuy nhiên, trong cơ sở 2, chỉ có một yếu tố chính: 2. Vì vậy, chỉ có các phân số có mẫu số là sức mạnh của 2 chấm dứt. Kết quả là, các phân số như ⅓, ⅕, ⅙, ⅐, và ⅒ đều không kết thúc khi được biểu thị bằng nhị phân.terminates if its denominator is a product of powers of prime factors of 10. The two prime factors of 10 are 2 and 5, so fractions like ½, ¼, ⅕, ⅛, and ⅒ all terminate, but ⅓, ⅐, and ⅑ do not. In base 2, however, there is only one prime factor: 2. So only fractions whose denominator is a power of 2 terminate. As a result, fractions like ⅓, ⅕, ⅙, ⅐, ⅑, and ⅒ are all non-terminating when expressed in binary.

Bây giờ bạn có thể hiểu ví dụ ban đầu trong bài viết này.

>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
2,
>>> numerator, denominator = (0.1).as_integer_ratio()
>>> f"0.1 ≈ {numerator} / {denominator}"
'0.1 ≈ 3602879701896397 / 36028797018963968'
4 và
>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
1 đều được làm tròn khi chuyển đổi thành số điểm nổi:

>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'

Khi

>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
2 và
>>> numerator, denominator = (0.1).as_integer_ratio()
>>> f"0.1 ≈ {numerator} / {denominator}"
'0.1 ≈ 3602879701896397 / 36028797018963968'
4 được thêm vào, kết quả là một số lớn hơn một chút so với
>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
1:

>>> 0.1 + 0.2
0.30000000000000004

Do

>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
0 lớn hơn một chút so với ____21 và
>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
1 được biểu thị bằng một số nhỏ hơn một chút so với chính nó, biểu thức
>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
2 đánh giá là
>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
3.

Lỗi biểu diễn điểm nổi là điều mà mọi lập trình viên trong mọi ngôn ngữ cần phải nhận thức và biết cách xử lý. Nó không cụ thể cho Python. Bạn có thể thấy kết quả của việc in

>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
0 bằng nhiều ngôn ngữ khác nhau tại trang web có tên khéo léo của Erik Wiffin 0.30000000000000004.com.It's not specific to Python. You can see the result of printing
>>> 0.1 + 0.2 <= 0.3
False

>>> 10.4 + 20.8 > 31.2
True

>>> 0.8 - 0.1 > 0.7
True
0 in many different languages over at Erik Wiffin's aptly named website 0.30000000000000004.com.

Vì vậy, làm thế nào để bạn đối phó với các lỗi biểu diễn dấu phẩy động khi so sánh phao trong Python? Bí quyết là tránh kiểm tra sự bình đẳng. Không bao giờ sử dụng

>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
5,
>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
6 hoặc
>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
7 với phao. Thay vào đó, hãy sử dụng chức năng
>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
8:

>>> import math
>>> math.isclose(0.1 + 0.2, 0.3)
True

>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
8 Kiểm tra xem đối số đầu tiên có thể chấp nhận gần với đối số thứ hai không. Nhưng chính xác thì điều đó có nghĩa là gì? Ý tưởng chính là kiểm tra khoảng cách giữa đối số thứ nhất và đối số thứ hai, tương đương với giá trị tuyệt đối của sự khác biệt của các giá trị:distance between the first argument and the second argument, which is equivalent to the absolute value of the difference of the values:

>>> a = 0.1 + 0.2
>>> b = 0.3
>>> abs(a - b)
5.551115123125783e-17

Nếu

>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
0 nhỏ hơn một số tỷ lệ phần trăm của
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
1 hoặc
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
2 lớn hơn, thì
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
1 được coi là đủ gần với
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
2 là "bằng" với
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
2. Tỷ lệ này được gọi là dung sai tương đối. Bạn có thể chỉ định dung sai tương đối với đối số từ khóa
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
6 của
>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
8 mặc định là
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
8. Nói cách khác, nếu
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
0 nhỏ hơn
>>> 0.1 + 0.2
0.30000000000000004
0, thì
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
1 và
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
2 được coi là "đóng" với nhau. Điều này đảm bảo rằng
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
1 và
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
2 bằng khoảng chín chữ số thập phân.relative tolerance. You can specify the relative tolerance with the
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
6 keyword argument of
>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
8 which defaults to
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
8. In other words, if
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
0 is less than
>>> 0.1 + 0.2
0.30000000000000004
0, then
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
1 and
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
2 are considered "close" to each other. This guarantees that
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
1 and
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
2 are equal to about nine decimal places.

Bạn có thể thay đổi dung sai tương đối nếu bạn cần:

>>> math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-20)
False

Tất nhiên, dung sai tương đối phụ thuộc vào các ràng buộc được đặt ra bởi vấn đề bạn đang giải quyết. Tuy nhiên, đối với hầu hết các ứng dụng hàng ngày, dung sai tương đối mặc định là đủ.

Có một vấn đề nếu một trong số

>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
1 hoặc
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
2 bằng không và
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
6 là ít hơn một. Trong trường hợp đó, cho dù giá trị khác không đến mức nào về 0, dung sai tương đối đảm bảo rằng việc kiểm tra sự gần gũi sẽ luôn thất bại. Trong trường hợp này, sử dụng dung sai tuyệt đối hoạt động như một dự phòng:

>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
0

>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
8 sẽ tự động kiểm tra này cho bạn. Đối số từ khóa
>>> 0.1 + 0.2
0.30000000000000004
9 xác định dung sai tuyệt đối. Tuy nhiên,
>>> 0.1 + 0.2
0.30000000000000004
9 mặc định là
>>> import math
>>> math.isclose(0.1 + 0.2, 0.3)
True
1 vì bạn sẽ cần thiết lập thủ công này nếu bạn cần kiểm tra mức độ gần với giá trị với 0.

Tất cả trong tất cả,

>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
8 trả về kết quả của so sánh sau, kết hợp các thử nghiệm tương đối và tuyệt đối thành một biểu thức duy nhất:

>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
1

>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
8 đã được giới thiệu trong PEP 485 và đã có sẵn kể từ Python 3.5.

Hãy vượt qua "bướu trung gian."

Một email, mỗi thứ bảy, để thách thức các kỹ năng của bạn và truyền cảm hứng cho sự tò mò. Luôn luôn dưới 5 phút thời gian của bạn.

Khi nào bạn nên sử dụng >>> format(numerator / denominator, ".55f") '0.1000000000000000055511151231257827021181583404541015625'8?

Nói chung, bạn nên sử dụng

>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
8 bất cứ khi nào bạn cần so sánh các giá trị dấu phẩy động. Thay thế
>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
5 bằng
>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
8:

>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
2

Bạn cũng cần phải cẩn thận với so sánh

>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
6 và
>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
7. Xử lý sự bình đẳng riêng biệt bằng cách sử dụng
>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
8 và sau đó kiểm tra so sánh nghiêm ngặt:

>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
3

Các lựa chọn thay thế khác nhau cho

>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
8 tồn tại. Nếu bạn sử dụng Numpy, bạn có thể tận dụng
>>> a = 0.1 + 0.2
>>> b = 0.3
>>> abs(a - b)
5.551115123125783e-17
2 và
>>> a = 0.1 + 0.2
>>> b = 0.3
>>> abs(a - b)
5.551115123125783e-17
3:

>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
4

Hãy nhớ rằng dung sai tương đối và tuyệt đối mặc định không giống như

>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
8. Dung sai tương đối mặc định cho cả
>>> a = 0.1 + 0.2
>>> b = 0.3
>>> abs(a - b)
5.551115123125783e-17
2 và
>>> a = 0.1 + 0.2
>>> b = 0.3
>>> abs(a - b)
5.551115123125783e-17
3 là
>>> a = 0.1 + 0.2
>>> b = 0.3
>>> abs(a - b)
5.551115123125783e-17
7 và dung sai tuyệt đối mặc định cho cả hai là
>>> a = 0.1 + 0.2
>>> b = 0.3
>>> abs(a - b)
5.551115123125783e-17
8.

>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
8 đặc biệt hữu ích cho các bài kiểm tra đơn vị, mặc dù có một số lựa chọn thay thế. Mô-đun
>>> math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-20)
False
0 tích hợp của Python có phương pháp
>>> math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-20)
False
1. Tuy nhiên, phương pháp đó chỉ sử dụng một bài kiểm tra khác biệt tuyệt đối. Đó cũng là một khẳng định, có nghĩa là những thất bại làm tăng
>>> math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-20)
False
2, khiến nó không phù hợp để so sánh trong logic kinh doanh của bạn.

Một giải pháp thay thế tuyệt vời cho

>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
8 để kiểm tra đơn vị là hàm
>>> math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-20)
False
4 từ gói
>>> math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-20)
False
5. Không giống như
>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
8,
>>> math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-20)
False
4 chỉ lấy một đối số - cụ thể là giá trị bạn mong đợi:

>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
5

>>> math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-20)
False
4 có
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
6 và
>>> 0.1 + 0.2
0.30000000000000004
9 đối số từ khóa để thiết lập dung sai tương đối và tuyệt đối. Các giá trị mặc định khác với
>>> format(numerator / denominator, ".55f")
'0.1000000000000000055511151231257827021181583404541015625'
8, tuy nhiên.
>>> # -----------vvvv  Display with 17 significant digits
>>> format(0.1, ".17g")
'0.10000000000000001'

>>> format(0.2, ".17g")
'0.20000000000000001'

>>> format(0.3, ".17g")
'0.29999999999999999'
6 có giá trị mặc định là
>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
03 và
>>> 0.1 + 0.2
0.30000000000000004
9 có giá trị mặc định là
>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
05.

Nếu đối số được chuyển đến

>>> math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-20)
False
4 giống như mảng, có nghĩa là đó là một con trăn có thể giống như một danh sách hoặc một tuple, hoặc thậm chí là một mảng numpy, thì
>>> math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-20)
False
4 hoạt động tương tự như
>>> a = 0.1 + 0.2
>>> b = 0.3
>>> abs(a - b)
5.551115123125783e-17
2 và trả về liệu hai mảng có bằng nhau trong phạm vi dung sai:

>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
6

>>> math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-20)
False
4 thậm chí sẽ hoạt động với các giá trị từ điển:

>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
7

Số điểm nổi là tuyệt vời để làm việc với các số bất cứ khi nào không cần độ chính xác tuyệt đối. Chúng nhanh chóng và hiệu quả bộ nhớ. Nhưng nếu bạn cần độ chính xác, thì có một số lựa chọn thay thế cho phao mà bạn nên xem xét.

Các lựa chọn thay thế điểm nổi chính xác

Có hai loại số tích hợp trong Python cung cấp độ chính xác đầy đủ cho các tình huống mà phao không đủ:

>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
10 và
>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
11.

Loại >>> 0.2 + 0.2 + 0.2 == 0.6 False >>> 1.3 + 2.0 == 3.3 False >>> 1.2 + 2.4 + 3.6 == 7.2 False10

Loại

>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
10 có thể lưu trữ các giá trị thập phân chính xác với độ chính xác nhiều như bạn cần. Theo mặc định,
>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
10 bảo tồn 28 số liệu quan trọng, nhưng bạn có thể thay đổi điều này thành bất cứ điều gì bạn cần để phù hợp với vấn đề cụ thể mà bạn đang giải quyết:

>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
8

Bạn có thể đọc thêm về loại

>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
10 trong tài liệu Python.

Loại >>> 0.2 + 0.2 + 0.2 == 0.6 False >>> 1.3 + 2.0 == 3.3 False >>> 1.2 + 2.4 + 3.6 == 7.2 False11

Một cách khác cho các số điểm nổi là loại

>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
11.
>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
11 có thể lưu trữ các số hợp lý chính xác và khắc phục các vấn đề lỗi đại diện gặp phải bởi các số điểm nổi:

>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
9

Cả

>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
11 và
>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
10 đều cung cấp nhiều lợi ích so với các giá trị điểm nổi tiêu chuẩn. Tuy nhiên, những lợi ích này có giá: giảm tốc độ và mức tiêu thụ bộ nhớ cao hơn. Nếu bạn không cần độ chính xác tuyệt đối, tốt hơn hết là bạn nên gắn bó với phao. Nhưng đối với những thứ như các ứng dụng tài chính và nhiệm vụ quan trọng, sự đánh đổi phát sinh bởi
>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
11 và
>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
10 có thể đáng giá.

Sự kết luận

Giá trị dấu phẩy động là cả một phước lành vừa là một lời nguyền. Họ cung cấp các hoạt động số học nhanh và sử dụng bộ nhớ hiệu quả với chi phí đại diện không chính xác. Trong bài viết này, bạn đã học được:

  • Tại sao các số điểm nổi là không chính xác
  • Tại sao lỗi biểu diễn điểm nổi là phổ biến
  • Cách so sánh chính xác các giá trị điểm nổi trong Python
  • Cách & nbsp; biểu thị các số chính xác bằng cách sử dụng các loại
    >>> 0.2 + 0.2 + 0.2 == 0.6
    False
    
    >>> 1.3 + 2.0 == 3.3
    False
    
    >>> 1.2 + 2.4 + 3.6 == 7.2
    False
    11 và
    >>> 0.2 + 0.2 + 0.2 == 0.6
    False
    
    >>> 1.3 + 2.0 == 3.3
    False
    
    >>> 1.2 + 2.4 + 3.6 == 7.2
    False
    10 của Python

Nếu bạn đã học được điều gì đó mới, thì thậm chí có thể có nhiều hơn mà bạn không biết về các con số trong Python. Ví dụ: bạn có biết loại

>>> 0.2 + 0.2 + 0.2 == 0.6
False

>>> 1.3 + 2.0 == 3.3
False

>>> 1.2 + 2.4 + 3.6 == 7.2
False
25 không phải là loại số nguyên duy nhất trong Python không? Tìm hiểu loại số nguyên khác là gì và các sự kiện ít được biết đến khác về các con số trong bài viết 3 của tôi những điều bạn có thể không biết về các con số trong Python.

3 điều bạn có thể không biết về các con số trong Python

Nếu bạn đã viết bất cứ điều gì bằng Python, bạn có thể đã sử dụng một số trong một trong các chương trình của mình. Nhưng có nhiều con số hơn là chỉ có giá trị thô của chúng.

Hướng dẫn can we use == to compare two float values in python? - chúng ta có thể sử dụng == để so sánh hai giá trị float trong python không?
David Amos

Tài nguyên bổ sung

  • Số học nổi: Các vấn đề và giới hạn
  • Hướng dẫn nổi
  • Những nguy hiểm của điểm nổi
  • Toán học nổi
  • Những gì mọi nhà khoa học máy tính nên biết về số học nổi
  • Cách làm tròn số trong Python

Cảm ơn Brian Okken đã giúp bắt gặp một vấn đề với một trong những ví dụ

>>> math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-20)
False
4.

Có phải == làm việc cho phao không?

Điểm mấu chốt: Không bao giờ sử dụng == để so sánh hai số điểm nổi. Đây là một ví dụ đơn giản: Double x = 1.0 / 10.0; gấp đôi y = x * 10.0; if (y! =Never use == to compare two floating point numbers. Here's a simple example: double x = 1.0 / 10.0; double y = x * 10.0; if (y !=

Chúng ta có thể sử dụng == để so sánh hai số float hoặc gấp đôi không?

Kết quả là sử dụng toán tử ==, chúng ta không thể có biểu diễn chính xác của hầu hết các giá trị kép trong máy tính của chúng ta. Chúng phải được làm tròn để được cứu. Trong trường hợp đó, so sánh cả hai giá trị với toán tử == sẽ tạo ra kết quả sai.comparing both values with the == operator would produce a wrong result.

Tại sao bạn không nên sử dụng toán tử == để so sánh hai phao?

Bởi vì ngay cả lỗi làm tròn nhỏ nhất cũng sẽ khiến hai số điểm nổi không bằng nhau, toán tử == có nguy cơ cao để trả lại sai khi có thể thực sự có thể được mong đợi.Toán tử! = Có cùng một loại vấn đề.Vì lý do này, việc sử dụng các nhà khai thác này với các toán hạng điểm nổi thường nên tránh.. Operator!= has the same kind of problem. For this reason, use of these operators with floating point operands should generally be avoided.

Có an toàn không khi sử dụng trực tiếp toán tử == để xác định xem các đối tượng có thể nổi có bằng nhau không?

Câu trả lời là không. Không an toàn khi sử dụng toán tử == để xác định xem các đối tượng nổi có bằng nhau không.it is not safe to use the == operator to determine whether objects of type float are equal.