8

Tôi đã cố gắng viết một hàm để gần đúng căn bậc hai (tôi biết có mô-đun toán học ... Tôi muốn tự mình làm điều đó), và tôi bị xáo trộn bởi số học dấu phẩy động. Làm thế nào bạn có thể tránh điều đó?Làm cách nào để tránh các lỗi dấu phẩy động?

def sqrt(num): 
    root = 0.0 
    while root * root < num: 
     root += 0.01 
    return root 

Sử dụng này có những kết quả này:

>>> sqrt(4) 
2.0000000000000013 
>>> sqrt(9) 
3.00999999999998 

Tôi nhận ra tôi chỉ có thể sử dụng round(), nhưng tôi muốn để có thể thực hiện điều này thực sự chính xác. Tôi muốn có thể tính toán đến 6 hoặc 7 chữ số. Điều đó sẽ không thể nếu tôi làm tròn. Tôi muốn hiểu cách xử lý đúng các phép tính dấu chấm động trong Python.

+0

Có thể thử mô-đun [thập phân] (http://docs.python.org/2/library/decimal.html), là được thiết kế cho độ chính xác? – Michael0x2a

Trả lời

15

Điều này thực sự không liên quan gì đến Python - bạn sẽ thấy cùng một hành vi trong bất kỳ ngôn ngữ nào bằng cách sử dụng số học dấu phẩy động nhị phân của phần cứng. Đầu tiên read the docs.

Sau khi bạn đọc điều đó, bạn sẽ hiểu rõ hơn rằng bạn đang không thêm một phần trăm trong mã của mình. Đây chính xác là những gì bạn đang thêm:

>>> from decimal import Decimal 
>>> Decimal(.01) 
Decimal('0.01000000000000000020816681711721685132943093776702880859375') 

Chuỗi đó cho biết giá trị thập phân chính xác của giá trị nhị phân ("chính xác kép" trong C) xấp xỉ với giá trị thập phân chính xác 0,01. Thứ bạn đang thực sự thêm lớn hơn 1/100.

Kiểm soát lỗi số dấu phẩy động là trường được gọi là "phân tích số" và là một chủ đề rất lớn và phức tạp. Vì vậy, miễn là bạn đang giật mình bởi thực tế là phao chỉ là xấp xỉ giá trị thập phân, sử dụng mô-đun decimal. Điều đó sẽ lấy đi một thế giới của những vấn đề "nông cạn" cho bạn. Ví dụ, do sự thay đổi nhỏ này để chức năng của bạn:

from decimal import Decimal as D 

def sqrt(num): 
    root = D(0) 
    while root * root < num: 
     root += D("0.01") 
    return root 

thì:

>>> sqrt(4) 
Decimal('2.00') 
>>> sqrt(9) 
Decimal('3.00') 

Nó không thực sự chính xác hơn, nhưng có thể ít ngạc nhiên trong các ví dụ đơn giản vì bây giờ nó thêm chính xác một một hàng trăm.

Cách khác là gắn vào phao nổi và thêm nội dung nào đó chính xác thể hiện dưới dạng phao nhị phân: giá trị của biểu mẫu I/2**J. Ví dụ: thay vì thêm 0,01, hãy thêm 0,125 (1/8) hoặc 0,0625 (1/16).

Sau đó tra cứu "phương pháp Newton" để tính căn bậc hai ;-)

+0

Đối với hồ sơ tôi đã đọc các tài liệu và tôi đã biết về toàn bộ điều chính xác điểm nổi với lưu trữ các biểu diễn nhị phân. Tôi đã quên phương pháp của Newton. Bạn đang chọn tất cả các câu hỏi của tôi xung quanh đây! Ngày may mắn của tôi khi bạn phát hiện SO. Tôi tự hỏi làm thế nào các mô-đun thập phân hoạt động. Có cách nào để tìm hiểu ngoài việc đọc nguồn không? – Aerovistae

+1

Vâng, 'thập phân' ban đầu được viết bằng Python và làm việc trên danh sách các chữ số thập phân (0, 1, 2, ..., 9). Rất nhiều mô phỏng cách chúng tôi làm số học trên giấy! "Điểm nổi" chỉ cần thêm số mũ (số thập phân) vào biểu diễn, và sau đó rất cẩn thận ;-) Mô-đun 'thập phân' hiện tại được mã hóa trong C, và mờ hơn nhiều :-( –

+0

như bạn đã nói, tôi đã thử để giải quyết '4 - 3.2' sử dụng mô-đun thập phân. a = Decimal (4) b = thập phân (3.2) nhưng một - kết quả b là số thập phân (',7999999999999998223643160600') – Srinesh

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