Tại sao các phép toán math.ceil () và math.floor () của Python trả lại số float thay vì số nguyên?


170

Ai đó có thể giải thích điều này (trực tiếp từ tài liệu - nhấn mạnh của tôi):

math.ceil (x) Trả về trần của x dưới dạng float , giá trị nguyên nhỏ nhất lớn hơn hoặc bằng x.

math.floor (x) Trả về sàn của x dưới dạng float , giá trị nguyên lớn nhất nhỏ hơn hoặc bằng x.

Tại sao .ceil.floortrả lại số float khi theo định nghĩa được cho là để tính các số nguyên?


BIÊN TẬP:

Vâng điều này có một số lập luận rất tốt là tại sao họ nên quay trở lại nổi, và tôi đã chỉ làm quen với ý tưởng, khi @jcollado chỉ ra rằng họ thực sự làm ints trở lại trong Python 3 ...


1
Tôi đoán là bởi vì x là số float, không phải là số nguyên, nhưng vì tôi không biết hoặc sử dụng Python, tôi sẽ để người khác trả lời dứt khoát hơn. :)
Adam V

6
@ Adam- nhưng toàn bộ hoạt động của trần / sàn là làm tròn số phao cho số nguyên!
Yarin

1
Điều này cũng làm tôi khó chịu khi lần đầu tiên tôi bắt gặp nó, bởi vì nó có vẻ sai. Ít nhất, nó không quá khó để sử dụng int(floor(n)).
wim

1
Trớ trêu thay (vì phao được sử dụng để ngăn tràn), giá trị được trả về bởi sàn / trần là vô nghĩa trong các chữ số thấp vì biểu diễn nổi, trước khi int 64 bit sẽ tràn. [Điều này không đúng trong những ngày cũ của 32 bit.]
Yves Daoust

Câu trả lời:


99

Phạm vi số dấu phẩy động thường vượt quá phạm vi số nguyên. Bằng cách trả về giá trị dấu phẩy động, các hàm có thể trả về giá trị hợp lý cho các giá trị đầu vào nằm ngoài phạm vi số nguyên có thể biểu thị.

Xem xét: Nếu floor()trả về một số nguyên, cái gì sẽ floor(1.0e30)trả về?

Bây giờ, trong khi các số nguyên của Python bây giờ có độ chính xác tùy ý, thì không phải lúc nào cũng như vậy. Các chức năng thư viện tiêu chuẩn là các hàm bao quanh mỏng xung quanh các chức năng thư viện C tương đương.


13
Và mặc dù số nguyên Python bây giờ có độ chính xác tùy ý, vẫn có những số nổi mà sàn và trần không thể được biểu thị bằng số nguyên. Hãy thử floor(float("inf"))hoặc ceil(float("nan")).
Michael Hoffman

4
@ Michael- Rõ ràng trong P3 bây giờ bạn sẽ nhận được OverflowExceptions nếu bạn thử điều đó. Xem câu trả lời của jcollado
Yarin

4
Er, nó sẽ trả về một loại 'dài' (còn gọi là 'bigint'), phải không? Có vẻ như một câu trả lời rõ ràng cho tôi, nhưng bây giờ tôi cảm thấy như mình đang ngây thơ bằng cách nào đó.
koschei

3
@koschei: Nó có trong Python 3.x, xem câu trả lời của jcollado.
Greg Hewgill

Xem thêm một bình luận cho một câu trả lời khác tại sao điều này có ý nghĩa ngay cả đối với các số trong phạm vi.
ivan_pozdeev

96

Như được chỉ ra bởi các câu trả lời khác, trong python họ trả lại phao có lẽ vì lý do lịch sử để ngăn chặn các vấn đề tràn. Tuy nhiên, họ trả về số nguyên trong python 3.

>>> import math
>>> type(math.floor(3.1))
<class 'int'>
>>> type(math.ceil(3.1))
<class 'int'>

Bạn có thể tìm thêm thông tin trong PEP 3141 .


@ jcollado- Bạn thấy họ trả về số nguyên trong P3 ở đâu?
Yarin

4
@Yarin Mình mới gõ các lệnh trên. Ngoài ra nếu bạn thử với float("inf")hoặc float("nan"), bạn sẽ nhận được một OverflowErrorngoại lệ.
jcollado

10
Để hoàn thiện, Python numpy.floorceilfloat float (<class 'numpy.float64'>)
Neil G

1
@jcollado: float("inf")không tạo ra ngoại lệ trong Python 2.7 hoặc 3
endolith

1
@endolith Bạn nói đúng, tôi đã kiểm tra điều đó và nó không còn xảy ra nữa. Có lẽ đó là thứ đã được thay đổi kể từ tháng 12 năm 2011
jcollado

18

Nguồn gốc của sự nhầm lẫn của bạn là rõ ràng trong bình luận của bạn:

Toàn bộ quan điểm của hoạt động trần / sàn là để chuyển đổi phao thành số nguyên!

Điểm của các hoạt động trần và sàn là làm tròn dữ liệu điểm nổi thành các giá trị tích phân . Không thực hiện chuyển đổi loại. Người dùng cần nhận giá trị nguyên có thể thực hiện chuyển đổi rõ ràng sau thao tác.

