Một máy tính sẽ cố gắng chia cho số không?


59

Chúng ta đều biết 0/0Undefinedvà trả về một lỗi nếu tôi đã đặt nó vào một máy tính, và nếu tôi là để tạo ra một chương trình (trong C ít nhất) hệ điều hành sẽ chấm dứt nó khi tôi cố gắng chia cho zero.

Nhưng điều tôi băn khoăn là liệu máy tính thậm chí có cố gắng chia cho số 0 hay nó chỉ có "bảo vệ tích hợp", để khi nó "nhìn thấy", 0/0nó sẽ trả về lỗi ngay cả trước khi thử tính toán?


10
0/0 là không xác định, bất kỳ số nào khác / 0 là một loại lỗi khác nhau, bạn có vẻ khó hiểu hai
edc65

7
Bất kỳ số nào chia cho 0 là không xác định, nói theo toán học.
ManoD nhạc

12
@jwg: "nếu nó có giá trị thì nó sẽ là 1" - không nhất thiết phải như vậy; có cả nhánh toán học dành cho những gì giá trị có thể có trong các trường hợp khác nhau :)
psmears

11
Để làm rõ thuật ngữ ở đây, 0/0 được gọi là một dạng không xác định trong khi x / 0 cho nonzero x không được xác định . Một phép tính kết thúc bằng 0/0 thường có thể được tính theo một cách khác để đưa ra câu trả lời thực sự, trong khi x / 0 về cơ bản là vô nghĩa.
Thời đại

9
@jwg bạn có thể quan tâm đến quy tắc của tôi. Chắc chắn có những trường hợp 0/0 không ngụ ý giá trị là 1.
d0nut

Câu trả lời:


74

CPU đã được xây dựng trong phát hiện. Hầu hết các kiến ​​trúc tập lệnh đều chỉ định rằng CPU sẽ bẫy một trình xử lý ngoại lệ để chia số nguyên cho 0 (Tôi không nghĩ rằng nó quan tâm nếu cổ tức bằng không).

Có thể việc kiểm tra ước số 0 xảy ra song song trong phần cứng cùng với nỗ lực thực hiện phép chia, tuy nhiên, việc phát hiện điều kiện vi phạm có hiệu quả hủy bỏ phân chia và bẫy thay vào đó, vì vậy chúng tôi thực sự không thể biết nếu một phần nào đó của nó đã cố gắng phân chia hay không.

(Phần cứng thường hoạt động như vậy, thực hiện nhiều việc song song và sau đó chọn kết quả phù hợp vì sau đó mỗi thao tác đều có thể bắt đầu ngay lập tức thay vì tuần tự hóa lựa chọn thao tác phù hợp.)

Cơ chế bẫy tương tự cũng sẽ được sử dụng khi bật phát hiện tràn, mà bạn thường yêu cầu bằng cách sử dụng các hướng dẫn thêm / phụ / mul khác nhau (hoặc cờ theo các hướng dẫn đó).

Phân chia dấu phẩy động cũng được xây dựng để phát hiện chia cho 0, nhưng trả về một giá trị khác ( IEEE 754 chỉ định NaN ) thay vì đặt bẫy cho trình xử lý ngoại lệ.


Về mặt giả thuyết, nếu CPU bỏ qua bất kỳ phát hiện nào để cố gắng chia cho 0, các vấn đề có thể bao gồm:

  • treo CPU (ví dụ: trong vòng lặp inf) - điều này có thể xảy ra nếu CPU sử dụng thuật toán để phân chia dừng khi tử số nhỏ hơn số chia (về giá trị tuyệt đối). Việc treo như thế này sẽ được tính là khá nhiều khi làm hỏng CPU.
  • một câu trả lời rác (có thể dự đoán được), nếu CPU sử dụng bộ đếm để chấm dứt phân chia ở số bước phân chia tối đa có thể (ví dụ 31 hoặc 32 trên máy 32 bit).

51
@Ankush Một "sự cố hệ thống" không thực sự xảy ra ở cấp độ CPU. Hành vi rất có thể của CPU không bị chia cho số 0 sẽ chỉ đơn giản là nó thực hiện thao tác phân chia, tạo ra một số kết quả vô nghĩa và tiếp tục. Giống như khi bạn thêm hai số nguyên xảy ra tràn.
Ixrec

