2012-02-14 26 views
20

Hoy en el trabajo tuve una discusión interesante con uno de mis compañeros de trabajo. Se sorprendió cuando tuvo la siguiente que le ocurra:¿Por qué el operador% se conoce como el operador "módulo" en lugar del operador "restante"?

assert(-1 % 10 == -1) //Expecting 9 

Por eso, cuando me vino a preguntar por él, le dije "bueno, eso tiene sentido cuando se divide por 10 -1, se obtiene 0. con -1 restante. Sin embargo, su argumento era que el operador de módulo se supone que es fiel al modelo "siempre positivo". Investigué un poco y encontré que el módulo al que se refería era el siguiente:

Sea q el cociente entero de ayn. Deje r ser el resto. Entonces:

a = n * q + r

La definición I estaba usando, sin embargo, parece ser la versión Knuth de módulo, que es:

Sea q el suelo de un dividido por n. Deje r ser el resto. Entonces:

r = a - n * q

Por lo tanto, mi pregunta es la razón por la que terminó en el estándar de FORTRAN (y posteriormente la norma C) para que el operador módulo truncar hacia 0? Parece un nombre inapropiado para mí llamarlo "módulo" y no "resto" (en matemáticas, la respuesta debería ser 9). ¿Esto está relacionado con cómo el hardware está haciendo la división?

Como referencia:

TLDR; ¿Es el hardware la razón por la que el operador del módulo trunca hacia 0?

+3

¿Se da cuenta de que esta pregunta y los enlaces están llenos de razones para evitar módulo con operandos negativos? –

+4

Evitarlo no es el objetivo de la pregunta. –

+0

¿Se llama realmente "módulo" o "mod"? ¿Cuántas sílabas tiene "mod"? ¿Qué tal "resto"? – supercat

Respuesta

15

Parece un nombre inapropiado para mí llamarlo "módulo" y no "resto" (En matemáticas, la respuesta debería ser 9).

C lo llama el operador% y llama al resultado el resto. C++ copia esto de C. Ninguno de los dos idiomas lo llama el operador de módulo. Esto también explica por qué el resto es negativo: porque el operador/trunca hacia 0, y (a/b) * b + (a % b) debe ser igual a a.

Edición: David Rodríguez con razón señala que C++ hace definir una clase de plantilla std::modulus, que llama operator%. En mi opinión, esa clase tiene un nombre pobre. Excavando un poco, se hereda de STL donde ya fue nombrado como lo es ahora. La descarga para STL dice "El STL fue desarrollado en SGI MIPSproTM C++ 7.0, 7.1, 7.2 y 7.2.1.", y hasta donde puedo decir sin tener realmente el compilador y el hardware, MIPSpro pasa la división a la CPU y el hardware MIPS trunca a 0, lo que significa que std::modulus siempre ha sido mal llamado.

+2

+1 Acabo de comprobar el estándar C++: * el operador% binario produce el resto de la división de la primera expresión por el segundo *, por lo que +1 para el operador mismo. Ahora otro problema es el nombre del funtor en 'funcional' que usa' operator% 'que se llama * modulus *, por lo que al menos parte de la pregunta se deja abierta ... –

+0

@ DavidRodríguez-dribeas Buen hallazgo, no puedo responder en la historia detrás de eso y por qué se llama así. – hvd

+1

Creo que el origen de la confusión, al menos para mí, es que si usas 'fmod', por ejemplo, no obtendrás un módulo verdadero, como su nombre implicaría. Parece que las dos palabras se usan de forma intercambiable. Pero está en lo cierto, el verdadero estándar de C++ dice "resto". La fuente original que utilicé fue MSDN porque estaba buscando específicamente VS2003. http://msdn.microsoft.com/en-us/library/ty2ax9z9(v=vs.71).aspx. Parece que son incorrectos. –

4

% es el operador restante en C y C++.

En el estándar de C++, se llama el operador % y se produce el el resto de la división. En la Norma C se llama el % operador y desde C99 en realidad es una operador de resto. Los operadores de módulo y resto difieren con respecto a los valores negativos.

El operador % se define en C y C++ con a == (a/b * b) + a % b.

El truncamiento de la división de enteros hacia 0 en C se realiza desde C99. En C89 se definió su implementación (y % puede ser un operador de módulo en C89). C++ también realiza el truncamiento hacia cero para la división de enteros.

Cuando el truncamiento se realiza hacia cero, % es un operador de resto y el signo del resultado es el signo del dividendo. Cuando el truncamiento se realiza hacia el infinito menos, % es un operador de módulo y el signo del resultado es el signo del divisor.

Por las razones por C cambió el comportamiento definido aplicación de la división entera con respecto truncamiento, Doug Gwyn de C comittee dijo:

C99 impone un requisito compatibles Fortran-en un intento por atraer a más rogrammers Fortran y para ayudar en la conversión de código Fortran a C.

C99 Fundamento dice con respecto truncamiento hacia la división cero entero:

En Fortran, sin embargo, el resultado siempre se truncará hacia cero, y la sobrecarga parece ser aceptable para la comunidad de programación numérica. Por lo tanto, C99 ahora requiere un comportamiento similar, que debería facilitar portabilidad de código de Fortran a C.

En gcc el comportamiento aplicación en C89 ha sido siempre el truncamiento hacia cero.

Así que % es el operador restante en C99, C++ y también en Java pero no es el operador restante en todos los lenguajes de programación. En Ruby y Python, % es, de hecho, el operador de módulo (la división entera se realiza hacia menos infinito en estos idiomas). Haskhell y Scheme tienen dos operadores separados: mod y rem para Haskell, y modulo y remainder para Scheme.

+0

Haskhell ¿eh? ;) – NateS

1

Me temo que el problema surge de un malentendido de las matemáticas. El módulo de congruencia n es una relación de equivalencia , por lo que solo define clases de equivalencia. Por lo tanto, es no correctos para decir que 'en matemáticas, la respuesta realmente debería ser 9' porque podría ser también 19, 29, y así sucesivamente. Y, por supuesto, puede ser -1 o -11.Hay infinitos elementos de la clase de los números n que son n ≡ -1 mod (10).

http://en.wikipedia.org/wiki/Modular_arithmetic

http://en.wikipedia.org/wiki/Congruence_relation

Entonces, la pregunta correcta podrían ser: qué elemento de la clase de los números que son ≡ -1 mod (10) será el resultado de -1% 10 en C++ ? Y la respuesta es: el resto de la división de -1 por 10. No hay misterio.

PS Su definición de módulo y de Knuth son, ehm, equivalente ... :)

+0

Esas definiciones no son iguales. Conecte el -1% 10 y verá por qué. –

+0

¿Por qué? "Deje q sea el cociente entero de a y n" es lo mismo que "Deje q sea el piso de a dividido por n". El resto de la definición es perfectamente igual, dado que voltea n * q en el otro lado de la igualdad ...;) – ascanio

+3

Muchas personas esperarían que la operación% devolvería un representante único de la clase de equivalencia. Este no es el caso, porque devuelve diferentes representantes para pares de enteros que pertenecen a la misma clase de equivalencia (x y -x, x! = 0). Su argumento de que -1% 10 podría ser -1 o -11 solo tendría sentido si siempre se utilizara el mismo desplazamiento desde [0, m-1] (por ejemplo, si -1% 10 = -11, luego 9% 10 también debería tener sentido) ser -11 y no 9). –

Cuestiones relacionadas