Найбезпечніший спосіб перетворення float в ціле число в python?


215

Математичний модуль Python містить зручні функції, такі як floor& ceil. Ці функції приймають номер з плаваючою комою і повертають найближче ціле число під ним або над ним. Однак ці функції повертають відповідь у вигляді числа з плаваючою комою. Наприклад:

import math
f=math.floor(2.3)

Тепер fповертається:

2.0

Який найбезпечніший спосіб вивести ціле число з цього плавця, не ризикуючи помилками округлення (наприклад, якщо float є еквівалентом 1.99999) або, можливо, я повинен взагалі використовувати іншу функцію?


7
math.floor повертає float в v2.6 , але він повертає ціле число в v3 . На даний момент (майже шість років після закінчення програми) ця проблема може з'являтися рідко.
sancho.s ReinstateMonicaCellio

однак numpy все ще повертає float, тому питання справедливе.
Vincenzooo

Відповіді:


178

Усі цілі числа, які можуть бути представлені числами з плаваючою комою, мають точне подання. Тож можна сміливо користуватисяint результат. Неточні уявлення виникають лише у тому випадку, якщо ви намагаєтесь представити раціональне число зі знаменником, який не є силою двох.

Що це працює зовсім не банально! Це властивість представлення IEEE з плаваючою точкою, що int∘floor = ⌊⋅⌋, якщо величина розглянутих чисел невелика, але можливі різні подання там, де int (floor (2.3)) може бути 1.

Цитувати з Вікіпедії ,

Будь-яке ціле число з абсолютним значенням, меншим або рівним 2 24, може бути точно представлено у форматі єдиної точності, і будь-яке ціле число з абсолютним значенням менше або рівне 2 53 може бути точно представлене у форматі подвійної точності.


8
+1 - зайти трохи глибше. Ви також можете навести коротке пояснення, чому: en.wikipedia.org/wiki/Floating_point : D
Гордон Густафсон

У Python 2 "int" - це те саме, що C "int". У Python 3, здається, немає обмеження на розмір "int, stackoverflow.com/questions/13795758/… . Значення" int "також залежить від операційної системи та базового обладнання. Див. En.wikipedia. org / wiki / 64-bit_computing # 64-bit_data_models Якщо ви програмуєте за допомогою C-API, python 3, ви повинні бути дуже обережними в тому, що визначення long і size_t знаходиться на вашій платформі. docs.python.org/3 /c-api/long.html
Хуан

112

Використання int(your non integer number)прибиває це.

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

4
Це не буде працювати для негативних чисел: floorраундів вниз , тоді як intраундів в напрямку 0.
Jochen

1
@jochen Я перевірив int(-2.3)на дистрибуції Python Canopy 2.7.6 і отримав, -2як очікувалося. Цілі числа можуть бути негативними, так само і у формальному математичному визначенні.
srodriguex

5
Я погоджуюсь, int(-2.3)дає, -2як ви говорите, тому що він спрямований 0, тобто в цьому випадку. На противагу цьому використовується оригінальне запитання math.floor, яке завжди округляє:math.floor(-2.3) дає -3.0.
jochen

1
Це насправді не проблема. OP просто хоче, щоб ціле число виходило з результату math.floor, і ця відповідь показує, як перетворити float в ціле число. Візьміть поплавок зmath.floor і intint(math.floor(2.3))
пропустіть

4
Ви навіть читали запитання? Він знає про функцію int () , але запитав, чи можете ви зіткнутися з проблемою з 1.9999 замість 2.0. Ваша відповідь зовсім не близька до відповіді, ви пропустили цілий пункт ...
Mayou36

48