6
Đối với điểm nổi, sự lựa chọn giữa "NaN" và "bẫy" thường có thể được giải quyết bằng cách lật cờ trong FPU.
Vatine

10
@Ankush Trong trường hợp những gì lxrec nói không rõ ràng: liên quan đến CPU, không có sự cố nào xảy ra.
dùng253751

7
@Ankush Rất ít tình huống gây ra "sự cố hệ thống" ở cấp độ CPU. Trong những trường hợp đó, chúng ta đang nói về những thứ như tắt máy bảo vệ nhiệt (bảo vệ quá nhiệt), lỗi ba và các tình huống tương tự. Hầu như mọi sự cố bạn sẽ gặp trong sử dụng thông thường, bao gồm cả các mã không hợp lệ , được xử lý bằng cách bẫy và khôi phục theo cách nào đó, hoặc đơn giản là bỏ qua lỗi và tiếp tục thực thi trong trạng thái có khả năng ô uế có thể đã đặt cờ lỗi.
một CVn

8
Nếu bạn không bẫy chia cho 0, kết quả sẽ là, theo cách nói của lập trình, "Hành vi không xác định." Điều này có nghĩa là máy tính có thể làm bất cứ điều gì. Nó có thể, như Bergi đề cập, đi vào một vòng lặp lỗi và treo. Nó có thể chỉ đơn giản là xuất ra một số bit không xác định mà là do việc triển khai logic phân chia của chúng (hãy nhớ rằng, một máy tính không "phân chia" theo nghĩa toán học. Nó hoạt động trên hai số, đủ gần để phân chia mà chúng ta thường chỉ đơn giản gọi nó là "phép chia" .. xem thêm vòng tròn dấu phẩy động).
Cort Ammon

34

Nó phụ thuộc vào ngôn ngữ, vào trình biên dịch, vào việc bạn đang sử dụng số nguyên hay số dấu phẩy động, v.v.

Đối với số dấu phẩy động, hầu hết các cài đặt đều sử dụng tiêu chuẩn IEEE 754 , trong đó phép chia cho 0 được xác định rõ. 0/0 cho kết quả được xác định rõ là NaN (không phải là số) và x / 0 cho x ≠ 0 cho + Infinity hoặc -Infinity, tùy thuộc vào dấu của x.

Trong các ngôn ngữ như C, C ++, vv chia cho số 0 gọi các hành vi không xác định. Vì vậy, theo định nghĩa ngôn ngữ, bất cứ điều gì có thể xảy ra. Đặc biệt là những điều bạn không muốn xảy ra. Giống như mọi thứ hoạt động hoàn toàn tốt khi bạn viết mã và hủy dữ liệu khi khách hàng của bạn sử dụng nó. Vì vậy, từ quan điểm ngôn ngữ, đừng làm điều này . Một số ngôn ngữ đảm bảo rằng ứng dụng của bạn sẽ bị sập; tùy thuộc vào cách họ thực hiện. Đối với những ngôn ngữ đó, chia cho số 0 sẽ sụp đổ.

Nhiều bộ xử lý có một số loại lệnh "chia" tích hợp, sẽ hoạt động khác nhau tùy thuộc vào bộ xử lý. Trên bộ xử lý Intel 32 bit và 64 bit, các hướng dẫn "chia" sẽ làm hỏng ứng dụng của bạn khi bạn cố chia cho 0. Các bộ xử lý khác có thể hành xử khác nhau.

Nếu trình biên dịch phát hiện ra rằng việc chia cho 0 sẽ xảy ra khi bạn thực thi một số mã và trình biên dịch tốt cho người dùng của nó, nó có thể sẽ đưa ra cảnh báo cho bạn và tạo ra một lệnh "chia" tích hợp để hành vi đó là tương tự.


