¿Cómo puedo calcular la división y el módulo para enteros en C #?

85

¿Cómo puedo calcular la división y el módulo para números enteros en C #?

kartal
fuente
15
Esto puede ser demasiado básico, pero es una pregunta real ...
2
Una publicación relacionada y un blog de lectura obligada sobre por qué el %operador no es el operador de módulo en C #.
RBT

Respuestas:

123

Antes de hacer preguntas de este tipo, consulte la documentación de MSDN .

Cuando divide dos números enteros, el resultado es siempre un número entero. Por ejemplo, el resultado de 7/3 es 2. Para determinar el resto de 7/3, utilice el operador de resto ( % ).

int a = 5;
int b = 3;

int div = a / b; //quotient is 1
int mod = a % b; //remainder is 2
as-cii
fuente
9
% devuelve el resto, no el módulo (como señala). No son lo mismo y pueden causar problemas cuando se trata de casos inusuales (por ejemplo, índices negativos). Sin embargo, se puede utilizar como operador de módulo cuando solo se busca, por ejemplo, cada décima iteración de un indexador débilmente positivo. ¿Quizás podría explicar cómo calcular el módulo real?
Cor_Blimey
1
Es cierto, leí publicaciones como esta y tuve problemas en mi aplicación :)
apocalypse
1
... ¿Cuál es exactamente el punto de declarar ay bsi no los vas a usar? : D
leviathanbadger
1
Quizás el usuario estaba buscando (como yo) una función DivRem, por lo que la pregunta podría no ser tan trivial como parece a primera vista. Gracias @danodonovan
Tancredi
1
La respuesta no es tan simple como afirma esta respuesta, como también han señalado otros, y puede conducir a errores difíciles de depurar. Ver /programming/10065080/mod-explanation
SansWit
88

También hay Math.DivRem

quotient = Math.DivRem(dividend, divisor, out remainder);
danodonovan
fuente
2
Esta debería ser la respuesta correcta en mi opinión, porque proporciona el cociente Y el resto en una función. No estoy seguro de qué enfoque funciona mejor (usar "a / b" para obtener el cociente y luego "a% b" para obtener el resto o Math.DivRem), pero este enfoque ciertamente es mucho más agradable de leer (en mi caso, necesito saber tanto el cociente como el resto) - ¡gracias!
Igor
2
@Igor gracias, cuando se respondió la pregunta original, esta función no existía. Sin embargo, la existencia de la función hace que el comentario de as-cii sobre la verificación de la documentación parezca un poco tonto .... :)
danodonovan
5
Solo para evitar confusiones, Math.DivRemno calcula div y mod en una sola operación. Es simplemente una función de ayuda y su código fuente es exactamente: public static int DivRem(int a, int b, out int result) { result = a%b; return a/b; }.
NightElfik
9
@NightElfik La implementación podría cambiar en el futuro, y es más fácil para el tiempo de ejecución identificar una llamada de método para optimización que disjuntos dive reminstrucciones
kbolino
6
@kbolino Esa es una gran predicción, ya que ha cambiado , al menos en .NET Core, para dividir y restar. Y hay más optimizaciones planeadas en RyuJIT para usar una sola instrucción div x86, aunque es cierto que los cambios JIT también deberían detectar los operadores %y /si se usan individualmente.
Bob
15

¡Hecho de la diversión!

La operación de 'módulo' se define como:

a % n ==> a - (a/n) * n

Ref: Aritmética modular

Por lo tanto, podría rodar el suyo, aunque será MUCHO más lento que el operador% integrado:

public static int Mod(int a, int n)
{
    return a - (int)((double)a / n) * n;
}

Editar: wow, me hablé mal aquí originalmente, gracias @joren por atraparme

Ahora, aquí estoy confiando en el hecho de que division + cast-to-int en C # es equivalente a Math.Floor(es decir, elimina la fracción), pero una implementación "verdadera" sería algo como:

public static int Mod(int a, int n)
{
    return a - (int)Math.Floor((double)a / n) * n;
}

De hecho, puede ver las diferencias entre% y "módulo verdadero" con lo siguiente:

var modTest =
    from a in Enumerable.Range(-3, 6)
    from b in Enumerable.Range(-3, 6)
    where b != 0
    let op = (a % b)
    let mod = Mod(a,b)
    let areSame = op == mod
    select new 
    { 
        A = a,
        B = b,
        Operator = op, 
        Mod = mod, 
        Same = areSame
    };
