objective c - Comportamiento extraño de Objective-C Mod para números negativos
modulo (12)
Así que pensé que los números negativos, cuando se modifican deben colocarse en el espacio positivo ... No puedo lograr que esto suceda en Objective-C
Espero esto
-1 % 3 = 2
0 % 3 = 0
1 % 3 = 1
2 % 3 = 2
Pero consigue esto
-1 % 3 = -1
0 % 3 = 0
1 % 3 = 1
2 % 3 = 2
¿Por qué es esto y hay una solución alternativa?
En C y Objective-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, por supuesto, 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).
En lugar de a%b
Uso: ab*floor((float)a/(float)b)
Esperas un resto y estás usando 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)(ab*floor((float)a/(float)b)))
Entonces podrías usar rem(-1,3)
en tu código y debería funcionar bien.
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. Ver la entrada de wikipedia también .
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.
La respuesta de UncleO es probablemente más sólida, pero si quieres hacerlo en una sola línea, estás seguro de que el valor negativo no será más negativo que una única iteración del mod (por ejemplo, si solo restas en la mayoría del valor de mod en cualquier momento) puedes simplificarlo a una sola expresión:
int result = (n + 3) % 3;
Como de todos modos está haciendo la modificación, agregar 3 al valor inicial no tiene efecto a menos que n sea negativo (pero no menos de -3), en cuyo caso causa que el resultado sea el módulo positivo esperado.
No solo el script java, casi todos los idiomas muestran la respuesta incorrecta ''lo que coneybeare dice es correcto, cuando tenemos modo, tenemos que obtener el resto El resto no es más que lo que queda después de la división y debería ser un entero positivo ...
Si marca la recta numérica, puede comprender que
También me enfrento al mismo problema en VB y me obligó a agregar un cheque adicional como si el resultado fuera negativo. Tenemos que agregar el divisor al resultado
Por qué: porque esa es la forma en que 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 la de uncleo.
Si este será 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: Para resumir, use r = ( n + ( m % n ) ) % n
Si n tiene un rango limitado, entonces puede obtener el resultado que desea simplemente agregando un múltiplo constante conocido de 3 que sea mayor que el valor absoluto del mínimo.
Por ejemplo, si n está limitado a -1000..2000, puede usar la expresión:
result = (n+1002) % 3;
Asegúrese de que el máximo más su constante no se desborde cuando se suma.
También habría esperado un número positivo, pero encontré esto, de ISO / IEC 14882: 2003: Lenguajes de programación - C ++, 5.6.4 (que se encuentra en el artículo de la Wikipedia sobre la operación del módulo ):
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
Tenemos un problema de lenguaje:
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 estas conversaciones está hablando de hacer matemáticas en una línea numérica 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, quiere el operador de mod del matemático y tiene 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.
result = n % 3;
if( result < 0 ) result += 3;
No realice operaciones mod adicionales como se sugiere en las otras respuestas. Son muy caros e innecesarios.