signo resto redondear programa para numeros hacer funcion enteros dividir con python ruby perl6 integer-division raku

resto - signo de division en python



¿Por qué la división de enteros se redondea hacia abajo en muchos lenguajes de script? (5)

En los idiomas que he probado, - (x div y ) no es igual a -x div y ; He probado // en Python, / en Ruby, div en Perl 6; C tiene un comportamiento similar .

Ese comportamiento suele ser de acuerdo con las especificaciones, ya que div se define generalmente como el redondeo hacia abajo del resultado de la división , sin embargo, no tiene mucho sentido desde el punto de vista aritmético, ya que hace que div comporte de una manera diferente dependiendo de en el signo, y causa confusión como esta publicación sobre cómo se hace en Python .

¿Hay alguna razón específica detrás de esta decisión de diseño, o simplemente la div define de esa manera desde cero? Al parecer, Guido van Rossum usa un argumento de coherencia en una publicación del blog que explica cómo se hace en Python, pero también puede tener coherencia si decide redondear.

(Inspirado por esta pregunta por PMurias en el canal IRC # perl6 )


Como dijo Paula, es por el resto.

El algoritmo se basa en la división euclidiana .

En Ruby, puedes escribir esto reconstruyendo el dividendo con consistencia:

puts (10/3)*3 + 10%3 #=> 10

Funciona igual en la vida real. 10 manzanas y 3 personas. Ok, puedes cortar una manzana en tres, pero yendo fuera de los enteros establecidos.

Con números negativos también se mantiene la consistencia:

puts (-10/3)*3 + -10%3 #=> -10 puts (10/(-3))*(-3) + 10%(-3) #=> 10 puts (-10/(-3))*(-3) + -10%(-3) #=> -10

El cociente siempre es redondeado hacia abajo (hacia abajo a lo largo del eje negativo) y el recordatorio sigue:

puts (-10/3) #=> -4 puts -10%3 #=> 2 puts (10/(-3)) #=> -4 puts 10%(-3) # => -2 puts (-10/(-3)) #=> 3 puts -10%(-3) #=> -1


Debido a que la implicación de la división de enteros es que la respuesta completa incluye un resto.


Idealmente, nos gustaría tener dos operaciones div y mod , satisfactorias, para cada b>0 :

  1. (a div b) * b + (a mod b) = a
  2. 0 <= (a mod b) < b
  3. (-a) div b = -(a div b)

Esto es, sin embargo, una imposibilidad matemática. Si todo lo anterior fuera cierto, tendríamos

1 div 2 = 0 1 mod 2 = 1

ya que esta es la única solución entera para (1) y (2). Por lo tanto, también tendríamos, por (3),

0 = -0 = -(1 div 2) = (-1) div 2

lo cual, por (1), implica

-1 = ((-1) div 2) * 2 + ((-1) mod 2) = 0 * 2 + ((-1) mod 2) = (-1) mod 2

haciendo (-1) mod 2 < 0 que contradice (2).

Por lo tanto, tenemos que renunciar a alguna propiedad entre (1), (2) y (3).

Algunos lenguajes de programación se dan por vencidos (3) y hacen div redondeados hacia abajo (Python, Ruby).

En algunos casos (raros) el lenguaje ofrece operadores de división múltiple. Por ejemplo, en Haskell tenemos div,mod satisfaciendo solo (1) y (2), de manera similar a Python, y también tenemos quot,rem satisfaciendo solo (1) y (3). El último par de operadores redondea la división hacia cero , al precio de devolver los (-1) `quot` 2 = 0 negativos, por ejemplo, tenemos (-1) `quot` 2 = 0 y (-1) `rem` 2 = (-1) .

C # también abandona (2) y permite que % devuelva un resto negativo. Coherentemente, la división entera se redondea hacia cero. Java, Scala, Pascal y C, a partir de C99, también adoptan esta estrategia.


Las operaciones de punto flotante están definidas por IEEE754 teniendo en cuenta las aplicaciones numéricas y, por defecto, redondean al valor representable más cercano de una manera muy estrictamente definida.

Las operaciones de enteros en computadoras no están definidas por estándares internacionales generales. Las operaciones otorgadas por los idiomas (especialmente las de la familia C) tienden a seguir lo que proporcione la computadora subyacente. Algunos lenguajes definen ciertas operaciones con mayor robustez que otros, pero para evitar implementaciones demasiado difíciles o lentas en las computadoras disponibles (y populares) de su tiempo, elegirán una definición que siga su comportamiento de manera bastante cercana.

Por esta razón, las operaciones de enteros tienden a envolverse alrededor del desbordamiento (para la suma, la multiplicación y el desplazamiento hacia la izquierda) y se redondean hacia el infinito negativo cuando se produce un resultado inexacto (para la división y el desplazamiento hacia la derecha). Ambos son simples truncamientos en su extremo respectivo del entero en la aritmética binaria de complemento a dos; La forma más sencilla de manejar una caja de esquina.

Otras respuestas discuten la relación con el resto o el operador de módulo que un idioma puede proporcionar junto con la división. Lamentablemente lo tienen al revés. El resto depende de la definición de división, no al revés , mientras que el módulo se puede definir independientemente de la división: si ambos argumentos son positivos y la división se redondea, funcionan como si fueran iguales, por lo que la gente rara vez se da cuenta.

La mayoría de los lenguajes modernos proporcionan un operador de resto o un operador de módulo, raramente ambos. Una función de biblioteca puede proporcionar la otra operación para las personas que se preocupan por la diferencia, que es que el resto conserva el signo del dividendo, mientras que el módulo conserva el signo del divisor.


Wikipedia tiene un gran artículo sobre esto , que incluye tanto la historia como la teoría.

Siempre que un lenguaje satisfaga la propiedad de la división euclidiana de que (a/b) * b + (a%b) == a , tanto la división de pisos como la división de truncamiento son coherentes y aritméticamente sensibles.

Por supuesto, a la gente le gusta argumentar que uno es obviamente correcto y el otro obviamente equivocado, pero tiene más el carácter de una guerra santa que una discusión sensata, y generalmente tiene más que ver con la elección de su lenguaje preferido al principio que cualquier otra cosa. más. También a menudo tienden a argumentar principalmente por el % elegido, aunque probablemente tenga más sentido elegir / primero y luego simplemente seleccionar el % que coincida.

  • Pisos (como Python):
    • No menos una autoridad que Donald Knuth lo sugiere.
    • Aparentemente, el % después del signo del divisor es lo que aproximadamente el 70% de todos los estudiantes adivinan
    • El operador generalmente se lee como mod o modulo lugar de remainder .
    • "C lo hace", que ni siquiera es verdad. 1
  • Truncando (como C ++):
    • Hace que la división de enteros sea más consistente con la división flotante IEEE (en el modo de redondeo predeterminado).
    • Más CPUs lo implementan. (Puede que no sea cierto en diferentes momentos de la historia).
    • El operador lee el modulo lugar del remainder (aunque esto realmente discute su punto).
    • Conceptualmente, la propiedad de la división tiene más que ver con el resto que con el módulo.
    • El operador se lee mod lugar de modulo , por lo que debe seguir la distinción de Fortran. (Esto puede sonar tonto, pero puede haber sido el factor decisivo para C99. Ver este hilo .)
  • "Euclidiano" (como Pascal - / floor o trunca dependiendo de los signos, por lo que % nunca es negativo):
    • Niklaus Wirth argumentó que a nadie le sorprende el cambio positivo.
    • Raymond T. Boute argumentó más tarde que no se puede implementar la división euclidiana ingenuamente con ninguna de las otras reglas.

Un número de idiomas proporcionan ambos. Normalmente, como en Ada, Modula-2, algunos Lisps, Haskell y Julia, utilizan nombres relacionados con mod para el operador de estilo Python y rem para el operador de estilo C ++. Pero no siempre: Fortran, por ejemplo, llama a las mismas cosas modulo y mod (como se mencionó anteriormente para C99).

No sabemos por qué Python, Tcl, Perl y los otros lenguajes de script influyentes en su mayoría eligieron el piso. Como se señaló en la pregunta, la respuesta de Guido van Rossum solo explica por qué tuvo que elegir una de las tres respuestas coherentes, no por la que eligió la que hizo.

Sin embargo, sospecho que la influencia de C fue clave. La mayoría de los lenguajes de secuencias de comandos se implementan (al menos inicialmente) en C, y toman prestado su inventario de operadores de C. El % definido % la implementación de C89 está obviamente dañado, y no es adecuado para un lenguaje "amigable" como Tcl o Python. Y C llama al operador "mod". Así que van con el módulo, no el resto.

1. A pesar de lo que dice la pregunta, y muchas personas lo utilizan como argumento, C en realidad no tiene un comportamiento similar al de Python y sus amigos. C99 requiere división truncada, no pisos. C89 permitió cualquiera, y también permitió cualquiera de las versiones de mod, por lo que no hay garantía de la propiedad de la división, y no hay manera de escribir código portátil haciendo división de enteros con signo. Eso es solo roto