Console.WriteLine("A      B     A%B   Mod(A,B)   Equal?");
Console.WriteLine("-----------------------------------");
foreach (var result in modTest)
{
    Console.WriteLine(
        "{0,-3} | {1,-3} | {2,-5} | {3,-10} | {4,-6}", 
        result.A,
        result.B,
        result.Operator, 
        result.Mod, 
        result.Same);
}

Resultados:

A      B     A%B   Mod(A,B)   Equal?
-----------------------------------
-3  | -3  | 0     | 0          | True  
-3  | -2  | -1    | -1         | True  
-3  | -1  | 0     | 0          | True  
-3  | 1   | 0     | 0          | True  
-3  | 2   | -1    | 1          | False 
-2  | -3  | -2    | -2         | True  
-2  | -2  | 0     | 0          | True  
-2  | -1  | 0     | 0          | True  
-2  | 1   | 0     | 0          | True  
-2  | 2   | 0     | 0          | True  
-1  | -3  | -1    | -1         | True  
-1  | -2  | -1    | -1         | True  
-1  | -1  | 0     | 0          | True  
-1  | 1   | 0     | 0          | True  
-1  | 2   | -1    | 1          | False 
0   | -3  | 0     | 0          | True  
0   | -2  | 0     | 0          | True  
0   | -1  | 0     | 0          | True  
0   | 1   | 0     | 0          | True  
0   | 2   | 0     | 0          | True  
1   | -3  | 1     | -2         | False 
1   | -2  | 1     | -1         | False 
1   | -1  | 0     | 0          | True  
1   | 1   | 0     | 0          | True  
1   | 2   | 1     | 1          | True  
2   | -3  | 2     | -1         | False 
2   | -2  | 0     | 0          | True  
2   | -1  | 0     | 0          | True  
2   | 1   | 0     | 0          | True  
2   | 2   | 0     | 0          | True  
JerKimball
fuente
"Ahora estoy confiando en el hecho de que la división de enteros en C # es equivalente a Math.Floor (es decir, elimina la fracción)" - Pero no lo es. La división de enteros redondea hacia cero, Math.Floor redondea hacia infinito negativo.
Joren
@Joren Lo siento, pero no - intente ejecutar esto: Enumerable.Range(0, 10).Select(x => (double)x / 10.0).Select(x => (int)x).ToList().ForEach(x => Console.WriteLine(x));- todos 0
JerKimball
2
Primero, estoy hablando de la división de enteros . Lo que sucede si hace una división de punto flotante y luego convierte a un número entero es irrelevante (aunque da el mismo resultado). En segundo lugar, no estoy seguro de por qué esperaría que los números enteros entre 0 y 9 den algo distinto de 0 después de dividir por 10 y truncar a la parte entera. Si eso dio lugar a 1 que sería el redondeo de distancia desde cero o hacia positivo infinito. En tercer lugar, no hay diferencia alguna entre redondear hacia cero y redondear hacia el infinito negativo para números positivos, por lo que ni siquiera está abordando el problema.
Joren
Math.Floor(-10.0 / 3.0)y no-10 / 3 son lo mismo.
Joren
@joren ah, veo la desconexión aquí, no, no estoy realizando una división de enteros , estoy realizando una división doble y luego lanzo el resultado a un número entero, muy diferente.
JerKimball
14

La división se realiza utilizando el /operador:

result = a / b;

La división de módulo se realiza mediante el %operador:

result = a % b;
Rion Williams
fuente
1
+1: Convenientemente omitir el tipo lo convierte en una mejor respuesta :-) Creo que esto también funciona con System.Numeric.BigInteger en 4.0.
5
% -> como dijo Cor_Blimey, devuelve el resto, no el módulo. Por ejemplo: (-5% 3) == -2 [C #], -5 mod 3 = 1 [wolframalpha.com].
apocalipsis
2
Nota: Módulo no es lo mismo que Módulo. Módulo es el resto, Módulo es el valor absoluto.
Ryan
-4

Leer dos números enteros del usuario. Luego calcule / muestre el resto y el cociente,

// When the larger integer is divided by the smaller integer
Console.WriteLine("Enter integer 1 please :");
double a5 = double.Parse(Console.ReadLine());
Console.WriteLine("Enter integer 2 please :");
double b5 = double.Parse(Console.ReadLine());

double div = a5 / b5;
Console.WriteLine(div);

double mod = a5 % b5;
Console.WriteLine(mod);

Console.ReadLine();
James Dombroski
fuente