Come posso calcolare la divisione e il modulo per i numeri interi in C #?


87

Come posso calcolare la divisione e il modulo per i numeri interi in C #?


16
Potrebbe essere troppo semplice, ma è una vera domanda ...

2
Un post correlato e un blog da leggere sul perché l' %operatore non è l'operatore modulo in C #.
RBT

Risposte:


124

Prima di porre domande di questo tipo, consultare la documentazione MSDN .

Quando dividi due numeri interi, il risultato è sempre un numero intero. Ad esempio, il risultato di 7/3 è 2. Per determinare il resto di 7/3, utilizzare l'operatore resto ( % ).

int a = 5;
int b = 3;

int div = a / b; //quotient is 1
int mod = a % b; //remainder is 2

10
% restituisce il resto, non il modulo (come hai sottolineato). Non sono la stessa cosa e possono causare problemi quando si tratta di casi insoliti (ad esempio indici negativi). Tuttavia, può essere utilizzato come l'operatore modulo quando si cerca, ad esempio, ogni 10 iterazioni di un indicizzatore debolmente positivo. Forse potresti spiegare come calcolare il modulo reale?
Cor_Blimey

1
È vero, ho letto post come questo e ho avuto problemi con la mia applicazione :)
apocalypse

1
... Che senso ha esattamente dichiararli ae bse non li userai? : D
leviathanbadger

1
Forse l'utente stava cercando (come me) una funzione DivRem, quindi la domanda potrebbe non essere così banale come sembra a prima vista. Grazie @danodonovan
Tancredi

1
La risposta non è così semplice come sostiene questa risposta, come altri hanno sottolineato, e può portare a errori difficili da eseguire il debug. Vedi /programming/10065080/mod-explanation
SansWit

90

C'è anche Math.DivRem

quotient = Math.DivRem(dividend, divisor, out remainder);

2
Questa dovrebbe essere la risposta corretta secondo me, perché fornisce il quoziente E il resto in una funzione. Non sono sicuro di quale approccio funzioni meglio (usando "a / b" per ottenere il quoziente e poi "a% b" per ottenere il resto o Math.DivRem), ma questo approccio è certamente molto più piacevole da leggere (nel mio caso ho bisogno per conoscere sia il quoziente che il resto) - grazie!
Igor

2
@Igor grazie, quando la domanda originale è stata risposta questa funzione non esisteva! Tuttavia, l'esistenza della funzione rende l'osservazione di as-cii sul controllo della documentazione un po 'sciocca .... :)
danodonovan

6
Solo per evitare confusione, Math.DivRemnon calcola div e mod in un'unica operazione. E 'solo una funzione di supporto e il suo codice sorgente è esattamente: public static int DivRem(int a, int b, out int result) { result = a%b; return a/b; }.
NightElfik

9
@NightElfik L'implementazione potrebbe cambiare in futuro ed è più facile per il runtime identificare una chiamata di metodo per l'ottimizzazione rispetto a disgiunti dive remistruzioni
kbolino

6
@kbolino Questa è una grande previsione, dal momento che ha cambiato , almeno in .NET core, per dividere e sottrarre. E ci sono ulteriori ottimizzazioni pianificate in RyuJIT per utilizzare una singola istruzione div x86, anche se è vero che le modifiche JIT dovrebbero anche rilevare gli operatori %e /se usati individualmente.
Bob

15

Fatto divertente!

L'operazione 'modulo' è definita come:

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

Rif: Aritmetica modulare

Così si potrebbe rotolare il proprio, anche se sarà molto più lento del costruito in operatore%:

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

Modifica: wow, ho parlato male piuttosto male qui originariamente, grazie @joren per avermi preso

Ora qui mi sto basando sul fatto che divisione + cast-to-int in C # è equivalente a Math.Floor(cioè, elimina la frazione), ma un'implementazione "vera" sarebbe invece qualcosa del tipo:

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

In effetti, puoi vedere le differenze tra% e "modulo vero" con quanto segue:

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);
}

Risultati:

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  

"Ora qui mi affido al fatto che la divisione di interi in C # è equivalente a Math.Floor (cioè, elimina la frazione)" - Ma non lo è. La divisione intera arrotonda verso zero, Math.Floor arrotonda verso l'infinito negativo.
Joren

@Joren Scusa, ma no - prova a eseguire questo: Enumerable.Range(0, 10).Select(x => (double)x / 10.0).Select(x => (int)x).ToList().ForEach(x => Console.WriteLine(x));- tutti gli 0
JerKimball

2
Innanzitutto, sto parlando della divisione di numeri interi . Cosa succede se esegui una divisione in virgola mobile e poi esegui il cast su intero è irrilevante (anche se dà lo stesso risultato). In secondo luogo, non sono sicuro del motivo per cui ti aspetteresti che i numeri interi compresi tra 0 e 9 diano qualcosa di diverso da 0 dopo aver diviso per 10 e troncato alla parte intera. Se questo risulta in 1 che verrebbe arrotondamento lontano da zero o verso positivo infinito. Terzo, non c'è alcuna differenza tra l'arrotondamento verso lo zero e l'arrotondamento verso l'infinito negativo per i numeri positivi, quindi non stai nemmeno affrontando il problema.
Joren

Math.Floor(-10.0 / 3.0)e non-10 / 3 sono la stessa cosa.
Joren

@joren ah, vedo la disconnessione qui - no, non sto eseguendo la divisione intera , sto eseguendo la doppia divisione, quindi lancio il risultato su un numero intero - molto diverso.
JerKimball

14

La divisione viene eseguita utilizzando l' /operatore:

result = a / b;

La divisione del modulo viene eseguita utilizzando l' %operatore:

result = a % b;

1
+1: Tralasciare convenientemente il tipo è una risposta migliore :-) Credo che funzioni anche con System.Numeric.BigInteger nella 4.0.

5
% -> come ha detto Cor_Blimey, restituisce il resto non il modulo. Ad esempio: (-5% 3) == -2 [C #], -5 mod 3 = 1 [wolframalpha.com].
apocalisse

2
Nota: Modulo non è la stessa cosa di Modulo. Modulo è il resto, Modulo è il valore assoluto.
Ryan

-4

Legge due numeri interi dall'utente. Quindi calcola / visualizza il resto e il quoziente,

// 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();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.