2013-08-08 37 views
11

Tôi đang cố gắng tìm hiểu cách ruby ​​xử lý phân chia bằng không. Ruby trả về các kết quả khác nhau dựa trên lớp. Đây là những gì tôi đã thửLàm thế nào để xử lý ruby ​​chia zero?

0/0  # => ZeroDivisionError: divided by 0  
1/0  # => ZeroDivisionError: divided by 0 
1.0/0 # => Infinity 
0.0/0.0 # => NaN 

Điều gì đang xảy ra ở đây? Tôi có nên nhận được ZeroDivisionError cho tất cả các trường hợp trên không?

Cập nhật Loại dữ liệu chuẩn có "Infinity" không?

(1.0/0).class # => Float 
+4

Nổi không giống như int. Có vẻ như bạn đã liệt kê các vấn đề. Những thứ như NaN và Infinity là điển hình cho phao nổi. –

+0

@DaveNewton nhưng không có ngoại lệ nào được nêu ra trong trường hợp nổi, tại sao lại là trường hợp này? – ZX12R

+0

Bởi vì nó không phải là một ngoại lệ khi giao dịch với số học dấu chấm động; có một giá trị được xác định rõ ('Infinity' hoặc' NaN'). Xem https://en.wikipedia.org/wiki/IEEE_floating_point#Exception_handling từ liên kết của Gene. –

Trả lời

10

Ruby chỉ theo dõi IEEE 754 Floating Point Standard. Trang Wikipedia đó không tệ khi giải thích những gì bạn đang thấy. Nhiều ngôn ngữ hiện đại có cùng cách tiếp cận.

Bằng trực giác, hành vi bạn thấy có ý nghĩa hoàn hảo. Nói chung,

1/<small number> = <big number> 

Do đó trong giới hạn,

1/0 -> Infinity and similarly -1/0 -> -Infinity 

Infinity là một hằng số hiểu bởi hệ thống con dấu chấm động. Mặt khác,

0/<any non-zero> = 0 

Vì vậy, chúng tôi có xung đột về 0/0. Nó có nên là số không hoặc vô cùng? Câu trả lời tiêu chuẩn IEEE là "Not a Number", số NaN bạn đang thấy, một hằng số dấu phẩy động khác.

Hằng số NaN và cộng hoặc trừ Infinity tuyên truyền thông qua biểu thức theo cách có ý nghĩa. Ví dụ:

Infinity + <any (necessarly finite) number> = Infinity 

<any number> + NaN = NaN 

Và thú vị hơn:

1/Infinity = 0 

nào bạn có thể thử tự hỏi:

irb(main):005:0> 1.0/(1.0/0.0) 
=> 0.0 

Theo cách này tính toán dấu chấm động có thể tiếp tục ngay cả khi nó đã tràn hoặc chia cho số không và vẫn tạo ra một câu trả lời hợp lý (mặc dù sau khi bạn biết tiêu chuẩn tốt, bạn sẽ thấy rằng dựa vào câu trả lời thường là một ý tưởng tồi).

Đây là hành vi duy nhất mà tiêu chuẩn cung cấp. Những người khác có thể được chọn. Nhưng Ruby làm điều này cho bạn. Tệp nguồn numeric.c, chức năng Init_Numeric, thiết lập bộ xử lý máy chủ để phân chia bằng không truyền bá thông tin. Các ngôn ngữ khác có thể thực hiện các lựa chọn khác, ví dụ để tạo ra một ngoại lệ.

+7

Tôi khuyên bạn nên bao gồm thông tin thực tế trong câu trả lời thay vì chỉ liên kết. –

+0

Um. Lấy làm tiếc. Thông tin này là nó theo dõi chuẩn IEEE 754. Mỗi lập trình viên phải nhận thức được tiêu chuẩn này ở bề rộng đầy đủ của nó. Nếu tôi trích đoạn trích ở đây, người đọc sẽ bỏ lỡ cơ hội đó. Tuy nhiên, – Gene

+4

Câu trả lời chỉ có liên kết thực sự không ổn. Đừng giấu đằng sau "họ phải đọc toàn bộ nội dung cho bản thân để hiển thị hai câu cần thiết để giải thích câu hỏi thực tế." Thay vào đó, hãy nêu bật sự cần thiết phải hiểu ngoài mức bề mặt, * và * trả lời câu hỏi cụ thể. –

7

Các hành vi cho điểm nổi phản ánh tiêu chuẩn trong IEEE 754:

  • hoạt động không hợp lệ (ví dụ, căn bậc hai của một số âm) (trả QNaN theo mặc định).
  • Phân chia bằng không (thao tác trên toán hạng hữu hạn cho kết quả vô hạn chính xác, ví dụ: 1/0 hoặc log (0)) (trả lại ± vô cực theo mặc định).

Quyết định triển khai lỗi thời gian chạy cho phân số nguyên bằng 0 là phổ biến trên nhiều ngôn ngữ khác cũng như Java, C++, Python. Python thực sự cũng gọi lỗi ZeroDivisionError.

Xem sawa's answer vì lý do phân loại và hành vi này.

4

Vấn đề là phao có lỗi làm tròn. Một phao 0.0 không nhất thiết thể hiện chính xác bằng không, hoặc 0.0 theo nghĩa toán học, nhưng đại diện cho tất cả các số sẽ được làm tròn thành 0.0 cho độ chính xác. Phân chia theo chính xác 0 không được định nghĩa về mặt toán học, nhưng cấm phân chia theo 0.0 sẽ có nguy cơ trả về lỗi trong trường hợp số chia xảy ra có giá trị tuyệt đối khác không đủ nhỏ để làm tròn thành 0.0. Bạn không muốn một chương trình đột nhiên trả về lỗi khi giá trị tuyệt đối của số chia nhỏ khi nó không bằng 0. Trong trường hợp phao nổi, an toàn hơn để hệ thống chỉ định một số nhất định để chia cho 0.0 thay vì cấm nó. Nhưng con số đó không thể được biểu diễn theo cách thông thường, vì vậy nó được gán NaN hoặc Infinity. Điều gây hiểu lầm về điều này là Infinity không phải là vô cùng trong ý nghĩa toán học. Nó chỉ có nghĩa là "một số lớn hơn bất kỳ số nào khác có thể được thể hiện trong hệ thống này." Điều đó giải thích trường hợp:

1.0/0.0 # => Infinity 
0.0/0.0 # => NaN 

Khi một đối số để / là một phao, Ruby kiểu phôi người kia nổi, vì vậy

1/0.0 
1.0/0 

sẽ được giống như 1.0/0.0.

Mặt khác, số nguyên 0 không bao gồm lỗi và chính xác là không, do đó không có nguy hiểm như vậy. Nó có ý nghĩa hơn để nâng cao một lỗi phân chia bằng không. Điều đó giải thích

1/0 # => Error 
0/0 # => Error 
Các vấn đề liên quan