22
"Trên bộ xử lý Intel 32 bit và 64 bit, các hướng dẫn" chia "sẽ làm hỏng ứng dụng của bạn khi bạn cố chia cho số không." Cần dẫn nguồn. CPU không có bất kỳ ý tưởng nào về các ứng dụng, chúng thực thi các hướng dẫn và (nếu chúng tôi bao gồm MMU) thực thi các giới hạn truy cập bộ nhớ (trừ khi ở vòng 0 hoặc tương đương trong các kiến ​​trúc không phải Intel-x86). Rằng hướng dẫn là một phần của Ứng dụng A chứ không phải Ứng dụng B hoặc Thành phần hệ điều hành C không liên quan đến CPU; liệu hướng dẫn có thể là Hướng dẫn X hoặc sử dụng Địa chỉ bộ nhớ Y có liên quan hay không.
một CVn

1
Để thêm vào nhận xét @ MichaelKjorling: Hệ điều hành có các cách để không áp dụng ứng dụng này (và các loại lỗi khác). Trong cửa sổ thế giới nó là EXCEPTION_INT_DIVIDE_BY_ZEROgiá trị trong EXCEPTION_RECORDđó sẽ được xử lý bởi các (hy vọng) được cài đặt structed Xử lý ngoại lệ Handler
user45891

1
Đôi khi họ làm những việc khác ngoài việc đảm bảo rằng ứng dụng của bạn sẽ bị sập. Ví dụ, nhiều ngôn ngữ / nền tảng đảm bảo rằng họ sẽ đưa ra một ngoại lệ khi chia cho số không. Sau đó, bạn có thể bắt và xử lý ngoại lệ nói mà không gặp sự cố.
đăng lại

2
Bạn có thể xóa "có thể" trong "Các bộ xử lý khác có thể hoạt động khác": Trên Nền tảng PowerPC, bộ phận chỉ tạo ra kết quả bằng 0 khi chia cho số không. Điều này hữu ích hơn nhiều so với hành vi hoảng loạn của nền tảng X86.
cmaster

13

Có vẻ như bạn đang tự hỏi điều gì sẽ xảy ra nếu ai đó tạo ra một CPU không kiểm tra rõ ràng về số 0 trước khi chia. Điều gì sẽ xảy ra phụ thuộc hoàn toàn vào việc thực hiện của bộ phận. Nếu không đi sâu vào chi tiết, một loại triển khai sẽ tạo ra kết quả có tất cả các bit được đặt, ví dụ 65535 trên CPU 16 bit. Một cái khác có thể treo lên.


1

Nhưng điều tôi băn khoăn là liệu máy tính thậm chí có cố gắng chia cho 0 hay nó chỉ có "bảo vệ tích hợp", để khi nó "thấy" 0/0, nó sẽ trả về lỗi ngay cả trước khi thử tính toán?

x/0không có ý nghĩa, thời gian, máy tính phải luôn kiểm tra phân chia cho số không. Có một vấn đề ở đây: Các lập trình viên muốn tính toán (a+b)/cmà không phải bận tâm kiểm tra xem phép tính đó có hợp lý hay không. Phản hồi bên dưới để phân chia cho 0 theo CPU + loại số + hệ điều hành + ngôn ngữ là để làm một cái gì đó khá quyết liệt (ví dụ: làm hỏng chương trình) hoặc làm một cái gì đó quá lành tính (ví dụ: tạo ra một giá trị không nghĩa là điểm nổi của IEEE NaN, một số là "Không phải là số").

Trong một khung cảnh bình thường, một lập trình viên dự kiến ​​sẽ biết liệu có hợp lý hay không (a+b)/c. Trong bối cảnh này, không có lý do để kiểm tra chia cho số không. Nếu việc chia cho số 0 xảy ra và nếu ngôn ngữ máy + ngôn ngữ thực hiện + kiểu dữ liệu + phản hồi của hệ điều hành là làm cho chương trình bị sập thì không sao. Nếu phản hồi là tạo ra một giá trị cuối cùng có thể gây ô nhiễm mọi số trong chương trình, điều đó cũng không sao.

