Cara teraman untuk mengkonversi float ke integer in python?

215

Modul matematika Python berisi fungsi-fungsi praktis seperti floor& ceil. Fungsi-fungsi ini mengambil nomor floating point dan mengembalikan bilangan bulat terdekat di bawah atau di atasnya. Namun fungsi-fungsi ini mengembalikan jawabannya sebagai angka titik mengambang. Sebagai contoh:

import math
f=math.floor(2.3)

Sekarang fkembali:

2.0

Apa cara teraman untuk mendapatkan bilangan bulat dari float ini, tanpa menjalankan risiko kesalahan pembulatan (misalnya jika float setara dengan 1,99999) atau mungkin saya harus menggunakan fungsi lain sama sekali?

Boas
sumber
7
math.floor mengembalikan float di v2.6 , tetapi mengembalikan bilangan bulat di v3 . Pada titik ini (hampir enam tahun setelah OP), masalah ini mungkin jarang muncul.
sancho.s ReinstateMonicaCellio
Namun numpy masih mengembalikan float, jadi pertanyaannya valid.
Vincenzooo

Jawaban:

178

Semua bilangan bulat yang dapat diwakili oleh angka floating point memiliki representasi yang tepat. Jadi Anda bisa menggunakan dengan amanint hasilnya dengan aman. Representasi eksak terjadi hanya jika Anda mencoba untuk mewakili bilangan rasional dengan penyebut yang bukan kekuatan dua.

Bahwa ini bekerja sama sekali tidak sepele! Ini adalah properti dari representasi floating point IEEE yang int∘floor = ⌊⋅⌋ jika besarnya angka yang dimaksud cukup kecil, tetapi representasi yang berbeda dimungkinkan di mana int (lantai (2.3)) mungkin 1.

Mengutip dari Wikipedia ,

Setiap integer dengan nilai absolut kurang dari atau sama dengan 2 24 dapat secara tepat direpresentasikan dalam format presisi tunggal, dan integer apa pun dengan nilai absolut kurang dari atau sama dengan 2 53 dapat secara tepat direpresentasikan dalam format presisi ganda.

Philipp
sumber
8
+1 untuk sedikit lebih dalam. Anda juga bisa memberikan penjelasan singkat mengapa: en.wikipedia.org/wiki/Floating_point : D
Gordon Gustafson
Dalam Python 2, "int" sama dengan C "int". Dalam Python 3, tampaknya tidak ada batasan untuk ukuran "int, stackoverflow.com/questions/13795758/ .... Arti" int "juga tergantung pada sistem operasi dan perangkat keras yang mendasarinya. Lihat en.wikipedia. org / wiki / 64-bit_computing # 64-bit_data_models Jika Anda memprogram dengan C-API, python 3 Anda harus sangat berhati-hati dalam definisi panjang dan size_t pada platform Anda. docs.python.org/3 /c-api/long.html
Juan
112

Gunakan int(your non integer number)akan paku itu.

print int(2.3) # "2"
print int(math.sqrt(5)) # "2"
srodriguex
sumber
4
Ini tidak akan berfungsi untuk angka negatif: floorputaran ke bawah sedangkan intputaran ke arah 0.
jochen
1
@ Joshen Saya diuji int(-2.3)dalam distribusi Python Canopy 2.7.6 dan mendapatkan -2seperti yang diharapkan. Angka integer bisa negatif, dengan cara yang sama dalam definisi Matematika formal.
srodriguex
5
Saya setuju, int(-2.3)memberi -2seperti yang Anda katakan, karena itu bulat ke atas 0, yaitu di dalam kasus ini. Sebaliknya, pertanyaan awal yang digunakan math.floor, yang selalu dibulatkan: math.floor(-2.3)memberi -3.0.
Jochen
1
Itu bukan masalah. OP hanya ingin integer keluar dari hasil math.floor, dan jawaban ini menunjukkan cara mengubah float menjadi integer. Ambil float dari math.floordan pipa melalui int, masalah terpecahkan:int(math.floor(2.3))
JMTyler
4
Apakah Anda bahkan membaca pertanyaannya? Ia mengetahui fungsi int () , tetapi telah menanyakan apakah Anda dapat mengalami masalah dengan 1.9999 alih-alih 2.0. Jawaban Anda bahkan tidak mendekati jawaban sama sekali, Anda melewatkan seluruh intinya ...
Mayou36
48

