Le moyen le plus sûr de convertir float en entier en python?

216

Le module mathématique de Python contient des fonctions pratiques comme floor& ceil. Ces fonctions prennent un nombre à virgule flottante et renvoient l'entier le plus proche en dessous ou au-dessus. Cependant, ces fonctions renvoient la réponse sous forme de nombre à virgule flottante. Par exemple:

import math
f=math.floor(2.3)

fRetourne maintenant :

2.0

Quelle est la façon la plus sûre d'extraire un entier de ce flottant, sans courir le risque d'erreurs d'arrondi (par exemple si le flottant est l'équivalent de 1,99999) ou peut-être devrais-je utiliser une autre fonction tout à fait?

Boaz
la source
7
math.floor renvoie un flottant dans la v2.6 , mais il renvoie un entier dans la v3 . À ce stade (près de six ans après le PO), ce problème pourrait apparaître rarement.
sancho.s ReinstateMonicaCellio
cependant numpy renvoie toujours float, donc la question est valide.
Vincenzooo

Réponses:

178

Tous les entiers pouvant être représentés par des nombres à virgule flottante ont une représentation exacte. Vous pouvez donc utiliser intle résultat en toute sécurité . Les représentations inexactes ne se produisent que si vous essayez de représenter un nombre rationnel avec un dénominateur qui n'est pas une puissance de deux.

Que cela fonctionne n'est pas anodin! C'est une propriété de la représentation en virgule flottante IEEE que int∘floor = ⌊⋅⌋ si la magnitude des nombres en question est suffisamment petite, mais différentes représentations sont possibles où int (floor (2.3)) pourrait être 1.

Pour citer Wikipédia ,

Tout entier dont la valeur absolue est inférieure ou égale à 2 24 peut être représenté exactement au format simple précision et tout entier dont la valeur absolue est inférieure ou égale à 2 53 peut être représenté exactement au format double précision.

Philipp
la source
8
+1 pour aller un peu plus loin. Vous pouvez également expliquer brièvement pourquoi: en.wikipedia.org/wiki/Floating_point : D
Gordon Gustafson
En Python 2, un "int" est le même qu'un C "int". En Python 3, il semble qu'il n'y ait pas de limite à la taille d'un "int, stackoverflow.com/questions/13795758/… . La signification de" int "dépend également du système d'exploitation et du matériel sous-jacent. Voir en.wikipedia. org / wiki / 64-bit_computing # 64-bit_data_models . Si vous programmez avec l'API C, python 3, vous devez faire très attention à la définition de long et size_t sur votre plate-forme. docs.python.org/3 /c-api/long.html
Juan
114

L'utilisation int(your non integer number)le clouera.

print int(2.3) # "2"
print int(math.sqrt(5)) # "2"
srodriguex
la source
4
Cela ne fonctionnera pas pour les nombres négatifs: floorarrondit vers le bas alors qu'il intarrondit vers 0.
jochen
1
@jochen J'ai testé int(-2.3)dans la distribution Python Canopy 2.7.6 et obtenu -2comme prévu. Les nombres entiers peuvent être négatifs, de la même manière dans la définition mathématique formelle.
srodriguex
5
Je suis d'accord, int(-2.3)donne -2comme vous dites, car il arrondit vers 0, c'est- à- dire vers le haut dans ce cas. En revanche, la question d'origine utilisée math.floor, qui arrondit toujours: math.floor(-2.3)donne -3.0.
jochen
1
Ce n'est pas vraiment un problème. OP veut juste un entier hors du résultat de math.floor, et cette réponse montre comment convertir un flottant en entier. Prenez le flotteur math.flooret intint(math.floor(2.3))
passez-
4
Avez-vous même lu la question? Il connaît la fonction int () , mais a demandé si vous pouviez rencontrer des problèmes avec 1.9999 au lieu de 2.0. Votre réponse n'est même pas du tout proche d'une réponse, vous avez raté tout le point ...
Mayou36
48

Vous pouvez utiliser la fonction ronde. Si vous n'utilisez pas de deuxième paramètre (nombre de chiffres significatifs), je pense que vous obtiendrez le comportement que vous souhaitez.

Sortie IDLE.

>>> round(2.99999999999)
3
>>> round(2.6)
3
>>> round(2.5)
3
>>> round(2.4)
2
Wade73
la source
28
roundrenvoie également un nombre flottant, au moins en Python 2.6.
Philipp
8
En Python 3.1.2, round renvoie un int.
robert
2
En effet, les deux roundet floorretournent des entiers en Python 3.x. Je suppose donc que la question concerne Python 2.x.
Philipp
4
alors peut int(round(2.65))- être ?
teewuane
1
pourquoi round(6.5)donne 6? Il semble un peu ceil()flotter quand il y a un 5 immédiat (ou plus jusqu'à 9) après la décimale dans tous les autres cas. Pourquoi cela ne fonctionne-t-il pas dans ce cas? ou tout autre cas où le nombre se termine par un six et qu'il y a un 5 juste après la décimale ...
candh
43

En combinant deux des résultats précédents, nous avons:

int(round(some_float))

Cela convertit un flottant en un entier de manière assez fiable.

user3763109
la source
Que se passe-t-il si vous essayez d'arrondir un flotteur très long? Cela va-t-il au moins soulever une exception?
Agostino
@Agostino Que voulez-vous dire par "très long flotteur"?
kralyk
@kralyk Je veux dire un floatreprésentant un nombre plus grand que ce que intpeut contenir une normale . En Python 2, existe-t-il des floatvaleurs que vous ne pouvez représenter qu'en utilisant un long(après l'arrondi)?
Agostino
@kralyk tu veux dire, après le tour? Alors, les lancer pour int déclencherait-il une exception, ou simplement les tronquer?
Agostino
@Agostino Non, la int()fonction produit un intou un longbasé sur ce qui est nécessaire ...
kralyk
18

