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 #?


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

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

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  

„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;

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();
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.