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 1int mod = a % b; //remainder is 2
% 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
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.
Więc mógł toczyć własne, choć będzie to o wiele wolniej niż wbudowany w operatora%:
publicstaticintMod(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:
publicstaticintMod(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 != 0let op = (a % b)
let mod = Mod(a,b)
let areSame = op == mod
selectnew
{
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);
}
„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.
%
operator nie jest operatorem modułu w C #.Odpowiedzi:
Przed zadaniem tego rodzaju pytań zapoznaj się z dokumentacją MSDN .
int a = 5; int b = 3; int div = a / b; //quotient is 1 int mod = a % b; //remainder is 2
źródło
a
ib
czy nie zamierzasz ich używać? : DJest również
Math.DivRem
quotient = Math.DivRem(dividend, divisor, out remainder);
źródło
Math.DivRem
nie 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; }
.div
irem
instrukcje%
i/
, jeśli są używane indywidualnie.Śmieszny fakt!
Działanie „modułu” definiuje się jako:
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
źródło
Enumerable.Range(0, 10).Select(x => (double)x / 10.0).Select(x => (int)x).ToList().ForEach(x => Console.WriteLine(x));
- wszystkie 0Math.Floor(-10.0 / 3.0)
i nie-10 / 3
są tym samym.Dzielenie odbywa się za pomocą
/
operatora:Dzielenie modulo odbywa się za pomocą
%
operatora:źródło
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();
źródło