copiar borrar archivos python modulo

borrar - copiar archivos python



Módulo de Python en flotadores (3)

¿Alguien puede explicar cómo funciona el operador de módulo en Python? No puedo entender por qué 3.5 % 0.1 = 0.1 .


En realidad, no es cierto que 3.5 % 0.1 sea 0.1 . Puedes probar esto muy fácilmente:

>>> print(3.5 % 0.1) 0.1 >>> print(3.5 % 0.1 == 0.1) False

En realidad, en la mayoría de los sistemas, 3.5 % 0.1 es 0.099999999999999811 . Pero, en algunas versiones de Python, str(0.099999999999999811) es 0.1 :

>>> 3.5 % 0.1 0.099999999999999811 >>> repr(3.5 % 0.1) ''0.099999999999999811'' >>> str(3.5 % 0.1) ''0.1''

Ahora, probablemente se esté preguntando por qué el 3.5 % 0.1 es 0.099999999999999811 lugar de 0.0 . Eso se debe a los problemas habituales de redondeo de coma flotante. Si no ha leído lo que todo científico informático debería saber sobre la aritmética de punto flotante , debería hacerlo, o al menos el breve resumen en Wikipedia de este tema en particular.

Tenga en cuenta también que 3.5/0.1 no es 34 , es 35 . Entonces, 3.5/0.1 * 0.1 + 3.5%0.1 es 3.5999999999999996 , que ni siquiera está cerca de 3.5 . Esto es bastante fundamental para la definición de módulo, y está mal en Python, y en casi todos los demás lenguajes de programación.

Pero Python 3 viene al rescate allí. La mayoría de las personas que saben // saben que se trata de cómo se hace una "división de enteros" entre enteros, pero no se dan cuenta de que es la forma en que se hace la división compatible con módulos entre cualquier tipo. 3.5//0.1 es 34.0 , entonces 3.5//0.1 * 0.1 + 3.5%0.1 es (al menos dentro de un pequeño error de redondeo de) 3.5 . Esto se transfirió a 2.x, por lo que (dependiendo de su versión y plataforma exactas) puede confiar en esto. Y, si no, puede usar divmod(3.5, 0.1) , que regresa (dentro del error de redondeo) (34.0, 0.09999999999999981) todo el camino de regreso a las brumas del tiempo. Por supuesto, aún esperaba que esto fuera (35.0, 0.0) , no (34.0, almost-0.1) , pero no puede tener eso debido a errores de redondeo.

Si está buscando una solución rápida, considere usar el tipo Decimal :

>>> from decimal import Decimal >>> Decimal(''3.5'') % Decimal(''0.1'') Decimal(''0.0'') >>> print(Decimal(''3.5'') % Decimal(''0.1'')) 0.0 >>> (Decimal(7)/2) % (Decimal(1)/10) Decimal(''0.0'')

Esta no es una panacea mágica, por ejemplo, todavía tendrá que lidiar con el error de redondeo siempre que el valor exacto de una operación no sea finitamente representable en la base 10, pero los errores de redondeo se alinean mejor con los casos que la intuición humana espera ser problemático (También hay ventajas en Decimal over float en cuanto a que puede especificar precisiones explícitas, rastrear dígitos significativos, etc., y que en realidad es el mismo en todas las versiones de Python de 2.4 a 3.3, mientras que los detalles sobre float han cambiado dos veces en el mismo Es solo que no es perfecto, porque sería imposible.) Pero cuando sabes de antemano que tus números son exactamente representables en la base 10, y no necesitan más dígitos que la precisión que has configurado, trabajará.


Modulo te da el rest de una división. 3.5 dividido por 0.1 debería darte 35 con un resto de 0 . Pero como los flotadores se basan en potencias de dos, los números no son exactos y se obtienen errores de redondeo.

Si necesita que su división de números decimales sea exacta, use el módulo decimal:

