operador ejemplos c# math modulo

c# - ejemplos - La modificación del número negativo está derritiendo mi cerebro



operador % c# (8)

Estoy tratando de modificar un entero para obtener una posición de matriz para que gire en redondo. Hacer i % arrayLength funciona bien para números positivos, pero para números negativos, todo va mal.

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

entonces necesito una implementación de

int GetArrayIndex(int i, int arrayLength)

tal que

GetArrayIndex( 4, 3) == 1 GetArrayIndex( 3, 3) == 0 GetArrayIndex( 2, 3) == 2 GetArrayIndex( 1, 3) == 1 GetArrayIndex( 0, 3) == 0 GetArrayIndex(-1, 3) == 2 GetArrayIndex(-2, 3) == 1 GetArrayIndex(-3, 3) == 0 GetArrayIndex(-4, 3) == 2

He hecho esto antes, pero por alguna razón está derritiendo mi cerebro hoy :(


Añadiendo algo de comprensión.

Según la definición euclidiana, el resultado del mod debe ser siempre positivo.

Ex:

int n = 5; int x = -3; int mod(int n, int x) { return ((n%x)+x)%x; }

Salida:

-1


Implementación de línea única usando % solo una vez:

int mod(int k, int n) { return ((k %= n) < 0) ? k+n : k; }


La respuesta de ShreevatsaR no funcionará para todos los casos, incluso si agrega "if (m <0) m = -m;", si representa dividendos / divisores negativos.

Por ejemplo, -12 mod -10 será 8, y debería ser -2.

La siguiente implementación funcionará tanto para dividendos / divisores positivos como negativos y cumple con otras implementaciones (a saber, Java, Python, Ruby, Scala, Scheme, Javascript y Google''s Calculator):

internal static class IntExtensions { internal static int Mod(this int a, int n) { if (n == 0) throw new ArgumentOutOfRangeException("n", "(a mod 0) is undefined."); //puts a in the [-n+1, n-1] range using the remainder operator int remainder = a%n; //if the remainder is less than zero, add n to put it in the [0, n-1] range if n is positive //if the remainder is greater than zero, add n to put it in the [n-1, 0] range if n is negative if ((n > 0 && remainder < 0) || (n < 0 && remainder > 0)) return remainder + n; return remainder; } }

Test suite usando xUnit:

[Theory] [PropertyData("GetTestData")] public void Mod_ReturnsCorrectModulo(int dividend, int divisor, int expectedMod) { Assert.Equal(expectedMod, dividend.Mod(divisor)); } [Fact] public void Mod_ThrowsException_IfDivisorIsZero() { Assert.Throws<ArgumentOutOfRangeException>(() => 1.Mod(0)); } public static IEnumerable<object[]> GetTestData { get { yield return new object[] {1, 1, 0}; yield return new object[] {0, 1, 0}; yield return new object[] {2, 10, 2}; yield return new object[] {12, 10, 2}; yield return new object[] {22, 10, 2}; yield return new object[] {-2, 10, 8}; yield return new object[] {-12, 10, 8}; yield return new object[] {-22, 10, 8}; yield return new object[] { 2, -10, -8 }; yield return new object[] { 12, -10, -8 }; yield return new object[] { 22, -10, -8 }; yield return new object[] { -2, -10, -2 }; yield return new object[] { -12, -10, -2 }; yield return new object[] { -22, -10, -2 }; } }


Me gusta el truco presentado por Peter N Lewis en este hilo : "Si n tiene un rango limitado, entonces puedes obtener el resultado que deseas simplemente agregando un múltiplo constante conocido de [el divisor] que sea mayor que el valor absoluto del mínimo."

Entonces, si tengo un valor d que está en grados y quiero tomar

d % 180f

y quiero evitar los problemas si d es negativo, entonces simplemente hago esto:

(d + 720f) % 180f

Esto supone que, aunque d puede ser negativo, se sabe que nunca será más negativo que -720.


Para los desarrolladores más conscientes del rendimiento

uint wrap(int k, int n) ((uint)k)%n

Una pequeña comparación de rendimiento

Modulo: 00:00:07.2661827 ((n%x)+x)%x) Cast: 00:00:03.2202334 ((uint)k)%n If: 00:00:13.5378989 ((k %= n) < 0) ? k+n : k

En cuanto al costo de rendimiento de un elenco, eche un vistazo here


Siempre uso mi propia función mod , definida como

int mod(int x, int m) { return (x%m + m)%m; }

Por supuesto, si le molesta tener dos llamadas a la operación de módulo, podría escribirla como

int mod(int x, int m) { int r = x%m; return r<0 ? r+m : r; }

o variantes de los mismos

La razón por la que funciona es que "x% m" siempre está en el rango [-m + 1, m-1]. Entonces, si es negativo, sumar m lo colocará en el rango positivo sin cambiar su valor módulo m.


Simplemente agregue su módulo (arrayLength) al resultado negativo de% y estará bien.


Tenga en cuenta que el operador% C # y C ++ en realidad NO es un módulo, es resto. La fórmula para módulo que desea, en su caso, es:

float nfmod(float a,float b) { return a - b * floor(a / b); }

Tienes que recodificar esto en C # (o C ++) pero esta es la forma en que obtienes módulo y no un resto.