Comment vérifier si une valeur flottante est un nombre entier

203

J'essaie de trouver la plus grande racine cubique qui soit un nombre entier, c'est-à-dire moins de 12 000.

processing = True
n = 12000
while processing:
    n -= 1
    if n ** (1/3) == #checks to see if this has decimals or not

Je ne sais pas comment vérifier s'il s'agit d'un nombre entier ou non! Je pourrais le convertir en chaîne, puis utiliser l'indexation pour vérifier les valeurs finales et voir si elles sont nulles ou non, cela semble plutôt lourd. Existe-t-il un moyen plus simple?

chopper draw lion4
la source
3
cela faciliterait le travail à partir de la racine du cube n -> (n * n * n <12000)
suspectus

Réponses:

367

Pour vérifier si une valeur flottante est un nombre entier, utilisez la float.is_integer()méthode :

>>> (1.0).is_integer()
True
>>> (1.555).is_integer()
False

La méthode a été ajoutée au floattype dans Python 2.6.

Tenez compte du fait qu'en Python 2, 1/3is 0(division au sol pour les opérandes entiers!), Et que l'arithmétique à virgule flottante peut être imprécise (a floatest une approximation utilisant des fractions binaires, pas un nombre réel précis). Mais en ajustant un peu votre boucle, cela donne:

>>> for n in range(12000, -1, -1):
...     if (n ** (1.0/3)).is_integer():
...         print n
... 
27
8
1
0

ce qui signifie que tout ce qui dépasse 3 cubes (dont 10648) a été oublié en raison de l'imprécision susmentionnée:

>>> (4**3) ** (1.0/3)
3.9999999999999996
>>> 10648 ** (1.0/3)
21.999999999999996

Vous devez plutôt rechercher des nombres proches du nombre entier ou ne pas utiliser float()pour trouver votre numéro. Comme arrondir la racine cubique de 12000:

>>> int(12000 ** (1.0/3))
22
>>> 22 ** 3
10648

Si vous utilisez Python 3.5 ou une version plus récente, vous pouvez utiliser la math.isclose()fonction pour voir si une valeur à virgule flottante se trouve dans une marge configurable:

>>> from math import isclose
>>> isclose((4**3) ** (1.0/3), 4)
True
>>> isclose(10648 ** (1.0/3), 22)
True

Pour les versions plus anciennes, l'implémentation naïve de cette fonction (ignorer la vérification des erreurs et ignorer l'infini et NaN) comme mentionné dans PEP485 :

def isclose(a, b, rel_tol=1e-9, abs_tol=0.0):
    return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
Martijn Pieters
la source
Ne connaissant pas le python, ce genre de déclaration me rendrait nerveux car il semble nécessiter des mathématiques parfaites pour fonctionner dans le monde réel.
Peter M
1
@PeterM: La méthode ne retourne en effet que Trues'il n'y a pas de décimales du tout. Il peut y avoir un malentendu de la part du PO au sujet de l'arithmétique en virgule flottante et de la précision, bien sûr.
Martijn Pieters
1
@MartijnPieters Oui et un petit glissement dans un calcul en virgule flottante et tout à coup, vous avez ces petites décimales indésirables comme 0.00000000000000000001
Peter M
1
@PeterM: et en Python 2, la représentation par défaut sera arrondie à 16 chiffres; 1.0000000000000001est affiché car 1.0, en 3, la représentation de chaîne la plus courte qui produit la même valeur est affichée.
Martijn Pieters
Vous range(12000, -1, -1)pourriez être (imo, plus proprement) réécrit commereversed(range(12000+1))
cs95
36

Nous pouvons utiliser l'opérateur modulo (%). Cela nous dit combien de restes nous avons lorsque nous divisons x par y - exprime comme x % y. Chaque nombre entier doit être divisé par 1, donc s'il y a un reste, il ne doit pas être un nombre entier.

Cette fonction renverra un booléen Trueou False, selon qu'il ns'agit d'un nombre entier.

def is_whole(n):
    return n % 1 == 0
MagikCow
la source
15

Vous pouvez utiliser ceci:

if k == int(k):
    print(str(k) + " is a whole number!")
Juri Robl
la source
5
il échoue pour un plus grand nombre tout en .is_integer()continuant à fonctionner.
jfs
Votre lien à mon humble avis ne montre pas qu'il ne fonctionne pas. Cela montre simplement que les gros flotteurs perdent en précision. is_integerutilise une méthode similaire ( o = (floor(x) == x) ? Py_True : Py_False;). Mais je suis d'accord, il faut utiliser is_integer()car c'est beaucoup plus clair.
Juri Robl
1
Oui. Cela montre simplement qu'un flotteur de grande taille peut perdre sa précision, c'est-à-dire large_float == large_intpeut échouer même si large_float == float(large_int).
jfs
2
123456789012345678901234567890.0 != 123456789012345678901234567890mais123456789012345678901234567890.0 == float(123456789012345678901234567890)
jfs
2
Oui, mais k = 123456789012345678901234567890.0alors k == int(k)est vrai, ce qui est la bonne réponse.
Juri Robl
9

Vous n'avez pas besoin de boucler ou de vérifier quoi que ce soit. Prenez simplement une racine cubique de 12 000 et arrondissez-la:

r = int(12000**(1/3.0))
print r*r*r # 10648
georg
la source
Ceci est une réponse raisonnable.
hughdbrown
7