Lưu ý rằng sẽ không thể thực hiện một giá trị tròn thành tích phân như một cách tầm thường nếu tất cả những gì bạn có sẵn là một hoạt động trần hoặc float trả về một số nguyên. Trước tiên, bạn cần kiểm tra xem đầu vào có nằm trong phạm vi số nguyên có thể biểu diễn hay không, sau đó gọi hàm; bạn sẽ cần xử lý NaN và vô cực trong một đường dẫn mã riêng.

Ngoài ra, bạn phải có các phiên bản trần và sàn trả về số dấu phẩy động nếu bạn muốn tuân thủ theo tiêu chuẩn IEEE 754 .


Stephen- Tôi viết lại nhận xét của mình- Tôi có nghĩa là tròn, không chuyển đổi. Nhưng đó không phải là nguồn gốc của sự nhầm lẫn của tôi - đúng hơn là tôi đã không nhận ra sự chênh lệch phạm vi.
Yarin

Đáng buồn thay, tôi đã hết phiếu ngày hôm nay. Đây là câu trả lời chính xác, nhiều hơn bất kỳ giới hạn nào của việc đại diện.
Marcin

13
Trong những năm lập trình của mình, tôi không nhớ mình đã từng gặp phải tình huống mà tôi muốn kết quả của sàn / trần là một hình nổi thay vì số nguyên. Thực tế là python3 không trả về số nguyên cho thấy rằng trên thực tế đây là điều hữu ích hơn để làm. Tôi không mua yêu cầu "quan điểm của ..."; có vẻ như bạn đang xác định điểm dựa trên những gì nó làm, hơn là những gì lập trình viên có thể muốn.
ShreevatsaR

2
@ShreevatsaR Tôi đã gặp tình huống đó một vài lần (tuy nhiên, chủ yếu là bên ngoài bối cảnh Python). Những lần tôi nhớ là khi làm việc với bộ Mandelbrot. Đôi khi bạn cần tạo một giá trị tích phân, nhưng sau đó áp dụng một số thao tác dấu phẩy động cho giá trị ngay sau đó (giả sử tỷ lệ của nó bằng 0,5). Sau đó, sẽ hiệu quả hơn nhiều khi giữ phao nổi và áp dụng thao tác điểm nổi cho nó so với trước tiên chuyển đổi nó thành int và sau đó ngay lập tức chuyển đổi nó trở lại nổi.
blubberdiblub

17

Bởi vì thư viện toán học của python là một trình bao bọc mỏng xung quanh thư viện toán học C trả về số float.


Thư viện toán C có hỗ trợ số nguyên chính xác tùy ý? Bởi vì đó là những gì các hàm toán học python khác trả về.
endolith

5

Trước Python 2.4, một số nguyên không thể chứa toàn bộ các số thực bị cắt cụt.

http://docs.python.org/whatsnew/2.4.html#pep-237-unifying-long-integers-and-integers


2
Hiện tại, nó không thể giữ "toàn bộ số thực bị cắt ngắn", bởi vì đó rõ ràng là một tập hợp vô hạn và do đó sẽ cần một lượng bộ nhớ vô hạn. Nó có thể chứa phạm vi của các phao cắt ngắn , nhưng chỉ là một tập con nhỏ của.
leftaroundabout

6
@leftaroundabout - kén chọn! Bạn biết ý tôi là gì
Đánh dấu tiền chuộc

4

Bởi vì phạm vi cho số float lớn hơn số nguyên - trả về một số nguyên có thể tràn


7
Các số nguyên không tràn vào Python; số nguyên của nó chuyển đổi thành bigint khi chúng trở nên quá lớn. Mở trình thông dịch Python và gõ "2 ** 500" và bạn sẽ thấy rằng bạn có một đối tượng bạn có thể xử lý theo mọi cách như int.
koschei

@koschei: Ngay cả những dấu hiệu lớn cũng tràn ra khi cố gắng thể hiện sự vô hạn.
Stephen Canon

4

Đây quả là một câu hỏi thú vị! Vì một số float yêu cầu một số bit để lưu trữ số mũ (= bits_for_exponent) bất kỳ số dấu phẩy động nào lớn hơn 2**(float_size - bits_for_exponent)sẽ luôn là một giá trị tích phân! Ở một thái cực khác, một số float với số mũ âm sẽ cho một 1, 0hoặc -1. Điều này làm cho các cuộc thảo luận về phạm vi số nguyên so với phạm vi di chuyển bởi vì các hàm này sẽ chỉ trả về số gốc bất cứ khi nào số nằm ngoài phạm vi của loại số nguyên. Các hàm python là các hàm bao của Chàm và vì vậy đây thực sự là một thiếu sót của các Chàm trong đó chúng phải trả về một số nguyên và buộc lập trình viên phải thực hiện phạm vi / NaN/Inf kiểm tra trước khi gọi trần / sàn.

Do đó, câu trả lời hợp lý là lần duy nhất các hàm này hữu ích, chúng sẽ trả về một giá trị trong phạm vi số nguyên và vì vậy thực tế chúng trả về một số float là một sai lầm và bạn rất thông minh khi nhận ra điều này!


1

Có thể vì các ngôn ngữ khác cũng làm điều này, nên nó thường được chấp nhận. (Vì những lý do chính đáng, như thể hiện trong các câu trả lời khác)


Hay những gì Charles nói. :)
Almo
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.