Comment forcer la division à virgule flottante? La division continue d'arrondir à 0?

721

J'ai deux valeurs entières aet b, mais j'ai besoin de leur rapport en virgule flottante. Je sais cela a < bet je veux calculer a / b, donc si j'utilise la division entière, j'obtiendrai toujours 0 avec un reste de a.

Comment puis-je forcer cà être un nombre à virgule flottante en Python dans ce qui suit?

c = a / b
Nathan Fellman
la source
Il suffit de passer à Python 3.
Boris

Réponses:

807

En Python 2, la division de deux entiers produit un int. En Python 3, il produit un flottant. Nous pouvons obtenir le nouveau comportement en important depuis __future__.

>>> from __future__ import division
>>> a = 4
>>> b = 6
>>> c = a / b
>>> c
0.66666666666666663
Michael Fairley
la source
13
Notez que cela from __future__ import divisiondoit être au tout début du fichier
yannis
Le problème est aussi si vous voulez la division entière à un endroit mais la division flottante à un autre endroit du fichier ...
mercury0114
1
@ mercury0114: Pas de problème; vous utilisez simplement //quand vous voulez une division au sol, et /quand vous voulez une floatdivision "true" ( ).
ShadowRanger
715

Vous pouvez lancer pour flotter en faisant c = a / float(b). Si le numérateur ou le dénominateur est un flottant, le résultat sera également.


Une mise en garde: comme l'ont souligné les commentateurs, cela ne fonctionnera pas s'il bpourrait être autre chose qu'un nombre entier ou à virgule flottante (ou une chaîne représentant un). Si vous avez affaire à d'autres types (tels que des nombres complexes), vous devrez soit les vérifier, soit utiliser une méthode différente.

Steve Trout
la source
195

Comment puis-je forcer la division à être flottante en Python?

J'ai deux valeurs entières a et b, mais j'ai besoin de leur rapport en virgule flottante. Je sais que a <b et je veux calculer a / b, donc si j'utilise une division entière, j'obtiendrai toujours 0 avec un reste de a.

Comment puis-je forcer c à être un nombre à virgule flottante en Python dans ce qui suit?

c = a / b

Ce qui est vraiment demandé ici, c'est:

"Comment puis-je forcer une vraie division telle que a / bcela rendra une fraction?"

Mettre à niveau vers Python 3

En Python 3, pour obtenir une véritable division, il vous suffit de le faire a / b.

>>> 1/2
0.5

La division au sol, le comportement de division classique pour les entiers, est désormais a // b:

>>> 1//2
0
>>> 1//2.0
0.0

Cependant, vous pouvez être bloqué en utilisant Python 2, ou vous pouvez écrire du code qui doit fonctionner à la fois dans 2 et 3.

Si vous utilisez Python 2

En Python 2, ce n'est pas si simple. Certaines façons de gérer la division Python 2 classique sont meilleures et plus robustes que d'autres.

Recommandation pour Python 2

Vous pouvez obtenir le comportement de division Python 3 dans n'importe quel module avec l'importation suivante en haut:

from __future__ import division

qui applique ensuite la division de style Python 3 à l'ensemble du module. Il fonctionne également dans un shell python à tout moment donné. En Python 2:

>>> from __future__ import division
>>> 1/2
0.5
>>> 1//2
0
>>> 1//2.0
0.0

C'est vraiment la meilleure solution car elle garantit que le code de votre module est plus compatible avec Python 3.

Autres options pour Python 2

Si vous ne souhaitez pas appliquer cela à l'ensemble du module, vous êtes limité à quelques solutions de contournement. Le plus populaire consiste à contraindre l'un des opérandes à un flotteur. Une solution robuste est a / (b * 1.0). Dans un nouveau shell Python:

>>> 1/(2 * 1.0)
0.5

Aussi robuste truedivdu operatormodule de operator.truediv(a, b), mais cela est probablement plus lent , car il est un appel de fonction:

>>> from operator import truediv
>>> truediv(1, 2)
0.5

Non recommandé pour Python 2

On le voit généralement a / float(b). Cela déclenchera une TypeError si b est un nombre complexe. Étant donné que la division avec des nombres complexes est définie, il est logique pour moi de ne pas faire échouer la division lors de la transmission d'un nombre complexe pour le diviseur.

>>> 1 / float(2)
0.5
>>> 1 / float(2j)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't convert complex to float

Cela n'a pas beaucoup de sens pour moi de rendre votre code plus fragile.

Vous pouvez également exécuter Python avec l' -Qnewindicateur, mais cela a l'inconvénient d'exécuter tous les modules avec le nouveau comportement Python 3, et certains de vos modules peuvent s'attendre à une division classique, donc je ne le recommande que pour les tests. Mais pour démontrer:

$ python -Qnew -c 'print 1/2'
0.5
$ python -Qnew -c 'print 1/2j'
-0.5j
Aaron Hall
la source
3
"1 // 2 = 0", "1 // 2.0 = 0.0" - petit gotcha intéressant, même si c'est une division entière, si l'un des opérandes est float alors le résultat est un nombre entier mais aussi float. J'utilisais une division entière pour calculer un index de liste et obtenir une erreur à cause de cela.
R. Navega
134
c = a / (b * 1.0)
Pinochle
la source
66