Không phải "một cái gì đó quyết liệt" hay "quá lành tính" là điều nên làm trong thế giới điện toán có độ tin cậy cao. Những phản ứng mặc định đó có thể giết chết một bệnh nhân, đâm máy bay hoặc làm cho một quả bom phát nổ không đúng chỗ. Trong một môi trường có độ tin cậy cao, một lập trình viên viết (a+b)/csẽ bị chọn chết trong khi xem lại mã, hoặc trong thời hiện đại, có lẽ được chọn tự động đến chết bởi một công cụ kiểm tra các cấu trúc verboten. Trong môi trường này, lập trình viên đó thay vào đó nên viết một cái gì đó dọc theo dòng div(add(a,b),c)(và có thể một số kiểm tra trạng thái lỗi). Bên dưới mui xe, các chức năng / macro div(và cả add) cũng bảo vệ chống phân chia bằng 0 (hoặc tràn trong trường hợp add). Những gì bảo vệ đòi hỏi là rất cụ thể thực hiện.


Chỉ vì NaN không tuân theo số học mà bạn đã học ở trường không có nghĩa là nó nghĩa. Nó tuân theo số học khác nhau
Caleth

-2

Chúng tôi biết rằng bây giờ x/00/0không có câu trả lời được xác định rõ. Điều gì xảy ra nếu bạn cố gắng tính toán 0/0?

Trên một hệ thống hiện đại, phép tính được chuyển đến MPU trong CPU và được gắn cờ là hoạt động bất hợp pháp, quay trở lại NaN.

Trên một hệ thống cũ hơn nhiều, chẳng hạn như máy tính gia đình thập niên 80 không có phân chia trên chip, việc tính toán được thực hiện bởi bất kỳ phần mềm nào đang chạy. Có một vài lựa chọn có thể:

  • Trừ các bản sao nhỏ hơn và nhỏ hơn của ước số cho đến khi giá trị bằng 0 và theo dõi các bản sao có kích thước được trừ
    • Nếu nó kiểm tra số 0 trước phép trừ đầu tiên, nó sẽ thoát ra nhanh chóng và kết quả sẽ là 0
    • Nếu nó giả định nó phải có thể trừ ít nhất một lần, kết quả sẽ là 1
  • Tính toán logarit của cả hai số, trừ chúng và nâng e lên lũy thừa của kết quả. Một phương pháp rất kém hiệu quả so với phương pháp trừ ở trên, nhưng có giá trị về mặt toán học
    • Một sự cố tràn có thể xảy ra khi cố gắng tính toán log(0)và phần mềm sẽ sử dụng các thói quen xử lý lỗi của nó hoặc sự cố
    • Phần mềm có thể giả định rằng tất cả các logarit có thể được tính theo một số bước cố định và trả về một giá trị lớn, nhưng không chính xác. Vì cả hai logarit đều giống nhau, nên sự khác biệt sẽ là 0và e 0 = 1, cho kết quả là1

Nói cách khác, nó sẽ phụ thuộc vào việc thực hiện những gì sẽ xảy ra và có thể viết phần mềm tạo ra kết quả chính xác và có thể dự đoán cho mọi giá trị nhưng dường như các giá trị lạ đối với 0/0điều đó dù sao vẫn phù hợp với nội bộ.


3
Câu hỏi này là về việc chia cho số 0 trong các số nguyên và không có điều gì giống như NaNtrong các số nguyên.
David Hammen

3
Không có CPU sẽ tính toán các bản ghi và trừ để tính kết quả của phép chia. Thời gian hướng dẫn logarit là một số bậc có độ lớn lớn hơn một phép chia. Giá trị của log (0) là gì?
wallyk

1
@DavidHammen OP không bao giờ nhắc đến số nguyên, và cũng không có ai bình luận về câu hỏi này. Số nguyên chỉ được đề cập trong câu trả lời.
CJ Dennis

@wallyk Tôi đã nói trong câu trả lời của mình rằng logarit là very inefficientđể phân chia. Chi phí cho số học là (cộng = trừ) <= phép nhân <= phép chia. Nếu bạn không có MPU có thể thực hiện phép chia trong cùng một số chu kỳ đồng hồ như cộng (thường là một), thì phép chia sẽ đắt hơn phép cộng và phép trừ và thường đắt hơn phép nhân.
CJ Dennis
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.