2010-03-12 12 views
9

Estoy un poco asustado por los resultados que obtengo cuando hago la aritmética de módulo en Objective-C. -1% 3 sale a ser -1, lo cual no es la respuesta correcta: de acuerdo con mi entendimiento, debería ser 2. -2% 3 está saliendo a -2, lo que tampoco es correcto: debería ser 1.Operador de módulo en Objective-C devuelve el resultado incorrecto

¿Hay algún otro método que deba utilizar además del operador% para obtener el resultado correcto?

+0

curioso si alguna de estas respuestas es módulo era lo que estaba buscando – kris

+1

Utilice frem (a, b) - el módulo que está esperando (que es el tipo utilizado en matemáticas estándar) se llama "resto" en la codificación . C tiene fmod() y frem(), estás usando mod (también conocido como "%"), necesitas usar rem. Módulo en Matemáticas === Resto (rem) en el código. Tonto, lo sé. –

+0

Se me ha informado que frem (a, b) estaba en GNU C solamente y no incluido en Obj-C. El equivalente sería este: 'a-b * floor ((float) a/(float) b)' –

Respuesta

7

Objective-C es un superconjunto de C99 y C99 define a % b como negativo cuando a es negativo. Consulte también the Wikipedia entry on the Modulo operation y this StackOverflow question.

Algo como (a >= 0) ? (a % b) : ((a % b) + b) (que no se ha probado y probablemente tiene paréntesis innecesarios) debería darle el resultado que desea.

+0

¡Genial! Me funcionó, sin embargo conté 2 situaciones que me causaron el error: (1) -n mod n da n en lugar de 0. (2) al definirlo como macro, algunos paréntesis se confunden. Termino haciendo: #define module (a, b) (a> = 0 || - (a) == (b))? (a)% (b): ((a)% (b) + b) – kahlo

2

ANSI C99 6.5.5 multiplicativa operadoras-

6.5.5.5: El resultado del operador / es el cociente de la división del primer operando por el segundo; el resultado del operador % es el resto. En ambas operaciones, si el valor del segundo operando es cero, el comportamiento no está definido.

6.5.5.6: Cuando se dividen los enteros, el resultado del operador / es el cociente algebraico con cualquier parte fraccional descartada (* 90). Si el cociente a/b es representable, la expresión (a/b)*b + a%b será igual a a.

* 90: Esto a menudo se denomina "truncamiento hacia cero".

El tipo de comportamiento de módulo en el que está pensando se denomina modulo/residuo de "aritmética modular" o "teoría de números". Utilizando la definición de aritmética modular/teoría de números del operador de módulo, no es sensitivo tener un resultado negativo. Este es (obviamente) no el estilo de comportamiento del módulo definido y utilizado por C99. No hay nada "incorrecto" con la forma C99, simplemente no es lo que esperabas. :)

0

una función explícita que le dará la respuesta correcta es al final, pero en primer lugar, aquí es una explicación de algunas de las otras ideas que se discutieron:

En realidad, (a >= 0) ? (a % b) : ((a % b) + b) sólo habrá lugar a la respuesta correcta si el número negativo, a, está dentro de un múltiplo de b.

En otras palabras: Si quieres encontrar: -1% 3, entonces seguro, (a >= 0) ? (a % b) : ((a % b)+ b) funcionará porque lo agregaste al final en ((a % b) + b).

-1 % 3 = -1 y -1 + 3 = 2, que es la respuesta correcta.

Sin embargo, si lo intenta con a = -4 y b = 3, entonces no va a trabajar:

-4 % 3 = -4 pero -4 + 3 = -1.

Si bien esto es técnicamente, también equivalente a 2 (módulo 3), no creo que esta sea la respuesta que está buscando.Probablemente estés esperando la forma canónica: que la respuesta siempre debe ser un número no negativo entre 0 y n-1.

Habría que añadir 3 dos veces para obtener la respuesta:

-4 + 3 = -1 
-1 + 3 = 2 

Aquí es una forma explícita de hacerlo:

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

** Ten cuidado! Asegúrate de mantener el molde (flotante) allí. De lo contrario, dividirá a/b como enteros y obtendrá una respuesta inesperada para los negativos. Por supuesto, esto significa que su resultado también será flotante. Será un número entero escrito como flotante, como 2.000000, por lo que es posible que desee convertir la respuesta completa a un número entero.

