¿La forma más segura de convertir float a entero en python?

El módulo matemático de Python contiene funciones útiles como floor & ceil . Estas funciones toman un número de punto flotante y devuelven el número entero más cercano por debajo o por encima de él. Sin embargo, estas funciones devuelven la respuesta como un número de punto flotante. Por ejemplo:

 import math f=math.floor(2.3) 

Ahora f regresa:

 2.0 

¿Cuál es la forma más segura de obtener un número entero de este flotador, sin correr el riesgo de errores de redondeo (por ejemplo, si el flotador es el equivalente a 1.99999) o quizás debería usar otra función por completo?

Todos los enteros que se pueden representar con números de punto flotante tienen una representación exacta. Así que puedes usar con seguridad int en el resultado. Las representaciones inexactas ocurren solo si está tratando de representar un número racional con un denominador que no es una potencia de dos.

¡Que esto funcione no es para nada trivial! Es una propiedad de la representación de punto flotante IEEE que int∘floor = ⌊⋅⌋ si la magnitud de los números en cuestión es lo suficientemente pequeña, pero son posibles diferentes representaciones donde int (floor (2.3)) puede ser 1.

Para citar de Wikipedia ,

Cualquier número entero con un valor absoluto menor o igual a 2 24 puede representarse exactamente en el formato de precisión simple, y cualquier número entero con un valor absoluto menor o igual a 2 53 puede ser representado exactamente en el formato de doble precisión.

Use int(your non integer number) lo clavará.

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

Podrías usar la función redonda. Si no usa un segundo parámetro (número de dígitos significativos), creo que obtendrá el comportamiento que desea.

Salida IDLE.

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

Combinando dos de los resultados anteriores, tenemos:

 int(round(some_float)) 

Esto convierte un flotador en un entero de manera bastante confiable.

¡Que esto funcione no es para nada trivial! Es una propiedad de la representación de punto flotante IEEE que int∘floor = ⌊⋅⌋ si la magnitud de los números en cuestión es lo suficientemente pequeña, pero son posibles diferentes representaciones donde int (floor (2.3)) puede ser 1.

Este post explica por qué funciona en ese rango .

En un doble, puedes representar enteros de 32 bits sin ningún problema. No puede haber problemas de redondeo. Más precisamente, los dobles pueden representar todos los números enteros entre 2 53 y -2 53 inclusive.

Breve explicación : un doble puede almacenar hasta 53 dígitos binarios. Cuando necesite más, el número se rellena con ceros a la derecha.

De ello se deduce que 53 unidades es el número más grande que se puede almacenar sin relleno. Naturalmente, todos los números (enteros) que requieren menos dígitos se pueden almacenar con precisión.

Sumando uno a 111 (omitido), 111 (53 unidades) produce 100 … 000, (53 ceros). Como sabemos, podemos almacenar 53 dígitos, lo que hace que el relleno de cero más a la derecha.

Aquí es de donde viene el 2 53 .


Más detalles: debemos considerar cómo funciona el punto flotante IEEE-754.

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

El número se calcula de la siguiente manera (excluyendo los casos especiales que son irrelevantes aquí):

-1 signo × 1.mantisa × 2 exponente – sesgo

donde sesgo = 2 exponente – 1 – 1 , es decir, 1023 y 127 para precisión doble / simple respectivamente.

Sabiendo que multiplicar por 2 X simplemente desplaza todos los bits X lugares a la izquierda, es fácil ver que cualquier número entero debe tener todos los bits en la mantisa que terminan a la derecha del punto decimal a cero.

Cualquier entero, excepto cero, tiene la siguiente forma en binario:

1x … x donde x -es representan los bits a la derecha de la MSB (el bit más significativo).

Debido a que excluimos el cero, siempre habrá un MSB que es uno, razón por la cual no se almacena. Para almacenar el número entero, debemos ponerlo en la forma mencionada anteriormente: -1 signo × 1.mantisa × 2 exponente – sesgo .

Eso dice lo mismo que desplazar los bits sobre el punto decimal hasta que solo quede el MSB hacia la izquierda del MSB. Todos los bits a la derecha del punto decimal se almacenan en la mantisa.

A partir de esto, podemos ver que podemos almacenar un máximo de 52 dígitos binarios aparte de la MSB.

De ello se deduce que el número más alto donde se almacenan explícitamente todos los bits es

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

Para esto, necesitamos establecer el exponente, de modo que el punto decimal se desplace 52 lugares. Si tuviéramos que boost el exponente en uno, no podemos saber el dígito de la derecha después del punto decimal.

 111(omitted)111x. 

Por convención, es 0. Poniendo toda la mantisa a cero, recibimos el siguiente número:

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

Eso es un 1 seguido de 53 ceros, 52 almacenados y 1 agregado debido al exponente.

Representa 2 53 , que marca el límite (tanto negativo como positivo) entre los cuales podemos representar con precisión todos los enteros. Si quisiéramos agregar uno a 2 53 , tendríamos que establecer el cero implícito (indicado por la x ) en uno, pero eso es imposible.

math.floor siempre devolverá un número entero y, por lo tanto, int(math.floor(some_float)) nunca introducirá errores de redondeo.

El error de redondeo ya podría math.floor(some_large_float) introducido en math.floor(some_large_float) , o incluso cuando se almacena un gran número en un flotador en primer lugar. (Los números grandes pueden perder precisión cuando se almacenan en flotadores).

Si necesita convertir una cadena flotante a un int, puede usar este método.

Ejemplo: '38.0' a 38

Para convertir esto en un int, puedes convertirlo en un flotante y luego en un int. Esto también funcionará para cadenas flotantes o cadenas enteras.

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

Nota : Esto eliminará cualquier número después del decimal.

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

Otro ejemplo de código para convertir un real / float en un entero usando variables. “vel” es un número real / flotante y se convierte al siguiente INTEGER más alto, “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)) 

Ya que está pidiendo la forma más segura, le daré otra respuesta que no sea la respuesta principal.

Una forma fácil de asegurarse de no perder ninguna precisión es verificar si los valores serían iguales después de convertirlos.

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

Si el valor flotante es 1.0, por ejemplo, 1.0 es igual a 1. Por lo tanto, la conversión a int se ejecutará. Y si el valor flotante es 1.1, int (1.1) equivale a 1, y 1.1! = 1. Por lo tanto, el valor seguirá siendo un valor flotante y no perderá precisión.