Cách an toàn nhất để chuyển đổi float thành số nguyên trong python?


215

Mô-đun toán học của Python chứa các hàm tiện dụng như floor& ceil. Các hàm này lấy một số dấu phẩy động và trả về số nguyên gần nhất bên dưới hoặc bên trên nó. Tuy nhiên, các hàm này trả về câu trả lời dưới dạng số dấu phẩy động. Ví dụ:

import math
f=math.floor(2.3)

Bây giờ ftrả lại:

2.0

Cách an toàn nhất để lấy số nguyên ra khỏi số float này, mà không gặp rủi ro làm tròn lỗi (ví dụ: nếu float tương đương với 1.99999) hoặc có lẽ tôi nên sử dụng chức năng khác hoàn toàn?


7
math.floor trả về một float trong v2.6 , nhưng nó trả về một số nguyên trong v3 . Tại thời điểm này (gần sáu năm sau OP), vấn đề này có thể hiếm khi xuất hiện.
sancho.s RebstateMonicaCellio

tuy nhiên numpy vẫn trả về float, vì vậy câu hỏi là hợp lệ.
Vincenzooo

Câu trả lời:


178

Tất cả các số nguyên có thể được biểu thị bằng số dấu phẩy động có biểu diễn chính xác. Vì vậy, bạn có thể sử dụng một cách an toàn inttrên kết quả. Các biểu diễn không chính xác chỉ xảy ra nếu bạn đang cố gắng biểu diễn một số hữu tỷ bằng mẫu số không phải là lũy thừa của hai.

Rằng công việc này không hề nhỏ chút nào! Đây là một thuộc tính của biểu diễn dấu phẩy động của IEEE mà intorfloor = ⌊⋅⌋ nếu độ lớn của các số trong câu hỏi đủ nhỏ, nhưng các cách biểu diễn khác nhau có thể xảy ra trong đó int (floor (2.3)) có thể là 1.

Để trích dẫn từ Wikipedia ,

Bất kỳ số nguyên nào có giá trị tuyệt đối nhỏ hơn hoặc bằng 2 24 đều có thể được biểu diễn chính xác theo định dạng chính xác duy nhất và bất kỳ số nguyên nào có giá trị tuyệt đối nhỏ hơn hoặc bằng 2 53 đều có thể được biểu diễn chính xác theo định dạng chính xác kép.


8
+1 để đi sâu hơn một chút. Bạn cũng có thể giải thích ngắn gọn về lý do tại sao: en.wikipedia.org/wiki/Floating_point : D
Gordon Gustafson

Trong Python 2, một "int" giống như C "int". Trong Python 3, dường như không có giới hạn về kích thước của "int, stackoverflow.com/questions/13795758/ . Ý nghĩa của" int "cũng phụ thuộc vào hệ điều hành và phần cứng cơ bản. Xem en.wikipedia. org / wiki / 64-bit_computing # 64-bit_data_models . Nếu bạn đang lập trình với C-API, python 3 bạn phải rất cẩn thận trong định nghĩa dài và size_t trên nền tảng của bạn. docs.python.org/3 /c-api/long.html
Juan

112

Sử dụng int(your non integer number)sẽ đóng đinh nó.

print int(2.3) # "2"
print int(math.sqrt(5)) # "2"

4
Điều này sẽ không hoạt động đối với các số âm: làm floortròn xuống trong khi làm inttròn về 0.
jochen

1
@jochen Tôi đã thử nghiệm int(-2.3)trong phân phối Python Canopy 2.7.6 và nhận được -2như mong đợi. Số nguyên có thể là số âm, giống như cách định nghĩa Toán chính thức.
srodriguex

5
Tôi đồng ý, int(-2.3)đưa ra -2như bạn nói, bởi vì nó làm tròn hướng tới 0, tức là trong trường hợp này. Ngược lại, câu hỏi ban đầu được sử dụng math.floor, luôn luôn làm tròn: math.floor(-2.3)đưa ra -3.0.
jochen

1
Đó không thực sự là một vấn đề. OP chỉ muốn một số nguyên ra khỏi kết quả math.floorvà câu trả lời này cho thấy cách chuyển đổi một số float thành một số nguyên. Lấy phao từ math.floorvà dẫn nó qua int, vấn đề đã được giải quyết:int(math.floor(2.3))
JMTyler

4
Bạn thậm chí đã đọc câu hỏi? Anh ta nhận thức được hàm int () , nhưng đã hỏi liệu bạn có thể gặp rắc rối với 1.9999 thay vì 2.0 không. Câu trả lời của bạn thậm chí không gần với câu trả lời nào cả, bạn đã bỏ lỡ toàn bộ vấn đề ...
Mayou36

48