>>> from decimal import Decimal >>> Decimal(''3.5'') / Decimal(''0.1'') Decimal(''35'') >>> Decimal(''3.5'') % Decimal(''0.1'') Decimal(''0.0'')

Como estoy siendo criticado que mi respuesta es engañosa aquí viene toda la historia:

0.1 es ligeramente más grande que 0.1

>>> ''%.50f'' % 0.1 ''0.10000000000000000555111512312578270211815834045410''

Si divide el flotador 3.5 por dicho número, obtendrá un descanso de casi 0.1 .

Comencemos con el número 0.11 y continuemos agregando ceros entre los dos dígitos para reducirlo y mantenerlo más grande que 0.1 .

>>> ''%.10f'' % (3.5 % 0.101) ''0.0660000000'' >>> ''%.10f'' % (3.5 % 0.1001) ''0.0966000000'' >>> ''%.10f'' % (3.5 % 0.10001) ''0.0996600000'' >>> ''%.10f'' % (3.5 % 0.100001) ''0.0999660000'' >>> ''%.10f'' % (3.5 % 0.1000001) ''0.0999966000'' >>> ''%.10f'' % (3.5 % 0.10000001) ''0.0999996600'' >>> ''%.10f'' % (3.5 % 0.100000001) ''0.0999999660'' >>> ''%.10f'' % (3.5 % 0.1000000001) ''0.0999999966'' >>> ''%.10f'' % (3.5 % 0.10000000001) ''0.0999999997'' >>> ''%.10f'' % (3.5 % 0.100000000001) ''0.1000000000''

La última línea da la impresión de que finalmente hemos llegado a 0.1 pero cambiar las cadenas de formato revela la verdadera naturaleza:

>>> ''%.20f'' % (3.5 % 0.100000000001) ''0.09999999996600009156''

El formato flotante predeterminado de python simplemente no muestra la precisión suficiente para que el 3.5 % 0.1 = 0.1 y el 3.5 % 0.1 = 35.0 . Realmente es 3.5 % 0.100000... = 0.999999... y 3.5 / 0.100000... = 34.999999.... En el caso de la división, incluso terminas con el resultado exacto, ya que 34.9999... se redondea por completo hasta 35.0 .

Dato curioso: si usas un número que es ligeramente más pequeño que 0.1 y realizas la misma operación, terminas con un número ligeramente mayor que 0 :

>>> 1.0 - 0.9 0.09999999999999998 >>> 35.0 % (1.0 - 0.9) 7.771561172376096e-15 >>> ''%.20f'' % (35.0 % (1.0 - 0.9)) ''0.00000000000000777156''

Usando C ++ incluso puedes mostrar que 3.5 dividido por el flotante 0.1 no es 35 sino algo un poco más pequeño.

#include <iostream> #include <iomanip> int main(int argc, char *argv[]) { // double/float, rounding errors do not cancel out std::cout << "double/float: " << std::setprecision(20) << 3.5 / 0.1f << std::endl; // double/double, rounding errors cancel out std::cout << "double/double: " << std::setprecision(20) << 3.5 / 0.1 << std::endl; return 0; }

ideone.com/fTNVho

En Python 3.5 / 0.1 le da el resultado exacto de 35 porque los errores de redondeo se cancelan entre sí. Realmente es 3.5 / 0.100000... = 34.9999999... Y 34.9999... es tan largo que terminas con exactamente 35 . El programa C ++ lo muestra muy bien ya que puedes mezclar dobles y flotar y jugar con las precisiones de los números de coma flotante.


Tiene que ver con la naturaleza inexacta de la aritmética de coma flotante. 3.5 % 0.1 me da 0.099999999999999811 , así que Python está pensando que 0.1 se divide en 3.5 a lo más 34 veces, con 0.099999999999999811 sobrante. No estoy seguro exactamente qué algoritmo se está utilizando para lograr este resultado, pero esa es la esencia.