Dans Python 3.x, la barre oblique unique ( /) signifie toujours une véritable division (non tronquée). (L' //opérateur est utilisé pour tronquer la division.) En Python 2.x (2.2 et supérieur), vous pouvez obtenir ce même comportement en mettant un

from __future__ import division

en haut de votre module.

newacct
la source
30

La simple création de l'un des paramètres de division au format virgule flottante produit également la sortie en virgule flottante.

Exemple:

>>> 4.0/3
1.3333333333333333

ou,

>>> 4 / 3.0
1.3333333333333333

ou,

>>> 4 / float(3)
1.3333333333333333

ou,

>>> float(4) / 3
1.3333333333333333
gsbabil
la source
4
Mais vous pourriez plus tard être tenté de faire 1.0 + 1/3ou float(c) + a/bou float(a/b)et vous serez déçu de la réponse. Mieux vaut utiliser python 3+ ou importer le __future__.divisionmodule, (voir réponse acceptée), pour toujours obtenir la réponse que vous attendez. Les règles de division existantes créent une erreur mathématique insidieuse et difficile à retracer.
plaques de cuisson
@JoeCondron Avez-vous essayé python -c 'a=10; b=3.0; print a/b'?
gsbabil
Je n'ai pas eu à le faire car cela fonctionne évidemment dans ce scénario. Cependant, que se passe-t-il si aet 'b', par exemple, sont les sorties d'une fonction de valeur entière? Par exemple, a = len(list1), b = len(list2).
JoeCondron
@JoeCondron: bon point. Je viens de mettre à jour la réponse pour l'inclure float(..). Je pense que la multiplication par 1.0, comme l'a suggéré @Pinochle ci-dessous, pourrait également être utile.
gsbabil
21

Ajoutez un point ( .) pour indiquer les nombres à virgule flottante

>>> 4/3.
1.3333333333333333
Alexandre
la source
2
Comment allez-vous appliquer cette approche si le numérateur et le dénominateur sont tous deux des variables?
stackoverflowuser2010
Je suppose que vous vous référez au premier exemple, si tel est le cas, je voudrais simplement utiliser float()sur l'une des variables.
Alexander
13

Cela fonctionnera également

>>> u=1./5
>>> print u
0.2
Gaurav Agarwal
la source
4
Et comment allez-vous appliquer cette approche si le numérateur et le dénominateur sont tous deux des variables?
stackoverflowuser2010
1
Parce que cela ne fonctionne pas lorsque des variables sont utilisées pour l'abstraction. Presque aucun code significatif n'a de valeurs codées en dur comme ça.
Keir Simmons
1
Cela a peu de votes parce que cette réponse ne répond pas à la question et n'est pas du tout une réponse générale. Dans une réponse, il est également important de montrer d'abord pourquoi cela fonctionne. C'est très simple: si le numérateur ou le dénominateur est un flottant, le résultat sera un flottant. Habituellement, vous n'utilisez pas python comme une calculatrice de texte en clair, vous voulez donc une réponse pour les variables aet b.
TimZaman
Pendant longtemps, j'ai pensé que ./c'était un opérateur valide en python qui vous permet de faire une division en virgule flottante. C'est pourquoi il est bon d'utiliser judicieusement les espaces blancs, dans n'importe quel langage de programmation
smac89
6

Si vous souhaitez utiliser la division "true" (virgule flottante) par défaut, il existe un indicateur de ligne de commande:

python -Q new foo.py

Il y a quelques inconvénients (du PEP):

Il a été soutenu qu'une option de ligne de commande pour modifier la valeur par défaut est mauvaise. Cela peut certainement être dangereux entre de mauvaises mains: par exemple, il serait impossible de combiner un paquetage de bibliothèque tiers qui nécessite -Qnew avec un autre qui nécessite -Qold.

Vous pouvez en savoir plus sur les autres valeurs de drapeaux qui modifient / avertissent du comportement de la division en consultant la page de manuel python.

Pour plus de détails sur les changements de division, lisez: PEP 238 - Changement d'opérateur de division

stephenbez
la source
2
from operator import truediv

c = truediv(a, b)
JoeCondron
la source
2
Ce n'est pas idéal, cependant, car cela ne fonctionne pas dans le cas où aest un int et best un flottant. Une meilleure solution dans le même sens est de faire from operator import truedivpuis d'utiliser truediv(a, b).
Mark Dickinson
Oui vous avez raison. Je supposais les deux entiers car c'est la seule fois où les opérations de division diffèrent, mais vous voulez vraiment une solution générale. Je ne savais pas vraiment que vous pouviez importer l'opérateur ou qu'il ne fonctionnait pas du tout pour les diviseurs flottants. Réponse modifiée.
JoeCondron
1
from operator import truediv

c = truediv(a, b)

où a est le dividende et b est le diviseur. Cette fonction est pratique lorsque le quotient après division de deux entiers est un flottant.

Chetan Yeshi
la source