2009-06-13 14 views
42

así que pensé que los números negativos, cuando mod'ed debe ser puesto en espacio positivo ... no puedo conseguir que esto suceda en Objective-Cextraño comportamiento de Objective-C Mod para números negativos

me esperaba esto:

-1 % 3 = 2 
0 % 3 = 0 
1 % 3 = 1 
2 % 3 = 2 

Pero conseguir este

-1 % 3 = -1 
0 % 3 = 0 
1 % 3 = 1 
2 % 3 = 2 

¿Por qué es esto y es que hay alguna solución?

+0

Clojure es el primer idioma que he encontrado que implementa mod correctamente. ¡Hurra! –

+2

@ToddOwen: Python también lo hace correctamente – Claudiu

+0

@Todd, Lisp tiene ambos. – Pacerier

Respuesta

53
result = n % 3; 
if(result < 0) result += 3; 

No realice operaciones de mod adicionales como se sugiere en las otras respuestas. Son muy caros e innecesarios.

+1

¿No depende del procesador si los condicionales son mejores o peores que un módulo? – Nosredna

+2

Nunca he visto un procesador donde la división o módulo no sea la operación más lenta. Verificar el valor negativo se reduce a probar el valor de un bit, por lo que suele ser una de las instrucciones más rápidas. – UncleO

+0

Sí. Eso es probablemente correcto. Creo que en el Core Duo Intels, una división es algo así como 15-17 ciclos. Veo que mucha gente trata de evitar la bifurcación hoy en día. Pero con un mod la rama probablemente valga la pena. – Nosredna

4

lo que habría esperado un número positivo, también, pero me encontré con esto, de la norma ISO/IEC 14882: 2003: Los lenguajes de programación - C++, 5.6.4 (que se encuentra en el Wikipedia article on the modulus operation):

El operador% binario produce el resto de la división de la primera expresión por el segundo. .... Si ambos operandos son no negativos, el resto no es negativo; si no, el signo del resto está definido por la implementación

+1

Hooray para especificaciones vagas. : | – devios1

14

En C y el objetivo C, los operadores de división y módulo realizan el truncamiento hacia cero. a/b es floor(a/b) si a/b > 0, de lo contrario es ceiling(a/b) si a/b < 0. Siempre es el caso que a == (a/b) * b + (a % b), a menos que b sea 0. Como consecuencia, positive % positive == positive, positive % negative == positive, negative % positive == negative y negative % negative == negative (puede resolver la lógica de los 4 casos, aunque es un poco complicado).

+2

+1 para _why_. –

0

Hay dos opciones para el resto, y el signo depende del idioma. ANSI C elige el signo del dividendo. Sospecho que es por eso que ves que Objective-C también lo hace. See the wikipedia entry as well.

4

Si este es el comportamiento, y usted sabe que lo será, entonces para m % n = r, simplemente use r = n + r. Si no está seguro de lo que sucederá aquí, use entonces r = r % n.

Editar: En resumen, el uso r = (n + (m % n)) % n

+1

Si acabas de decir que debería hacerlo (-1 + 3)% 3 = 2, estoy de acuerdo. :-) – Nosredna

+1

Yo diría que do (3 + (-1% 3))% 3 == (3 + (-1))% 3 == (2% 3) == 2 – maxwellb

+0

Gotcha. Eso es bueno. Se puede hacer con un condicional (si o ternario) también. – Nosredna

1

JavaScript hace esto, también. Me han atrapado un par de veces. Piense en ello como un reflejo alrededor de cero en lugar de una continuación.

8

Si n tiene un rango limitado, entonces puede obtener el resultado que desea simplemente al agregar un múltiplo constante conocido de 3 que es mayor que el valor absoluto del mínimo.

Por ejemplo, si n se limita a -1000..2000, entonces se puede usar la expresión:

result = (n+1002) % 3; 

Asegúrese de que el máximo, además de su constante no se desbordará cuando se suman.

1

Motivo: porque así es como se especifica el operador de mod en el estándar C (recuerde que Objective-C es una extensión de C). Confunde a la mayoría de las personas que conozco (como yo) porque es sorprendente y tienes que recordarlo.

En cuanto a una solución: yo usaría uncleo's.

+0

Sí, confuso al igual que resta en el eje y para subir. Solo una de esas cosas preferidas de los primeros diseñadores de la lengua. Molesto al principio; probablemente útil más adelante. De hecho, apostaría a que el mod trabajando así tenía una gran utilidad cuando los programadores tenían que diseñar funciones compactas para obtener sus bytes en sus programas, el mismo motivo que las matrices comienzan en el índice 0 y no en el índice 1, hizo las matemáticas más compactables –

7

Tenemos un problema de idioma:

 
math-er-says: i take this number plus that number mod other-number 
code-er-hears: I add two numbers and then devide the result by other-number 
code-er-says: what about negative numbers? 
math-er-says: WHAT? fields mod other-number don't have a concept of negative numbers? 
code-er-says: field what? ... 
  • la persona de matemáticas en esta conversación es hablar de hacer matemáticas en una línea de números circular. Si restas del fondo, te envuelves en la parte superior.
  • la persona del código está hablando de un operador que calcula el resto.

En este caso, usted quiere que el operador de mod del matemático tenga el resto de la función a su disposición. puede convertir el operador restante en el operador de mod del matemático comprobando si cayó del fondo cada vez que resta.

+0

los números naturales definen una división tal que (n + d)/d == (n/d) +1. Los números reales también. Los números reales también admiten - (n/d) == (- n)/d, pero los números naturales no. Es posible que los enteros admitan un axioma u otro, pero no ambos. Si bien el lenguaje de programación podría mantener el primer axioma para enteros y algunos lo hacen, los creadores de FORTRAN decidieron apoyar el segundo en su lugar, y muchos otros lenguajes han seguido su ejemplo. – supercat

0

No sólo java script, casi todos los idiomas muestra la respuesta equivocada' lo Coneybeare dicho es correcto, cuando hemos mode'd tenemos que conseguir resto El resto no es más que lo que queda después de la división y que debería ser una entero positivo ....

Si marca la línea de números se puede entender que

que también se enfrentan a la misma cuestión en VB y, lo que hizo que añada fuerza cheque extra como si el resultado es negativo tenemos que agregar el divisor al resultado

1

La respuesta de UncleO es probablemente más sólida, pero si quiere hacerlo en una sola línea, y está seguro de que el valor negativo no será más negativo que una sola iteración del mod (por ejemplo, si está sólo alguna vez restando como máximo el valor de la mOD en cualquier momento) se puede simplificar a una sola expresión:

int result = (n + 3) % 3; 

Desde que está haciendo el Ministerio de Defensa de todos modos, añadiendo 3 al valor inicial no tiene ningún efecto a menos n es negativo (pero no menos de -3) en cuyo caso causa que el resultado sea el módulo positivo esperado.

0

En lugar de a%b

Uso: a-b*floor((float)a/(float)b)

Usted está esperando resto y está utilizando módulo. En matemáticas son lo mismo, en C son diferentes. GNU-C tiene Rem() y Mod(), objetivo-c solo tiene mod(), así que tendrás que usar el código anterior para simular la función rem (que es lo mismo que mod en el mundo matemático, pero no en la programación mundo [para la mayoría de los idiomas al menos])


También tenga en cuenta que podría definir una macro fácil de usar para esto.

#define rem(a,b) ((int)(a-b*floor((float)a/(float)b)))

Entonces es posible que utilices rem(-1,3) en el código y que debería funcionar bien.