Hành vi của phân chia số nguyên là gì?


209

Ví dụ,

int result;

result = 125/100;

hoặc là

result = 43/100;

Kết quả sẽ luôn là sàn của bộ phận? Hành vi được xác định là gì?


5
Tóm tắt: phân chia số nguyên cắt ngắn về không . Đối với kết quả không âm, điều này giống như sàn (vòng về phía -Infality). (Coi chừng C89 không đảm bảo điều này, hãy xem câu trả lời.)
Peter Cordes

5
Mọi người cứ nói "cắt ngắn về không" hoặc "trần" hoặc "sàn" như mã đang đưa ra quyết định có chủ ý về việc sử dụng kỹ thuật nào. Nếu mã có thể nói chuyện thì nó sẽ nói"I just throw the dam fraction part in the trash and move on with life"
Timothy LJ Stewart

3
@ TimothyL.J.Stewart "Code" đang đưa ra quyết định có chủ ý. Theo đặc điểm kỹ thuật, phép chia số nguyên có nghĩa là phân chia T (phân chia). Do đó, toán tử modulo / phần còn lại được ngụ ý khác với ngôn ngữ khác, ví dụ như Python hoặc Ruby. Xem phần này để biết danh sách các cách khác nhau mà các ngôn ngữ thực hiện toán tử modulo và bài viết này liệt kê ra ít nhất năm trong số các cách phổ biến mà các ngôn ngữ lập trình quyết định thực hiện div / modulo.
13steinj

1
@ 13steinj Tôi đang nói một cách thông tục theo các bình luận mà nó đang biến thành "nó bị cắt cụt về 0 ... không phải là sàn ... không nếu âm của nó trần ..." đôi khi các kỹ thuật không truyền vào tương lai bằng trí nhớ của con người như chúng tôi mong muốn, nhưng biết một cách trực giác rằng "phần phân số bị ném đi" bạn có thể rút ra được các điểm kỹ thuật. Kỹ thuật là một gánh nặng lớn, nhưng trực giác thì nhẹ nhàng và sảng khoái như gió, tôi sẽ mang những thứ đó thật xa và khi cần tôi sẽ biết bắt đầu từ đâu. Giống như tờ giấy mà bạn liên kết, cảm ơn bạn.
Timothy LJ Stewart

Tôi đã trả lời ở đây với sự nhấn mạnh vào phân chia Euclide (liên kết giữa phép chia số nguyên và toán tử mô đun).
Picaud Vincent

Câu trả lời:


182

Kết quả sẽ luôn là sàn của bộ phận? Hành vi được xác định là gì?

Có, thương số nguyên của hai toán hạng.

6.5.5 Toán tử nhân

6 Khi các số nguyên được chia, kết quả của toán tử / là thương số đại số với bất kỳ phần phân số nào bị loại bỏ. 88) Nếu thương số a / b là đại diện, biểu thức (a / b) * b + a% b sẽ bằng a.

và chú thích tương ứng:

88) Điều này thường được gọi là "cắt ngắn về không".

Tất nhiên hai điểm cần lưu ý là:

3 Các chuyển đổi số học thông thường được thực hiện trên các toán hạng.

và:

5 Kết quả của toán tử / là thương số từ việc chia toán hạng thứ nhất cho toán tử thứ hai; kết quả của toán tử% là phần còn lại. Trong cả hai thao tác, nếu giá trị của toán hạng thứ hai bằng 0, thì hành vi không được xác định.

[Lưu ý: Nhấn mạnh mỏ]


26
... Tất nhiên, trừ khi bạn chia số âm cho số dương (hoặc vv), trong trường hợp đó, nó sẽ là trần.
Sẽ có

74
Nó không phải là sàn hay trần, nó là một phần của phân đoạn, nó là khác nhau về mặt khái niệm!
lornova

38
@ Will A: Không. Nó được định nghĩa là cắt ngắn về không. Gọi nó là bất cứ điều gì khác sẽ chỉ gây thêm nhầm lẫn, vì vậy xin vui lòng không làm như vậy.
Martin York

43
Ít nhất là từ góc độ toán học, cắt ngắn về 0 tương đương với "nếu> 0 thì sàn khác trần". Tôi nghĩ chỉ cần gọi nó là cắt ngắn đơn giản hơn gọi nó là sàn / trần, nhưng một trong hai là hợp lệ. Bất kể, quan điểm của Will A là hợp lệ: Câu trả lời của Dirkgently là không đúng một phần, vì ông tuyên bố rằng OP đúng về kết quả là sàn của bộ phận.
Brian

9
@Philip Potter: Tôi không nghĩ nó được định nghĩa trong C89 và nó không phải là tiêu chuẩn C ++ năm 1998. Trong đó, tất nhiên (a / b) * b + a % b == aphải được thỏa mãn, và giá trị tuyệt đối a % bphải nhỏ hơn a, nhưng cho dù a % blà âm đối với âm ahay bkhông được chỉ định.
David Thornley

39

Dirkgently đưa ra một mô tả tuyệt vời về phân chia số nguyên trong C99, nhưng bạn cũng nên biết rằng trong phân chia số nguyên C89 với toán hạng âm có hướng xác định thực hiện.

Từ dự thảo ANSI C (3.3.5):

Nếu một toán hạng là âm, thì kết quả của toán tử / là số nguyên lớn nhất nhỏ hơn thương số đại số hay số nguyên nhỏ nhất lớn hơn thương số đại số được xác định theo thực thi, như là dấu hiệu của kết quả của toán tử%. Nếu thương số a / b là đại diện, biểu thức (a / b) * b + a% b sẽ bằng a.