Bạn có thể sử dụng chức năng tròn. Nếu bạn không sử dụng tham số thứ hai (# chữ số có nghĩa) thì tôi nghĩ bạn sẽ có được hành vi bạn muốn.

Đầu ra IDLE.

>>> round(2.99999999999)
3
>>> round(2.6)
3
>>> round(2.5)
3
>>> round(2.4)
2

28
roundcũng trả về một số float, ít nhất là trong Python 2.6.
Phi

8
Trong Python 3.1.2, vòng trả về một int.
robert

2
Thật vậy, cả hai roundfloortrả về số nguyên trong Python 3.x. Vì vậy, tôi cho rằng câu hỏi liên quan đến Python 2.x.
Phi

4
vậy có lẽ int(round(2.65))nào
teewuane

1
Tại sao lại round(6.5)cho 6? Nó dường như ceil()nổi lên khi có 5 ngay lập tức (hoặc lớn hơn đến 9) sau số thập phân trong tất cả các trường hợp khác. Tại sao điều này không làm việc trong trường hợp này? hoặc bất kỳ trường hợp nào khác khi số kết thúc bằng số sáu và có 5 ngay sau số thập phân ...
candh

43

Kết hợp hai trong số các kết quả trước đó, chúng tôi có:

int(round(some_float))

Điều này chuyển đổi một float thành một số nguyên khá phụ thuộc.


Điều gì xảy ra nếu bạn cố gắng làm tròn một phao rất dài? Điều này ít nhất sẽ đưa ra một ngoại lệ?
Agostino

@Agostino Ý bạn là "phao rất dài" là gì?
kralyk

@kralyk Ý tôi là một floatđại diện cho một con số lớn hơn những gì một người bình thường intcó thể nắm giữ. Trong Python 2, có floatcác giá trị mà bạn chỉ có thể biểu thị bằng cách sử dụng long(sau khi làm tròn) không?
Agostino

@kralyk Ý bạn là, sau vòng đấu? Vì vậy, sẽ đúc chúng để int đưa ra một ngoại lệ, hoặc chỉ cắt bớt chúng?
Agostino

@Agostino Không, int()chức năng này tạo ra một inthoặc longdựa trên những gì cần thiết ...
kralyk

18

Rằng công việc này không hề nhỏ chút nào! Đây là một thuộc tính của biểu diễn dấu phẩy động của IEEE mà intorfloor = ⌊⋅⌋ nếu độ lớn của các số trong câu hỏi đủ nhỏ, nhưng các cách biểu diễn khác nhau có thể xảy ra trong đó int (floor (2.3)) có thể là 1.

Bài đăng này giải thích tại sao nó hoạt động trong phạm vi đó .

Trong một đôi, bạn có thể đại diện cho số nguyên 32 bit mà không có bất kỳ vấn đề. Không thể có bất kỳ vấn đề làm tròn. Chính xác hơn, nhân đôi có thể đại diện cho tất cả các số nguyên giữa và bao gồm 2 53-2 53 .

Giải thích ngắn : Một đôi có thể lưu trữ tới 53 chữ số nhị phân. Khi bạn yêu cầu nhiều hơn, số được đệm bằng số 0 ở bên phải.

Theo sau đó, 53 cái là số lớn nhất có thể được lưu trữ mà không cần đệm. Đương nhiên, tất cả các số (số nguyên) yêu cầu ít chữ số hơn có thể được lưu trữ chính xác.

Thêm một vào 111 (bỏ qua) 111 (53 cái) sẽ mang lại 100 ... 000, (53 số không). Như chúng ta biết, chúng ta có thể lưu trữ 53 chữ số, điều đó làm cho phần đệm bằng không bên phải.

Đây là nơi 2 53 đến từ.


Chi tiết hơn: Chúng ta cần xem xét cách thức hoạt động của dấu phẩy động IEEE-754.

  1 bit    11 / 8     52 / 23      # bits double/single precision
[ sign |  exponent | mantissa ]

Số này sau đó được tính như sau (không bao gồm các trường hợp đặc biệt không liên quan ở đây):

-1 ký hiệu × 1.mantissa × 2 số mũ - sai lệch

trong đó bias = 2 số mũ - 1 - 1 , tức là 1023 và 127 cho độ chính xác kép / đơn tương ứng.

Biết rằng nhân với 2 X chỉ đơn giản là dịch chuyển tất cả các bit X sang trái, dễ dàng nhận thấy rằng bất kỳ số nguyên nào cũng phải có tất cả các bit trong lớp phủ cuối cùng bên phải của dấu thập phân về 0.

Bất kỳ số nguyên nào trừ 0 đều có dạng sau trong nhị phân:

1x ... x trong đó x -es đại diện cho các bit ở bên phải của MSB (bit quan trọng nhất).

Bởi vì chúng tôi đã loại trừ 0, sẽ luôn có một MSB là một đơn vị, đó là lý do tại sao nó không được lưu trữ. Để lưu trữ số nguyên, chúng ta phải đưa nó vào dạng đã nói ở trên: -1 ký hiệu × 1.mantissa × 2 số mũ - độ lệch .

Điều đó nói giống như việc dịch chuyển các bit qua dấu thập phân cho đến khi chỉ còn MSB về phía bên trái của MSB. Tất cả các bit bên phải của dấu thập phân sau đó được lưu trữ trong lớp phủ.

Từ điều này, chúng ta có thể thấy rằng chúng ta có thể lưu trữ tối đa 52 chữ số nhị phân ngoài MSB.

Theo sau đó, số cao nhất trong đó tất cả các bit được lưu trữ rõ ràng là

111(omitted)111.   that's 53 ones (52 + implicit 1) in the case of doubles.

Đối với điều này, chúng ta cần đặt số mũ, sao cho dấu thập phân sẽ được dịch chuyển 52 vị trí. Nếu chúng ta tăng số mũ lên một, chúng ta không thể biết chữ số bên phải sau dấu thập phân.

111(omitted)111x.

Theo quy ước, nó là 0. Đặt toàn bộ lớp phủ về 0, chúng tôi nhận được số sau:

100(omitted)00x. = 100(omitted)000.

Đó là số 1 theo sau là 53 số 0, 52 được lưu và 1 được thêm vào do số mũ.

Nó đại diện cho 2 53 , đánh dấu ranh giới (cả âm và dương) giữa chúng ta có thể biểu diễn chính xác tất cả các số nguyên. Nếu chúng ta muốn thêm một đến 2 53 , chúng ta sẽ phải đặt số 0 ẩn (ký hiệu là x) thành một, nhưng điều đó là không thể.


8

math.floorsẽ luôn trả về một số nguyên và do đó int(math.floor(some_float))sẽ không bao giờ đưa ra các lỗi làm tròn.

Tuy nhiên, lỗi làm tròn có thể đã được đưa vào math.floor(some_large_float)hoặc ngay cả khi lưu trữ một số lượng lớn trong một số float ở vị trí đầu tiên. (Số lượng lớn có thể mất độ chính xác khi được lưu trữ trong phao.)


7
Từ: docs.python.org/2/library/math.html - Math.floor (x) - Trở về sàn của x như một phao, giá trị số nguyên lớn nhất nhỏ hơn hoặc bằng với x.
Bill Rosmus

Tại sao bạn cần phải gọi math.floor khi int đã làm điều tương tự?
Alex

1
@Alex: intfloortrả về các giá trị khác nhau cho các số âm, tất nhiên.

8

Nếu bạn cần chuyển đổi một chuỗi float thành int, bạn có thể sử dụng phương thức này.

Ví dụ: '38.0'để38

Để chuyển đổi nó thành int, bạn có thể sử dụng nó như một float sau đó là int. Điều này cũng sẽ làm việc cho chuỗi float hoặc chuỗi số nguyên.

>>> int(float('38.0'))
38
>>> int(float('38'))
38

Lưu ý : Điều này sẽ tước bất kỳ số nào sau số thập phân.

>>> int(float('38.2'))
38

1

Một mẫu mã khác để chuyển đổi một số thực / float thành một số nguyên bằng các biến. "Vel" là số thực / số float và được chuyển đổi thành INTEGER cao nhất tiếp theo, "newvel".

import arcpy.math, os, sys, arcpy.da
.
.
with arcpy.da.SearchCursor(densifybkp,[floseg,vel,Length]) as cursor:
 for row in cursor:
    curvel = float(row[1])
    newvel = int(math.ceil(curvel))

0

Vì bạn đang hỏi cách 'an toàn nhất', tôi sẽ cung cấp một câu trả lời khác ngoài câu trả lời hàng đầu.

Một cách dễ dàng để đảm bảo bạn không mất bất kỳ độ chính xác nào là kiểm tra xem các giá trị có bằng nhau không sau khi bạn chuyển đổi chúng.

if int(some_value) == some_value:
     some_value = int(some_value)

Nếu float là 1.0 chẳng hạn, 1.0 bằng 1. Vì vậy, việc chuyển đổi thành int sẽ thực hiện. Và nếu số float là 1.1, int (1.1) tương đương với 1 và 1.1! = 1. Vì vậy, giá trị sẽ vẫn là float và bạn sẽ không mất bất kỳ độ chính xác nào.


0

df ['Cột_Name'] = df ['Cột_Name']. astype (int)


Một lời giải thích cho câu trả lời của bạn đi một chặng đường dài.
bibliophilsagar
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.