Cómo verificar si un valor flotante es un número entero


203

Estoy tratando de encontrar la raíz cúbica más grande que sea un número entero, que sea menos de 12,000.

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

¡No estoy seguro de cómo verificar si es un número entero o no! Podría convertirlo en una cadena y luego usar la indexación para verificar los valores finales y ver si son cero o no, aunque parece bastante engorroso. ¿Hay alguna forma más simple?


3
facilitaría el trabajo desde la raíz cúbica n -> (n * n * n <12000)
sospechoso

Respuestas:


367

Para verificar si un valor flotante es un número entero, use el float.is_integer()método :

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

El método fue agregado al float tipo en Python 2.6.

Tenga en cuenta que en Python 2, 1/3es 0(¡división de piso para operandos enteros!), Y que la aritmética de coma flotante puede ser imprecisa (a floates una aproximación que usa fracciones binarias, no un número real preciso). Pero ajustando un poco su bucle, esto da:

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

lo que significa que se perdió algo más de 3 cubos (incluido 10648) debido a la imprecisión mencionada anteriormente:

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

Tendría que buscar números cercanos al número entero en su lugar, o no usar float()para encontrar su número. Como redondear la raíz cúbica de 12000:

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

Si está utilizando Python 3.5 o más reciente, puede usar la math.isclose()función para ver si un valor de coma flotante está dentro de un margen configurable:

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

Para versiones anteriores, la implementación ingenua de esa función (omitiendo la comprobación de errores e ignorando el infinito y NaN) como se menciona en 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)

Sin conocer Python, este tipo de afirmación me pondría nervioso, ya que parece requerir una matemática perfecta para trabajar en el mundo real.
Peter M

1
@PeterM: El método de hecho solo regresa Truesi no hay decimales en absoluto. Puede haber un malentendido por parte del OP sobre la aritmética y precisión de coma flotante, por supuesto.
Martijn Pieters

1
@MartijnPieters Sí y un pequeño desliz en un cálculo de coma flotante y de repente tienes estos pequeños decimales no deseados como 0.00000000000000000001
Peter M

1
@PeterM: y en Python 2 la representación predeterminada se redondeará a 16 dígitos; 1.0000000000000001se muestra como 1.0, en 3 se muestra la representación de cadena más corta que produce el mismo valor.
Martijn Pieters

Tu range(12000, -1, -1)podría ser (en mi opinión, más limpiamente) reescrito comoreversed(range(12000+1))
cs95

36

Podemos usar el operador de módulo (%). Esto nos dice cuántos residuos tenemos cuando dividimos x por y - se expresa comox % y . Cada número entero debe dividirse por 1, por lo que si hay un resto, no debe ser un número entero.

Esta función devolverá un valor booleano Trueo False, dependiendo de si nes un número entero.

def is_whole(n):
    return n % 1 == 0

15

Podrías usar esto:

if k == int(k):
    print(str(k) + " is a whole number!")

55
falla para grandes cantidades mientras .is_integer()continúa funcionando.
jfs

Su enlace en mi humilde opinión no muestra que no funciona. Simplemente muestra que los flotadores grandes pierden precisión. is_integerusa un método similar ( o = (floor(x) == x) ? Py_True : Py_False;). Pero estoy de acuerdo, uno debería usarlo, is_integer()ya que es mucho más claro.
Juri Robl

1
si. Simplemente muestra que un flotador grande puede perder precisión, es decir, large_float == large_intpuede fallar incluso si large_float == float(large_int).
jfs

2
123456789012345678901234567890.0 != 123456789012345678901234567890pero123456789012345678901234567890.0 == float(123456789012345678901234567890)
jfs

2
Sí, pero k = 123456789012345678901234567890.0entonces k == int(k)es cierto, que es la respuesta correcta.
Juri Robl

9

No necesita hacer un bucle o verificar nada. Solo toma una raíz cúbica de 12,000 y redondea hacia abajo:

r = int(12000**(1/3.0))
print r*r*r # 10648

Esta es una respuesta razonable.
hughdbrown

7

Puede usar una operación de módulo para eso.

if (n ** (1.0/3)) % 1 != 0:
    print("We have a decimal number here!")

2
si nes 6.2, 6.0, 6.12312412, todos tenemos "We have a decimal number here!"?
Jay Wong

@JayWong no está seguro de cómo cargó su prueba, pero esto funciona bien en mi máquina usando Python3.7.
Zchpyvr

6

¿No sería más fácil probar las raíces cúbicas? Comienza con 20 (20 ** 3 = 8000) y sube a 30 (30 ** 3 = 27000). Entonces tienes que probar menos de 10 enteros.

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

1
Además, los flotadores tienen errores de redondeo para que pueda omitir el número al calcular si n**(1/3)es entero. Por ejemplo, en mi computadora `10648 ** (1/3) = 21.999999999999996` en lugar de 22: ¡problema! Con el método de esta respuesta no existe tal problema. Creo que esta es la única solución correcta desde un punto de vista matemático (otras soluciones son Python-correct).
JPG


3

Las respuestas anteriores funcionan para muchos casos pero se pierden algunas. Considera lo siguiente:

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

Usando esto como punto de referencia, algunas de las otras sugerencias no obtienen el comportamiento que podríamos desear:

fl.is_integer() # False

fl % 1 == 0     # False

En su lugar, intente:

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))

ahora obtenemos:

is_integer(fl)   # True

iscloseviene con Python 3.5+ , y para otras Python puede usar esta definición mayormente equivalente (como se menciona en la PEP correspondiente )


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

1

Solo una información adicional, is_integerestá haciendo internamente:

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

No exactamente en python, pero la implementación de cpython se implementa como se mencionó anteriormente.


1

Todas las respuestas son buenas, pero un método seguro sería

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

La función devuelve True si es un número entero más False ... Sé que llego un poco tarde, pero aquí está uno de los métodos interesantes que hice ...

Editar: como se indica en el comentario a continuación, una prueba equivalente más barata sería:

def whole(n):
    return n%1==0

1
Esto no debería ser funcionalmente diferente de n % 1 == 0. En este caso, está realizando dos operaciones que son más caras para una prueba equivalente más barata.
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
>>>

Aquí hay algunas pautas para ¿Cómo escribo una buena respuesta? . Esta respuesta proporcionada puede ser correcta, pero podría beneficiarse de una explicación. Las respuestas de solo código no se consideran respuestas "buenas". De la revisión .
Trenton McKinney

-1

Intenta usar:

int(val) == val

Le dará mucha más precisión que cualquier otro método.


¿Puede dar un ejemplo para respaldar la afirmación de que "dará mucha más precisión"? Esto parece infundado.
Mark Dickinson

-1

Puede usar la roundfunción para calcular el valor.

Sí, en Python, como muchos han señalado cuando calculamos el valor de una raíz cúbica, le dará una salida con un poco de error. Para verificar si el valor es un número entero, puede usar la siguiente función:

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

Pero recuerde que int(n)es equivalente a math.floory debido a esto, si encuentra el int(41063625**(1.0/3.0)), obtendrá 344 en lugar de 345.

Por lo tanto, tenga cuidado al usar con intraíces cúbicas.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.