¡Que esto funcione no es trivial en absoluto! Es una propiedad de la representación de coma 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)) podría ser 1.
Esta publicación explica por qué funciona en ese rango .
En un doble, puede representar enteros de 32 bits sin ningún problema. No puede haber problemas de redondeo. Más precisamente, los dobles pueden representar todos los enteros entre 2 53 y -2 53 inclusive .
Breve explicación : un doble puede almacenar hasta 53 dígitos binarios. Cuando necesita más, el número se rellena con ceros a la derecha.
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.
Agregar uno a 111 (omitido) 111 (53 unidades) produce 100 ... 000, (53 ceros). Como sabemos, podemos almacenar 53 dígitos, lo que hace que el margen cero más a la derecha.
De aquí 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 casos especiales que son irrelevantes aquí):
-1 signo × 1.mantissa × 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 cambia 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 número entero excepto cero tiene la siguiente forma en binario:
1x ... x donde las x -es representan los bits a la derecha del MSB (bit más significativo).
Debido a que excluimos cero, siempre habrá un MSB que sea uno, razón por la cual no se almacena. Para almacenar el entero, debemos llevarlo a la forma mencionada anteriormente: -1 signo × 1.mantissa × 2 exponente - sesgo .
Eso dice lo mismo que desplazar los bits sobre el punto decimal hasta que solo esté 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 como máximo 52 dígitos binarios aparte del MSB.
Se deduce que el número más alto donde todos los bits se almacenan explícitamente 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 aumentar el exponente en uno, no podríamos conocer el dígito de derecha a izquierda después del punto decimal.
111(omitted)111x.
Por convención, es 0. Al establecer toda la mantisa en cero, recibimos el siguiente número:
100(omitted)00x. = 100(omitted)000.
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 el que 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 el x
) en uno, pero eso es imposible.
math.floor
devuelve un flotante en v2.6 , pero devuelve un entero en v3 . En este punto (casi seis años después del OP), este problema podría aparecer raramente.