(int) (a - floor((float) a/b)*b) 
3

Spencer, hay una forma sencilla de pensar mods (la forma en que se define en las matemáticas, no se programa). En realidad es bastante sencillo:

Toma a todos los números enteros:

...- 9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ...

Ahora pensemos en los múltiplos de 3 (si está considerando mod 3). Comencemos con 0 y los múltiplos positivos de 3:

...- 9, -8, -7, -6, -5, -4, -3, -2, -1, , 1 , 2, 3 , 4, 5, 6 , 7, 8, 9 ...

estos son todos los números que tienen un resto de cero cuando se divide por 3, es decir, estos son todos los unos que mod a cero.

Ahora cambiemos todo este grupo por uno.

...- 9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1 , 2, 3, 4 , 5, 6, 7 , 8, 9 ...

estos son todos los números que tienen un resto de 1 cuando se divide por 3, es decir, estos son todos los que mOD a 1.

Ahora vamos turno todo este grupo nuevamente por uno.

...- 9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2 , 3, 4, 5 , 6, 7, 8 , 9 ...

estos son todos los números que tienen un resto de 2 cuando se divide por 3, es decir, estos son todos los que mOD a 2.

podrás observe que en cada uno de estos casos, los números seleccionados están espaciados por 3. Siempre tomamos cada tercer número porque estamos considerando el módulo 3. (Si estuviéramos haciendo mod 5, tomaríamos cada quinto número).

Por lo tanto, puede llevar este patrón hacia atrás en los números negativos. Solo mantén el espacio de 3.Usted obtendrá estas tres clases de congruencia (un tipo especial de clases de equivalencia , como se les llama en matemáticas):

... -9, -8, -7, -6 , -5, -4, -3 , -2, -1, 0 , 1, 2, 3 , 4, 5, 6 , 7, 8, 9 ...

...- 9, -8, -7, -6, -5 , -4, -3, -2 , -1, 0, 1 , 2, 3, 4 , 5, 6, 7 , 8, 9 ...

...- 9, -8, -7 , -6, -5, -4 , -3, -2, -1 , 0, 1, , 3, 4, , 6, 7, , 9 ...

La representación matemática estándar de todos estos números equivalentes es utilizar el residuo de la clase, que solo significa tomar el número no negativo más pequeño.

Así que por lo general, cuando estoy pensando en mods y yo estoy tratando con un número negativo, sólo pienso de añadir sucesivamente el número de módulo y otra vez hasta que llegue el primer 0 o un número positivo:

Si estamos haciendo mod 3, entonces con -1, solo agregue 3 una vez: -1 + 3 = 2. Con -4, agregue 3 dos veces porque una vez no es suficiente. Si agregamos +3 una vez, obtenemos -4 + 3 = -1, que sigue siendo negativo. Así que agregaremos +3 nuevamente: -1 + 3 = 2.

Probemos un número negativo mayor, como -23. Si continúa agregando +3, obtendrá:

-23, -20, -17, -14, -11, -8, -5, -2, 1. Tenemos un número positivo, por lo que detener. El residuo es 1, y esta es la forma que los matemáticos suelen usar.

1

Tuve el mismo problema, pero lo resolví. Todo lo que necesita hacer es comprobar si el número es positivo o negativo y si es negativo, es necesario agregar un número más:

//neg 
// -6 % 7 = 1 
int testCount = (4 - 10); 
if (testCount < 0) { 
    int moduloInt = (testCount % 7) + 7; // add 7 
    NSLog(@"\ntest modulo: %d",moduloInt); 
} 
else{ 
    int moduloInt = testCount % 7; 
    NSLog(@"\ntest modulo: %d",moduloInt); 
} 

// pos 
// 1 % 7 = 1 
int testCount = (6 - 5); 
if (testCount < 0) { 
    int moduloInt = (testCount % 7) + 7; // add 7 
    NSLog(@"\ntest modulo: %d",moduloInt); 
} 
else{ 
    int moduloInt = testCount % 7; 
    NSLog(@"\ntest modulo: %d",moduloInt); 
} 

Espero que ayude! A.

Cuestiones relacionadas