Jak mogę obliczyć dzielenie i modulo dla liczb całkowitych w C #?

86

Jak mogę obliczyć dzielenie i modulo dla liczb całkowitych w C #?

kartal
źródło
15
To może być zbyt proste, ale to jest prawdziwe pytanie ...
2
Powiązany wpis i obowiązkowy blog o tym, dlaczego %operator nie jest operatorem modułu w C #.
RBT

Odpowiedzi:

123

Przed zadaniem tego rodzaju pytań zapoznaj się z dokumentacją MSDN .

Kiedy dzielisz dwie liczby całkowite, wynikiem jest zawsze liczba całkowita. Na przykład wynik 7/3 to 2. Aby określić pozostałą część 7/3, użyj operatora reszty ( % ).

int a = 5;
int b = 3;

int div = a / b; //quotient is 1
int mod = a % b; //remainder is 2
as-cii
źródło
9
% zwraca resztę, a nie moduł (jak wskazałeś). Nie są tym samym i mogą powodować problemy w przypadku nietypowych przypadków (np. Indeksów ujemnych). Można go jednak używać podobnie jak operatora modułu, gdy szukamy np. Co dziesiątej iteracji słabo dodatniego indeksatora. Może mógłbyś wyjaśnić, jak obliczyć rzeczywisty moduł?
Cor_Blimey
1
To prawda, czytałem takie posty i miałem problemy z aplikacją :)
apocalypse
1
... Jaki dokładnie jest sens deklarowania ai bczy nie zamierzasz ich używać? : D
leviathanbadger
1
Być może użytkownik szukał (tak jak ja) funkcji DivRem, więc pytanie nie mogło być tak banalne, jak się wydaje na pierwszy rzut oka. Dzięki @danodonovan
Tancredi
1
Odpowiedź nie jest tak prosta, jak twierdzi ta odpowiedź, jak wskazywali inni, i może prowadzić do trudnych do debugowania błędów. Zobacz /programming/10065080/mod-explanation
SansWit
88

Jest również Math.DivRem

quotient = Math.DivRem(dividend, divisor, out remainder);
danodonovan
źródło
2
Moim zdaniem powinna to być poprawna odpowiedź, ponieważ zapewnia iloraz ORAZ resztę w jednej funkcji. Nie jestem pewien, które podejście działa lepiej (używając "a / b", aby uzyskać iloraz, a następnie "a% b", aby uzyskać resztę lub Math.DivRem), ale to podejście z pewnością jest znacznie przyjemniejsze do czytania (w moim przypadku potrzebuję znać iloraz i resztę) - dziękuję!
Igor
2
@Igor dzięki, kiedy udzielono odpowiedzi na pierwotne pytanie, ta funkcja nie istniała! Jednak istnienie tej funkcji sprawia, że ​​uwaga as-cii dotycząca sprawdzenia dokumentacji wygląda trochę głupio ... :)
danodonovan
5
Aby uniknąć nieporozumień, Math.DivRemnie oblicza div i mod w jednej operacji. Jest to tylko funkcja pomocnika i jego kod źródłowy jest dokładnie: public static int DivRem(int a, int b, out int result) { result = a%b; return a/b; }.
NightElfik,
9
@NightElfik Implementacja może się zmienić w przyszłości, a środowisku wykonawczemu łatwiej będzie zidentyfikować wywołanie metody do optymalizacji niż rozłączne divi reminstrukcje
kbolino
6
@kbolino To świetny przewidywania, ponieważ to jest zmieniane , przynajmniej w .NET Core dzielić i odejmować. W RyuJIT planowane są dalsze optymalizacje w celu użycia pojedynczej instrukcji div x86, chociaż trzeba przyznać, że zmiany w JIT powinny również wykrywać operatory %i /, jeśli są używane indywidualnie.
Bob
15

Śmieszny fakt!

Działanie „modułu” definiuje się jako:

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

Ref: Arytmetyka modularna

Więc mógł toczyć własne, choć będzie to o wiele wolniej niż wbudowany w operatora%:

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

Edycja: wow, początkowo źle się tu wymówiłem, dzięki @joren za złapanie mnie

Teraz opieram się na fakcie, że dzielenie + rzutowanie na int w C # jest równoważne Math.Floor(tj. Porzuca ułamek), ale zamiast tego "prawdziwa" implementacja wyglądałaby tak:

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

W rzeczywistości możesz zobaczyć różnice między% a „prawdziwym modułem” z:

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

Wyniki:

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
źródło
„Teraz opieram się na fakcie, że dzielenie liczb całkowitych w C # jest równoważne Math.Floor (tj. Zmniejsza ułamek)” - ale tak nie jest. Dzielenie liczb całkowitych zaokrągla w kierunku zera, natomiast funkcja Math.Floor w kierunku ujemnej nieskończoności.
Joren
@Joren Przepraszamy, ale nie - spróbuj uruchomić to: Enumerable.Range(0, 10).Select(x => (double)x / 10.0).Select(x => (int)x).ToList().ForEach(x => Console.WriteLine(x));- wszystkie 0
JerKimball
2
Po pierwsze, mówię o dzieleniu liczb całkowitych . To, co się stanie, jeśli wykonasz dzielenie zmiennoprzecinkowe, a następnie rzutujesz na liczbę całkowitą, nie ma znaczenia (nawet jeśli daje ten sam wynik). Po drugie, nie jestem pewien, dlaczego można by oczekiwać, że liczby całkowite od 0 do 9 dadzą cokolwiek innego niż 0 po podzieleniu przez 10 i obcięciu do części całkowitej. Jeśli to powodowało 1, która byłaby zaokrąglenia dala od zera lub w kierunku dodatnim nieskończoności. Po trzecie, nie ma żadnej różnicy między zaokrąglaniem w kierunku zera a zaokrąglaniem w kierunku ujemnej nieskończoności dla liczb dodatnich, więc nawet nie rozwiązujesz problemu.
Joren,
Math.Floor(-10.0 / 3.0)i nie-10 / 3 są tym samym.
Joren
@joren ah, widzę tutaj rozłączenie - nie, nie wykonuję dzielenia liczb całkowitych , wykonuję dzielenie podwójne, a następnie rzutowanie wyniku na liczbę całkowitą - bardzo różne.
JerKimball
14

Dzielenie odbywa się za pomocą /operatora:

result = a / b;

Dzielenie modulo odbywa się za pomocą %operatora:

result = a % b;
Rion Williams
źródło
1
+1: Dogodne pominięcie typu sprawia, że ​​jest to lepsza odpowiedź :-) Uważam, że działa to również z System.Numeric.BigInteger w 4.0.
5
% -> jak powiedział Cor_Blimey, zwraca resztę, a nie moduł. Na przykład: (-5% 3) == -2 [C #], -5 mod 3 = 1 [wolframalpha.com].
apokalipsa
2
Uwaga: Modulo to nie to samo, co Modulus. Modulo to reszta, Modulus to wartość bezwzględna.
Ryan
-4

Odczytaj dwie liczby całkowite od użytkownika. Następnie oblicz / wyświetl resztę i iloraz,

// 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
źródło