Que cela fonctionne n'est pas anodin! C'est une propriété de la représentation en virgule flottante IEEE que int∘floor = ⌊⋅⌋ si la magnitude des nombres en question est suffisamment petite, mais différentes représentations sont possibles où int (floor (2.3)) pourrait être 1.

Ce post explique pourquoi cela fonctionne dans cette gamme .

Dans un double, vous pouvez représenter des entiers 32 bits sans aucun problème. Il ne peut y avoir de problème d'arrondi. Plus précisément, les doubles peuvent représenter tous les entiers compris entre 2 53 et -2 53 inclus .

Brève explication : un double peut stocker jusqu'à 53 chiffres binaires. Lorsque vous en avez besoin de plus, le nombre est complété par des zéros à droite.

Il s'ensuit que 53 unités est le plus grand nombre pouvant être stocké sans remplissage. Naturellement, tous les nombres (entiers) nécessitant moins de chiffres peuvent être stockés avec précision.

Ajouter un à 111 (omis) 111 (53 uns) donne 100 ... 000, (53 zéros). Comme nous le savons, nous pouvons stocker 53 chiffres, ce qui fait le remplissage zéro le plus à droite.

C'est de là que vient 2 53 .


Plus de détails: nous devons examiner comment fonctionne la virgule flottante IEEE-754.

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

Le nombre est ensuite calculé comme suit (hors cas particuliers qui ne sont pas pertinents ici):

-1 signe × 1.mantisse × 2 exposant - biais

biais = 2 exposants - 1 - 1 , c'est-à-dire 1023 et 127 pour la précision double / simple respectivement.

Sachant que multiplier par 2 X décale simplement tous les bits X à gauche, il est facile de voir que tout entier doit avoir tous les bits de la mantisse qui se terminent à droite de la virgule décimale par zéro.

Tout entier sauf zéro a la forme suivante en binaire:

1x ... x où les x -es représentent les bits à droite du MSB (bit le plus significatif).

Parce que nous avons exclu zéro, il y aura toujours un MSB qui est un, c'est pourquoi il n'est pas stocké. Pour stocker l'entier, nous devons le mettre sous la forme susmentionnée: -1 signe × 1.mantisse × 2 exposant - biais .

Cela signifie la même chose que de déplacer les bits sur la virgule décimale jusqu'à ce qu'il n'y ait que le MSB vers la gauche du MSB. Tous les bits à droite de la virgule décimale sont ensuite stockés dans la mantisse.

De cela, nous pouvons voir que nous pouvons stocker au plus 52 chiffres binaires en dehors du MSB.

Il s'ensuit que le nombre le plus élevé où tous les bits sont explicitement stockés est

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

Pour cela, nous devons définir l'exposant, de sorte que la virgule décimale soit décalée de 52 places. Si nous devions augmenter l'exposant de un, nous ne pouvons pas connaître le chiffre de droite à gauche après le point décimal.

111(omitted)111x.

Par convention, c'est 0. En mettant la mantisse entière à zéro, nous recevons le nombre suivant:

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

C'est un 1 suivi de 53 zéros, 52 stockés et 1 ajouté en raison de l'exposant.

Il représente 2 53 , qui marque la frontière (à la fois négative et positive) entre laquelle nous pouvons représenter avec précision tous les entiers. Si nous voulions ajouter un à 2 53 , nous devions définir le zéro implicite (indiqué par le x) à un, mais c'est impossible.

phant0m
la source
8

math.floorrenverra toujours un nombre entier et int(math.floor(some_float))n'introduira donc jamais d'erreurs d'arrondi.

L'erreur d'arrondi peut déjà être introduite dans math.floor(some_large_float), ou même lors du stockage d'un grand nombre dans un flottant en premier lieu. (Les grands nombres peuvent perdre en précision lorsqu'ils sont stockés dans des flotteurs.)


la source
7
From: docs.python.org/2/library/math.html - math.floor (x) - Renvoie le plancher de x sous forme de flottant, la plus grande valeur entière inférieure ou égale à x.
Bill Rosmus
Pourquoi avez-vous besoin d'appeler math.floor alors que int fait déjà la même chose?
Alex
1
@Alex: intet floorrenvoie bien sûr différentes valeurs pour les nombres négatifs.
8

Si vous devez convertir un flottant de chaîne en entier, vous pouvez utiliser cette méthode.

Exemple: '38.0'à38

Pour le convertir en entier, vous pouvez le convertir en flottant puis en entier. Cela fonctionnera également pour les chaînes flottantes ou les chaînes entières.

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

Remarque : Cela supprimera tous les nombres après la décimale.

>>> int(float('38.2'))
38
brandonbanks
la source
1

Un autre exemple de code pour convertir un réel / flottant en un entier à l'aide de variables. "vel" est un nombre réel / flottant et converti au prochain INTEGER le plus élevé, "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
la source
0

Puisque vous demandez le moyen le plus sûr, je fournirai une autre réponse que la première réponse.

Un moyen facile de vous assurer de ne perdre aucune précision est de vérifier si les valeurs seront égales après les avoir converties.

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

Si le flottant est 1.0 par exemple, 1.0 est égal à 1. La conversion en int s'exécutera donc. Et si le flottant est 1.1, int (1.1) équivaut à 1 et 1.1! = 1. La valeur restera donc un flottant et vous ne perdrez aucune précision.

Troy H
la source
0

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

Niruttara
la source
Une explication à votre réponse va un long chemin.
bibliophilsagar