Vì vậy, xem ra với số âm khi bạn bị mắc kẹt với trình biên dịch C89.

Thật là một sự thật thú vị khi C99 chọn cách cắt ngắn về 0 vì đó là cách FORTRAN đã làm điều đó. Xem tin nhắn này trên comp.std.c.


2
Và dự thảo C99 N1256 đoạn 5 đề cập đến reliable integer divisionnhư là một tính năng ngôn ngữ mới. Tuyệt vời *-*.
Ciro Santilli 郝海东 冠状 病 事件

Cắt ngắn là cách phần cứng CPU phổ biến nhất (ví dụ x86) hoạt động, vì vậy sẽ thật điên rồ khi đưa ra một lựa chọn khác. IDK xuất hiện đầu tiên, ngữ nghĩa của Fortran hoặc hành vi phần cứng, nhưng không phải ngẫu nhiên mà chúng cũng giống nhau.
Peter Cordes

2
@PeterCordes: Hầu hết các phần cứng CPU phổ biến có thể thực hiện phân chia trôi nổi bởi hầu hết các hằng số nhanh hơn chúng có thể thực hiện phân chia. IMHO, sẽ tốt hơn nếu Tiêu chuẩn nói điều đó expr1 / expr2expr1 % expr2phải nhất quán với nhau khi cả hai trường expr1hợp kết hợp cùng một đối tượng theo cùng một cách, và tương tự như vậy expr2, nhưng sự lựa chọn cắt ngắn so với phân chia trôi nổi là không xác định. Điều đó sẽ cho phép tạo mã hiệu quả hơn mà không phá vỡ nhiều khả năng tương thích (và việc triển khai có thể ghi lại hành vi cụ thể nếu nghiêng)
supercat

23

Trường hợp kết quả là âm, C cắt ngắn về 0 thay vì sàn - Tôi đã học được cách đọc này về lý do tại sao phân chia số nguyên Python luôn luôn ở đây: Tại sao Sàn phân chia số nguyên của Python


3
Tôi đồng ý với nhận xét tự hỏi liệu có (neg% pos) đi tiêu cực có bao giờ hữu ích không? Trên một lưu ý liên quan, tôi tự hỏi liệu hành vi không chính xác được yêu cầu trong một số trường hợp "unsignvar> Signvar" có bao giờ hữu ích không? Tôi có thể hiểu lý do không yêu cầu hành vi luôn luôn đúng; Tôi thấy không có lý do cho việc yêu cầu hành vi sai.
supercat

8
+1 cho một tài liệu tham khảo tuyệt vời về lý do tại sao sàn là hành vi chính xác cho phân chia số nguyên (trái với định nghĩa của C, bị hỏng và gần như không bao giờ hữu ích).
R .. GitHub DỪNG GIÚP ICE

@supercat Xem xét : filtered = (k - 1) * filtered + value + carry; carry = filtered % factor; filtered /= factor, lặp đi lặp lại với các giá trị thay đổi của value. Nó tạo ra một xấp xỉ số nguyên đẹp cho bộ lọc thông thấp thứ nhất với hằng số thời gian k... nhưng nó chỉ đối xứng nếu phân chia bị cắt cụt và carrynhận các giá trị âm. Đôi khi cả hai hành vi để phân chia đều có ích.
hobbs 21/12/17

1
@hobbs: Tôi không nghĩ đoạn mã trên sẽ hoạt động sạch sẽ khi tín hiệu vượt qua 0. Nếu divlà một toán tử phân chia nổi và factorlà số lẻ, thì filtered += (filter+(factor div 2)) div factorsẽ mang lại hành vi sạch và đối xứng cho tất cả các giá trị lên đến INT_MAX-(factor div 2).
supercat

@supercat nó hoạt động mặc dù; mã đó chỉ được chưng cất một chút từ thứ mà tôi đã chạy trong bộ điều khiển của đồng hồ nguyên tử trong một thời gian.
hobbs

21

Có, kết quả luôn luôn bị cắt về không. Nó sẽ làm tròn hướng tới giá trị tuyệt đối nhỏ nhất.

-5 / 2 = -2
 5 / 2 =  2

Đối với các giá trị được ký không dấu và không âm, điều này giống như sàn (làm tròn theo hướng -Infality).


43
Cắt ngắn, không sàn.
dan04

9
@ dan04: sàn sẽ chỉ có hiệu lực đối với số nguyên dương :)
Leonid

13

Kết quả sẽ luôn là sàn của bộ phận?

Không. Kết quả khác nhau, nhưng biến thể chỉ xảy ra đối với các giá trị âm.

Hành vi được xác định là gì?

Để làm cho nó rõ ràng làm tròn các vòng về phía vô cực âm, trong khi phép chia số nguyên làm tròn về 0 (cắt ngắn)

Đối với các giá trị tích cực, chúng giống nhau

int integerDivisionResultPositive= 125/100;//= 1
double flooringResultPositive= floor(125.0/100.0);//=1.0

Đối với giá trị âm, điều này là khác

int integerDivisionResultNegative= -125/100;//=-1
double flooringResultNegative= floor(-125.0/100.0);//=-2.0

0

Tôi biết mọi người đã trả lời câu hỏi của bạn nhưng theo thuật ngữ giáo dân:

5 / 2 = 2 // vì cả 5 và 2 là số nguyên và phép chia số nguyên luôn cắt các số thập phân

5.0 / 2 or 5 / 2.0 or 5.0 /2.0 = 2.5 // ở đây 5 hoặc 2 hoặc cả hai đều có số thập phân do đó thương số bạn sẽ nhận được sẽ ở dạng thập phân.

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.