Anda bisa menggunakan fungsi putaran. Jika Anda tidak menggunakan parameter kedua (# digit signifikan) maka saya pikir Anda akan mendapatkan perilaku yang Anda inginkan.

Output IDLE.

>>> round(2.99999999999)
3
>>> round(2.6)
3
>>> round(2.5)
3
>>> round(2.4)
2
Wade73
sumber
28
roundmengembalikan nomor float juga, setidaknya dalam Python 2.6.
Philipp
8
Dalam Python 3.1.2, round mengembalikan int.
robert
2
Memang, keduanya rounddan floormengembalikan integer dengan Python 3.x. Jadi saya kira pertanyaannya menyangkut Python 2.x.
Philipp
4
jadi mungkin int(round(2.65))?
Teewuane
1
mengapa round(6.5)memberi 6? Tampaknya agak ceil()mengambang ketika ada 5 langsung (atau lebih besar hingga 9) setelah desimal dalam semua kasus lainnya. Mengapa ini tidak berhasil dalam kasus ini? atau kasus lain ketika angka berakhir dengan angka enam dan ada angka 5 tepat setelah desimal ...
candh
43

Menggabungkan dua hasil sebelumnya, kami memiliki:

int(round(some_float))

Ini mengkonversi float ke integer yang cukup dapat diandalkan.

pengguna3763109
sumber
Apa yang terjadi jika Anda mencoba mengitari pelampung yang sangat panjang? Apakah ini setidaknya akan menimbulkan pengecualian?
Agostino
@ Agostino Apa maksudmu "pelampung yang sangat panjang"?
kralyk
@ kyyyk maksud saya floatmewakili angka yang lebih besar dari apa yang intbisa dimiliki orang normal . Dalam Python 2, apakah ada floatnilai yang hanya bisa Anda wakili menggunakan long(setelah pembulatan)?
Agostino
@ kyyk maksudmu, setelah ronde? Jadi, akankah casting mereka untuk meningkatkan pengecualian, atau hanya memotongnya?
Agostino
@ Agostino Tidak, int()fungsi ini menghasilkan suatu intatau longberdasarkan apa yang dibutuhkan ...
kralyk
18

Bahwa ini bekerja sama sekali tidak sepele! Ini adalah properti dari representasi floating point IEEE yang int∘floor = ⌊⋅⌋ jika besarnya angka yang dimaksud cukup kecil, tetapi representasi yang berbeda dimungkinkan di mana int (lantai (2.3)) mungkin 1.

Posting ini menjelaskan mengapa ia bekerja dalam kisaran itu .

Dalam double, Anda dapat mewakili bilangan bulat 32bit tanpa masalah. Ada tidak bisa menjadi masalah pembulatan. Lebih tepatnya, ganda dapat mewakili semua bilangan bulat di antara dan termasuk 2 53 dan -2 53 .

Penjelasan singkat : Double dapat menyimpan hingga 53 digit biner. Ketika Anda membutuhkan lebih banyak, nomor tersebut diisi dengan angka nol di sebelah kanan.

Oleh karena itu, 53 yang merupakan jumlah terbesar yang dapat disimpan tanpa bantalan. Secara alami, semua angka (bilangan bulat) yang membutuhkan lebih sedikit digit dapat disimpan secara akurat.

Menambahkan satu ke 111 (dihilangkan) 111 (53 yang) menghasilkan 100 ... 000, (53 nol). Seperti yang kita tahu, kita dapat menyimpan 53 digit, yang membuat padding nol paling kanan.

Di sinilah 2 53 berasal.


Lebih detail: Kita perlu mempertimbangkan cara kerja floating point IEEE-754.

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

Jumlahnya kemudian dihitung sebagai berikut (tidak termasuk kasus khusus yang tidak relevan di sini):

-1 tanda × 1.mantissa × 2 eksponen - bias

di mana bias = 2 eksponen - 1 - 1 , yaitu 1023 dan 127 untuk presisi ganda / tunggal.

Mengetahui bahwa mengalikan dengan 2 X hanya menggeser semua bit X tempat ke kiri, mudah untuk melihat bahwa setiap bilangan bulat harus memiliki semua bit dalam mantissa yang berakhir tepat dari titik desimal ke nol.

Bilangan bulat apa pun kecuali nol memiliki bentuk berikut dalam biner:

1x ... x di mana x -es mewakili bit di sebelah kanan MSB (bit paling signifikan).

Karena kami mengecualikan nol, akan selalu ada MSB yang satu - yang mengapa tidak disimpan. Untuk menyimpan bilangan bulat, kita harus membawanya ke dalam bentuk yang disebutkan di atas: -1 tanda × 1.mantissa × 2 eksponen - bias .

Itu mengatakan hal yang sama seperti menggeser bit ke titik desimal sampai hanya ada MSB di sebelah kiri MSB. Semua bit tepat dari titik desimal kemudian disimpan dalam mantissa.

Dari sini, kita dapat melihat bahwa kita dapat menyimpan paling banyak 52 digit biner selain dari MSB.

Oleh karena itu jumlah tertinggi di mana semua bit disimpan secara eksplisit adalah

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

Untuk ini, kita perlu mengatur eksponen, sehingga titik desimal akan bergeser 52 tempat. Jika kita ingin meningkatkan eksponen dengan satu, kita tidak dapat mengetahui angka kanan ke kiri setelah titik desimal.

111(omitted)111x.

Dengan konvensi, ini adalah 0. Menetapkan seluruh mantissa ke nol, kami menerima nomor berikut:

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

Itu 1 diikuti oleh 53 nol, 52 disimpan dan 1 ditambahkan karena eksponen.

Ini mewakili 2 53 , yang menandai batas (baik negatif dan positif) di mana kita dapat secara akurat mewakili semua bilangan bulat. Jika kita ingin menambahkan satu ke 2 53 , kita harus menetapkan nol implisit (dilambangkan oleh x) menjadi satu, tetapi itu tidak mungkin.

hantu0m
sumber
8

math.floor akan selalu mengembalikan angka integer dan karenanya int(math.floor(some_float)) tidak akan pernah memperkenalkan kesalahan pembulatan.

Kesalahan pembulatan mungkin sudah diperkenalkan math.floor(some_large_float), meskipun, atau bahkan ketika menyimpan sejumlah besar dalam pelampung di tempat pertama. (Sejumlah besar mungkin kehilangan presisi saat disimpan dalam mengapung.)


sumber
7
Dari: docs.python.org/2/library/math.html - math.floor (x) - Kembalikan lantai x sebagai float, nilai integer terbesar kurang dari atau sama dengan x.
Bill Rosmus
Mengapa Anda perlu melakukan panggilan math.floor ketika int sudah melakukan hal yang sama?
Alex
1
@Alex: intdan floormengembalikan nilai yang berbeda untuk angka negatif, tentu saja.
8

Jika Anda perlu mengkonversi string float ke int, Anda dapat menggunakan metode ini.

Contoh: '38.0' untuk38

Untuk mengonversikannya menjadi int, Anda dapat mengubahnya sebagai float lalu int. Ini juga akan berfungsi untuk string float atau string integer.

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

Catatan : Ini akan menghilangkan nomor apa pun setelah desimal.

>>> int(float('38.2'))
38
brandonbanks
sumber
1

Contoh kode lain untuk mengonversi real / float ke integer menggunakan variabel. "vel" adalah bilangan real / float dan dikonversi ke INTEGER tertinggi berikutnya, "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))
mrichey56
sumber
0

Karena Anda meminta cara 'paling aman', saya akan memberikan jawaban lain selain jawaban teratas.

Cara mudah untuk memastikan Anda tidak kehilangan presisi adalah memeriksa apakah nilainya akan sama setelah Anda mengubahnya.

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

Jika float adalah 1.0 misalnya, 1.0 sama dengan 1. Jadi konversi ke int akan dieksekusi. Dan jika float adalah 1.1, int (1.1) sama dengan 1, dan 1.1! = 1. Jadi nilainya akan tetap float dan Anda tidak akan kehilangan presisi.

Troy H
sumber
0

df ['Column_Name'] = df ['Column_Name']. astype (int)

Niruttara
sumber
Penjelasan untuk jawaban Anda sangat membantu.
bibliophilsagar