Ви можете використовувати функцію круглих. Якщо ви не використовуєте жодного другого параметра (# значущих цифр), я думаю, ви отримаєте потрібну поведінку.

IDLE вихід.

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

28
roundтакож повертає число з поплавком, принаймні, в Python 2.6.
Філіпп

8
У Python 3.1.2, круглий повертає int.
Роберт

2
Дійсно, і обидва, roundі floorповернути цілі числа в Python 3.x. Тому я припускаю, що питання стосується Python 2.x.
Філіпп

4
так, можливо int(round(2.65))?
teewuane

1
чому round(6.5)дає 6? Здається, що ceil()це поплавок, коли у всіх інших випадках є одразу 5 (або більше до 9) після десяткових. Чому в цьому випадку це не працює? або будь-який інший випадок, коли число закінчується на шість, а після десяткової
5,

43

Поєднуючи два попередні результати, ми маємо:

int(round(some_float))

Це перетворює поплавок на ціле число досить надійно.


Що станеться, якщо ви спробуєте закрутити дуже довгий поплавок? Чи це принаймні призведе до винятку?
Агостіно

@Agostino Що ви маєте на увазі "дуже довго плавати"?
кралик

@kralyk Я маю на увазі число, яке floatпредставляє більше, ніж те, що intможе мати нормальний . Чи є в Python 2 floatзначення, які ви можете представляти лише за допомогою long(після округлення)?
Агостіно

@kralyk ти маєш на увазі, після туру? Отже, чи було б їх кастингом до int підняти виняток, чи просто урізати їх?
Агостіно

@Agostino Ні, ця int()функція виробляє intабо longбазується на тому, що потрібно ...
kralyk

18

Що це працює зовсім не банально! Це властивість представлення IEEE з плаваючою точкою, що int∘floor = ⌊⋅⌋, якщо величина розглянутих чисел невелика, але можливі різні подання там, де int (floor (2.3)) може бути 1.

У цій публікації пояснюється, чому вона працює в такому діапазоні .

У подвоєнні ви можете без проблем представляти 32-бітні цілі числа. Не може бути жодних питань округлення. Точніше, парні можуть представляти всі цілі числа між і включати 2 53 та -2 53 .

Коротке пояснення : подвійний може зберігати до 53 двійкових цифр. Коли вам потрібно більше, число праворуч забито нулями.

Звідси випливає, що 53 з них - найбільше число, яке можна зберігати без прокладки. Природно, усі (цілі) числа, що потребують менших цифр, можуть бути точно збережені.

Додавання до 111 (пропущеного) 111 (53) дає 100 ... 000, (53 нулі). Як ми знаємо, ми можемо зберігати 53 цифри, що робить найбільш правильним нульове набивання.

Звідси походить 2 53 .


Більш детально: нам потрібно розглянути, як працює плаваюча точка IEEE-754.

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

Потім кількість обчислюється наступним чином (виключаючи особливі випадки, які тут не мають значення):

-1 знак × 1.mantissa × 2 показник - зміщення

де зміщення = 2 показник - 1 - 1 , тобто 1023 та 127 для подвійної / одиничної точності відповідно.

Знаючи, що множення на 2 X просто зміщує всі біти X місць вліво, легко помітити, що будь-яке ціле число повинно мати всі біти в мантісі, які закінчуються справа від десяткової крапки до нуля.

Будь-яке ціле число, крім нуля, має таку форму у двійковій формі:

1x ... x де x -es представляють біти праворуч від MSB (найбільш значущий біт).

Оскільки ми виключили нуль, завжди буде MSB, який є одним - ось чому він не зберігається. Щоб зберегти ціле число, ми повинні привести його до вищезгаданої форми: -1 знак × 1.mantissa × 2 показник - зміщення .

Це говорить так само, як переміщення бітів через десяткову точку, поки не залишиться лише MSB вліво від MSB. Усі біти праворуч від десяткової крапки потім зберігаються в мантісі.

З цього ми бачимо, що ми можемо зберігати не більше 52 двійкових цифр крім MSB.

Звідси випливає, що найбільше число, де явно зберігаються всі біти

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

Для цього нам потрібно встановити показник, таким чином, щоб десяткова точка змістилася на 52 місця. Якби ми збільшили показник на одиницю, ми не можемо знати цифру праворуч ліворуч після десяткової крапки.

111(omitted)111x.

За умовою, це 0. Установивши всю мантісу на нуль, ми отримаємо таке число:

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

Це 1, за яким 53 нулі, 52 збережені та 1 додано через показник.

Він представляє 2 53 , який позначає межу (як негативну, так і позитивну), між якою ми можемо точно представити всі цілі числа. Якби ми хотіли додати один до 2 53 , нам доведеться встановити неявний нуль (позначений символом x) на один, але це неможливо.


8

math.floorзавжди поверне ціле число і, таким чином int(math.floor(some_float)), ніколи не введе помилки округлення.

Помилка округлення може бути вже введена в math.floor(some_large_float), хоча, або навіть навіть при зберіганні великої кількості в плавці, в першу чергу. (Велика кількість може втратити точність при зберіганні в поплавках.)


7
Від: docs.python.org/2/library/math.html - math.floor (x) - повернути підлогу x у вигляді поплавця, найбільше ціле значення менше або рівне x.
Білл Росмус

Чому потрібно робити дзвінки math.floor, коли int вже робить те саме?
Олексій

1
@ Алекс: intі floorповертайте різні значення для від'ємних чисел, звичайно.

8

Якщо вам потрібно перетворити поплавок рядка в int, ви можете скористатися цим методом.

Приклад: '38.0'до38

Щоб перетворити це в int, ви можете подати його як float, а потім int. Це також буде працювати для плаваючих рядків або цілих рядків.

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

Примітка . При цьому буде викреслено будь-які цифри після коми.

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

1

Ще один зразок коду для перетворення дійсного / float в ціле число, використовуючи змінні. "vel" - це дійсне / плаваюче число і перетворюється на наступний найвищий INTEGER, "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

Оскільки ви запитуєте про «найбезпечніший» спосіб, я надам іншу відповідь, окрім основної відповіді.

Найпростіший спосіб переконатися, що ви не втрачаєте жодної точності, - це перевірити, чи будуть рівні рівні після їх перетворення.

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

Якщо float, наприклад, 1,0, 1,0 дорівнює 1. Отже, буде здійснено перетворення до int. І якщо float дорівнює 1.1, int (1.1) дорівнює 1, а 1.1! = 1. Значення залишатиметься плаваючою, і ви не втратите жодної точності.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.