Python'da float'ı tamsayıya dönüştürmenin en güvenli yolu?


216

Python'un matematik modülü floor& gibi kullanışlı fonksiyonlar içerir ceil. Bu işlevler bir kayan nokta sayısı alır ve en yakın tamsayıyı altına veya üstüne döndürür. Ancak bu işlevler cevabı kayan nokta sayısı olarak döndürür. Örneğin:

import math
f=math.floor(2.3)

Şimdi fdöner:

2.0

Yuvarlama hataları riski olmadan (örneğin şamandıra 1.99999'a eşdeğerse) bu şamandıranın tamsayısını almanın en güvenli yolu nedir veya belki de başka bir işlevi tamamen kullanmalıyım?


7
math.floor v2.6'da bir kayan nokta döndürür , ancak v3'te bir tam sayı döndürür . Bu noktada (OP'den yaklaşık altı yıl sonra), bu sorun nadiren ortaya çıkabilir.
sancho.s ReinstateMonicaCellio

ancak numpy hala float döndürür, bu yüzden soru geçerlidir.
Vincenzooo

Yanıtlar:


178

Kayan nokta sayıları ile temsil edilebilecek tüm tamsayıların tam bir temsili vardır. Böylece intsonuç üzerinde güvenle kullanabilirsiniz . Hatalı gösterimler, yalnızca iki payda olmayan bir payda ile rasyonel bir sayıyı temsil etmeye çalışıyorsanız ortaya çıkar.

Bunun işe yaraması hiç de önemsiz değil! Söz konusu sayıların büyüklüğü yeterince küçükse, IEEE kayan nokta gösteriminin bir özelliğidir, ancak int (kat (2.3)) 1 olabileceği yerlerde farklı gösterimler mümkündür.

Wikipedia'dan alıntı yapmak için ,

Mutlak değeri 2 24'e eşit veya daha düşük olan herhangi bir tam sayı, tek duyarlık biçiminde tam olarak temsil edilebilir ve mutlak değeri 2 53'e eşit veya daha düşük olan herhangi bir tam sayı , çift duyarlık biçiminde tam olarak temsil edilebilir.


8
Biraz daha derine inmek için +1. Ayrıca nedenine ilişkin kısa bir açıklama da yapabilirsiniz: en.wikipedia.org/wiki/Floating_point : D
Gordon Gustafson

Python 2'de "int", C "int" ile aynıdır. Python 3'te, "int, stackoverflow.com/questions/13795758/… " boyutuyla ilgili bir sınırlama yok gibi görünüyor . "İnt" nin anlamı, işletim sistemine ve temeldeki donanıma da bağlıdır. Bkz. En.wikipedia. org / wiki / 64-bit_computing # 64-bit_data_models C-API, python 3 ile programlama yapıyorsanız, platformunuzda long ve size_t tanımının ne olduğuna çok dikkat etmelisiniz. docs.python.org/3 /c-api/long.html
Juan

113

Kullanım int(your non integer number)çivi olacak.

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

4
Bu negatif sayılar için işe yaramaz: flooraşağı intyuvarlar, 0'a yuvarlar.
jochen

1
@jochen int(-2.3)Python dağıtım Canopy 2.7.6'da test ettim ve -2beklediğim gibi aldım . Tamsayı sayıları resmi Matematik tanımında olduğu gibi negatif olabilir.
srodriguex

5
Kabul ediyorum, int(-2.3)verir -2dediğiniz gibi o doğru yuvarlar, çünkü 0, yani bu durumda yukarı. Buna karşılık, math.floorher zaman aşağı yuvarlanan orijinal soru kullanılır : math.floor(-2.3)verir -3.0.
jochen

1
Bu gerçekten bir sorun değil. OP sadece sonucundan bir tamsayı istiyor math.floorve bu cevap bir şamandıranın tamsayıya nasıl dönüştürüleceğini gösteriyor. Şamandırayı alın math.floorve boru ile intsorun çözüldü:int(math.floor(2.3))
JMTyler

4
Soruyu bile okudun mu? İnt () işlevinin farkındadır , ancak 2.0 yerine 1.9999 ile sorun yaşayabileceğinizi sordu. Cevabınız bir cevaba hiç yakın değil, tüm noktayı kaçırdınız ...
Mayou36

48

Yuvarlak fonksiyonunu kullanabilirsiniz. İkinci parametre (anlamlı basamak sayısı) kullanmazsanız, istediğiniz davranışı elde edeceğinizi düşünüyorum.

IDLE çıkışı.

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

28
rounden azından Python 2.6'da da bir kayan sayı döndürür.
Philipp

8
Python 3.1.2'de, yuvarlak bir int döndürür.
robert

2
Gerçekten de, hem roundve floorPython 3.x dönüş tamsayılar Bu yüzden sorunun Python 2.x ile ilgili olduğunu düşünüyorum.
Philipp

4
öyleyse belki int(round(2.65))?
teewuane

1
neden round(6.5)6 veriyor? Diğer tüm durumlarda ondalıktan ceil()hemen sonra 5 (veya 9'a kadar) olduğunda şamandıra gibi görünüyor . Bu neden bu durumda çalışmıyor? ya da sayı altı ile bitiyor ve
ondalıktan

43

Önceki sonuçlardan ikisini birleştirdiğimizde:

int(round(some_float))

Bu, bir şamandırayı oldukça güvenilir bir tam sayıya dönüştürür.


Çok uzun bir şamandıra yuvarlamaya çalışırsanız ne olur? Bu en azından bir istisna getirecek mi?
Agostino

@Agostino Ne demek "çok uzun şamandıra"?
kralyk

@kralyk Yani floatnormalin inttutabileceğinden daha büyük bir sayıyı temsil ediyordum . Python 2'de, floatyalnızca long(yuvarlamadan sonra) kullanarak temsil edebileceğiniz değerler var mı ?
Agostino

@kralyk, turdan sonra mı demek istiyorsun? Peki, onları istisna oluşturmak mı yoksa sadece kısaltmak mı?
Agostino

@Agostino Hayır, int()fonksiyon gerekeni temel alan bir intya da bir longtemel üretir ...
kralyk

18

Bunun işe yaraması hiç de önemsiz değil! Söz konusu sayıların büyüklüğü yeterince küçükse, IEEE kayan nokta gösteriminin bir özelliğidir, ancak int (kat (2.3)) 1 olabileceği yerlerde farklı gösterimler mümkündür.

Bu yazı neden bu aralıkta çalıştığını açıklıyor .

Bir çiftte, 32bit tam sayıları sorunsuz olarak temsil edebilirsiniz. Orada olamaz herhangi yuvarlama sorunları olabilir. Daha kesin olarak, çiftler, 2 53 ve -2 53 arasındaki ve arasındaki tüm tam sayıları temsil edebilir .

Kısa açıklama : Bir çift 53 adede kadar ikili rakam saklayabilir. Daha fazlasına ihtiyacınız olduğunda, sayı sağda sıfırlarla doldurulur.

53 adetin dolgu olmadan saklanabilecek en büyük sayı olduğu anlaşılmaktadır. Doğal olarak, daha az hane gerektiren tüm (tamsayı) sayılar doğru bir şekilde saklanabilir.

111'e (atlanmış) 111 (53 olanlar) eklenmesi 100 ... 000, (53 sıfır) verir. Bildiğimiz gibi, en sağdaki sıfır dolguyu yapan 53 basamak saklayabiliriz.

2 53 buradan geliyor.


Daha fazla detay: IEEE-754 kayan noktasının nasıl çalıştığını düşünmemiz gerekir.

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

Daha sonra sayı aşağıdaki gibi hesaplanır (burada alakasız olan özel durumlar hariç):

-1 işareti × 1.mantissa × 2 üs - önyargı

burada yanlılık = 2 üs - 1 - 1 , yani çift / tek kesinlik için sırasıyla 1023 ve 127.

2 X ile çarpmanın tüm X bitlerini sola kaydırdığını bilerek, herhangi bir tamsayının mantis içinde ondalık noktasının sağına kadar biten tüm bitlere sahip olması gerektiğini görmek kolaydır.

Sıfır dışında herhangi bir tam sayı ikili olarak aşağıdaki forma sahiptir:

1x ... x burada x -es, MSB'nin sağındaki bitleri temsil eder (en önemli bit).

Sıfırı hariç tuttuğumuz için, her zaman bir MSB olacaktır - bu yüzden depolanmaz. Tamsayıyı saklamak için, yukarıda belirtilen forma getirmeliyiz: -1 işaretiTamsayıyı × 1.mantissa × 2 üs - sapma .

Bu, MSB'nin soluna doğru yalnızca MSB olana kadar bitleri ondalık noktaya kaydırmakla aynı şeydir. Ondalık noktasının sağındaki tüm bitler mantis içinde saklanır.

Bundan, MSB dışında en fazla 52 ikili basamak depolayabildiğimizi görebiliriz.

Tüm bitlerin açıkça saklandığı en yüksek sayının

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

Bunun için üssü, ondalık nokta 52 basamak kaydırılacak şekilde ayarlamamız gerekir. Üst üssü bir arttırırsak, ondalık noktadan sonraki sağdaki rakamı bilemeyiz.

111(omitted)111x.

Kural olarak, 0'dır. Tüm mantisin sıfıra ayarlanması, aşağıdaki sayıyı alırız:

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

Bu 1'i takiben 53 sıfır, 52'si depolanmış ve 1'i üs nedeniyle eklenmiştir.

Aralarında tüm tamsayıları doğru bir şekilde temsil edebileceğimiz (hem negatif hem de pozitif) sınırı işaret eden 2 53'ü temsil eder. Birini 2 53'e eklemek isteseydik , örtük sıfırı (ile gösterilir x) birine ayarlamamız gerekirdi , ama bu imkansız.


8

math.floorher zaman bir tam sayı döndürür ve böylece int(math.floor(some_float))yuvarlama hataları oluşturmaz.

Yuvarlama hatası math.floor(some_large_float), ilk etapta bir şamandırada çok sayıda saklanırken bile olsa ortaya çıkmış olabilir . (Büyük sayılar şamandıralarda saklandığında hassasiyeti kaybedebilir.)


7
Kimden: docs.python.org/2/library/math.html - math.floor (x) - x'in tabanını bir kayan nokta olarak, x'den küçük veya ona eşit en büyük tamsayı değeri olarak döndür.
Bill Rosmus

İnt zaten aynı şeyi yaptığında neden math.floor'u çağırmanız gerekiyor?
Alex

1
@Alex: intve floornegatif sayılar için elbette farklı değerler döndürür.

8

Bir dize kayan noktasını int'e dönüştürmeniz gerekirse bu yöntemi kullanabilirsiniz.

Örnek: '38.0'-38

Bu bir int dönüştürmek için bir float sonra bir int olarak döküm yapabilirsiniz. Bu ayrıca kayan dizgiler veya tamsayı dizgiler için de çalışır.

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

Not : Bu, ondalık basamaktan sonraki tüm sayıları çıkarır.

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

1

Değişkenleri kullanarak bir real / float değerini tamsayıya dönüştüren başka bir kod örneği. "vel" gerçek / kayan sayıdır ve bir sonraki en yüksek INTEGER "newvel" e dönüştürülür.

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

'En güvenli' yolu istediğin için, en iyi cevaptan başka bir cevap daha vereceğim.

Herhangi bir hassasiyeti kaybetmediğinizden emin olmanın kolay bir yolu, değerleri dönüştürdükten sonra değerlerin eşit olup olmadığını kontrol etmektir.

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

Eğer şamandıra 1.0 ise, 1.0 1'e eşittir. Bu nedenle int'e dönüşüm gerçekleştirilecektir. Ve şamandıra 1.1 ise, int (1.1) 1 ve 1.1! = 1'e eşittir. Böylece değer bir şamandıra olarak kalır ve herhangi bir hassasiyeti kaybetmezsiniz.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.