Vous pouvez utiliser une opération modulo pour cela.

if (n ** (1.0/3)) % 1 != 0:
    print("We have a decimal number here!")
Jakub Jirutka
la source
2
si nest 6.2, 6.0, 6.12312412, nous l'avons tous "We have a decimal number here!"?
Jay Wong
@JayWong ne sais pas comment vous avez chargé votre test, mais cela fonctionne très bien sur ma machine en utilisant Python3.7.
Zchpyvr
6

Ne serait-il pas plus facile de tester les racines cubiques? Commencez avec 20 (20 ** 3 = 8000) et montez jusqu'à 30 (30 ** 3 = 27000). Ensuite, vous devez tester moins de 10 entiers.

for i in range(20, 30):
    print("Trying {0}".format(i))
    if i ** 3 > 12000:
        print("Maximum integral cube root less than 12000: {0}".format(i - 1))
        break
Hughdbrown
la source
1
De plus, les flottants ont des erreurs d'arrondi de sorte que vous pouvez manquer un nombre lors du calcul si n**(1/3)est entier. Par exemple sur mon ordinateur `10648 ** (1/3) = 21.99999999999999696 au lieu de 22: problème! Avec la méthode de cette réponse, il n'y a pas un tel problème. Je pense que c'est la seule solution correcte d'un point de vue mathématique (d'autres solutions sont correctes en Python).
JPG
5

Que diriez-vous

if x%1==0:
    print "is integer"
Daniel
la source
3

Les réponses ci-dessus fonctionnent pour de nombreux cas, mais elles en manquent. Considérer ce qui suit:

fl = sum([0.1]*10)  # this is 0.9999999999999999, but we want to say it IS an int

En utilisant cela comme référence, certaines des autres suggestions n'obtiennent pas le comportement que nous pourrions souhaiter:

fl.is_integer() # False

fl % 1 == 0     # False

Essayez plutôt:

def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
    return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)

def is_integer(fl):
    return isclose(fl, round(fl))

maintenant on obtient:

is_integer(fl)   # True

iscloseest livré avec Python 3.5+ , et pour d'autres Python, vous pouvez utiliser cette définition essentiellement équivalente (comme mentionné dans le PEP correspondant )

control_fd
la source
1
math.fsum([0.1] * 10) == 1
Acumenus
1

Juste une info latérale, is_integerfait en interne:

import math
isInteger = (math.floor(x) == x)

Pas exactement en python, mais l'implémentation de cpython est implémentée comme mentionné ci-dessus.

user1767754
la source
1

Toutes les réponses sont bonnes mais une méthode de tir sûre serait

def whole (n):
     return (n*10)%10==0

La fonction renvoie True si c'est un nombre entier sinon False .... Je sais que je suis un peu en retard mais voici une des méthodes intéressantes que j'ai faites ...

Edit: comme indiqué par le commentaire ci-dessous, un test équivalent moins cher serait:

def whole(n):
    return n%1==0
random_npc
la source
1
Cela ne devrait pas être différent sur le plan fonctionnel n % 1 == 0. Dans ce cas, vous effectuez deux opérations, ce qui est plus cher pour un test équivalent moins cher.
Zchpyvr
0
>>> def is_near_integer(n, precision=8, get_integer=False):
...     if get_integer:
...         return int(round(n, precision))
...     else:
...         return round(n) == round(n, precision)
...
>>> print(is_near_integer(10648 ** (1.0/3)))
True
>>> print(is_near_integer(10648 ** (1.0/3), get_integer=True))
22
>>> for i in [4.9, 5.1, 4.99, 5.01, 4.999, 5.001, 4.9999, 5.0001, 4.99999, 5.000
01, 4.999999, 5.000001]:
...     print(i, is_near_integer(i, 4))
...
4.9 False
5.1 False
4.99 False
5.01 False
4.999 False
5.001 False
4.9999 False
5.0001 False
4.99999 True
5.00001 True
4.999999 True
5.000001 True
>>>
csaszizoltan
la source
Voici quelques lignes directrices pour Comment écrire une bonne réponse? . Cette réponse fournie peut être correcte, mais elle pourrait bénéficier d'une explication. Les réponses codées uniquement ne sont pas considérées comme de «bonnes» réponses. De l' avis .
Trenton McKinney
-1

Essayez d'utiliser:

int(val) == val

Cela donnera beaucoup plus de précision que toute autre méthode.

Nishant Ingle
la source
Pouvez-vous donner un exemple pour étayer l'affirmation selon laquelle «cela donnera beaucoup plus de précision»? Cela semble sans fondement.
Mark Dickinson
-1

Vous pouvez utiliser la roundfonction pour calculer la valeur.

Oui en python comme beaucoup l'ont souligné lorsque nous calculons la valeur d'une racine de cube, cela vous donnera une sortie avec un peu d'erreur. Pour vérifier si la valeur est un nombre entier, vous pouvez utiliser la fonction suivante:

def cube_integer(n):
    if round(n**(1.0/3.0))**3 == n:
        return True
    return False

Mais rappelez-vous que cela int(n)équivaut à math.flooret à cause de cela, si vous trouvez le, int(41063625**(1.0/3.0))vous obtiendrez 344 au lieu de 345.

Soyez donc prudent lorsque vous utilisez des intracines cubiques.

Anivarth
la source