Làm cách nào để tính toán chia và môđun cho các số nguyên trong C #?


85

Làm cách nào để tính phép chia và môđun cho các số nguyên trong C #?


15
Đây có thể là quá cơ bản, nhưng nó là một câu hỏi thực sự ...

2
Một bài đăng liên quan và một blog phải đọc về lý do tại sao %toán tử không phải là toán tử mô đun trong C #.
RBT

Câu trả lời:


123

Trước khi đặt câu hỏi kiểu này, vui lòng kiểm tra tài liệu MSDN .

Khi bạn chia hai số nguyên, kết quả luôn là một số nguyên. Ví dụ, kết quả của 7/3 là 2. Để xác định phần dư của 7/3, hãy sử dụng toán tử phần dư ( % ).

int a = 5;
int b = 3;

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

9
% trả về phần còn lại, không phải mô đun (như bạn đã chỉ ra). Chúng không giống nhau, và có thể gây ra vấn đề khi xử lý các trường hợp bất thường (ví dụ: chỉ số âm). Tuy nhiên, nó có thể được sử dụng giống như toán tử mô-đun khi chỉ tìm kiếm, ví dụ: mỗi lần lặp thứ 10 của một chỉ mục tích cực yếu. Có lẽ bạn có thể giải thích cách tính toán mô đun thực?
Cor_Blimey

1
Đúng, tôi đọc bài viết như thế này, và tôi đã có vấn đề trong ứng dụng của tôi :)
ngày tận thế

1
... Chính xác thì điểm khai báo là gì abnếu bạn không sử dụng chúng? : D
leviathanbadger

1
Có lẽ người dùng đang tìm kiếm (như tôi) cho một chức năng DivRem, vì vậy câu hỏi có thể không quá tầm thường như thoạt nhìn. Cảm ơn @danodonovan
Tancredi

1
Câu trả lời không đơn giản như câu trả lời này tuyên bố, như những người khác cũng đã chỉ ra, và có thể dẫn đến những sai lầm khó sửa chữa. Xem /programming/10065080/mod-explanation
SansWit

88

Ngoài ra còn có Math.DivRem

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

2
Đây phải là câu trả lời chính xác theo ý kiến ​​của tôi, bởi vì nó cung cấp thương số VÀ phần còn lại trong một hàm. Tôi không chắc cách tiếp cận nào hoạt động tốt hơn (sử dụng "a / b" để lấy thương số và sau đó "a% b" để lấy phần còn lại hoặc Math.DivRem), nhưng cách tiếp cận này chắc chắn là dễ đọc hơn nhiều (trong trường hợp của tôi, tôi cần để biết cả thương và phần dư) - cảm ơn bạn!
Igor

2
@Igor cảm ơn, khi câu hỏi ban đầu được trả lời, chức năng này không tồn tại! Tuy nhiên, sự tồn tại của chức năng làm xét làm như-CII về kiểm tra giao diện tài liệu một chút ngớ ngẩn .... :)
danodonovan

5
Chỉ để tránh nhầm lẫn, Math.DivRemkhông tính toán div và mod trong một thao tác. Nó chỉ là một hàm helper và mã nguồn của nó là chính xác: public static int DivRem(int a, int b, out int result) { result = a%b; return a/b; }.
NightElfik

9
@NightElfik Việc thực hiện có thể thay đổi trong tương lai, và nó là dễ dàng hơn cho thời gian chạy để xác định một phương pháp gọi để tối ưu hóa hơn rời nhau divremhướng dẫn
kbolino

6
@kbolino Đó là một dự đoán tuyệt vời, vì đã thay đổi , ít nhất là trong .NET Core, để chia và trừ. Và có kế hoạch tối ưu hơn nữa trong RyuJIT để sử dụng một lệnh div x86 duy nhất, mặc dù phải thừa nhận rằng các thay đổi JIT cũng sẽ phát hiện các toán tử %/nếu được sử dụng riêng lẻ.
Bob

15

Sự thật thú vị!

Hoạt động 'mô-đun' được định nghĩa là:

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

Tham khảo: Số học mô-đun

Vì vậy, bạn có thể tự cuộn, mặc dù nó sẽ FAR chậm hơn so với toán tử% được tích hợp sẵn:

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

Chỉnh sửa: wow, ban đầu bỏ lỡ khá tệ ở đây, cảm ơn @joren đã bắt tôi

Bây giờ ở đây tôi dựa vào thực tế là phép chia + cast-to-int trong C # tương đương với Math.Floor(tức là nó giảm phân số), nhưng triển khai "true" thay vào đó sẽ giống như:

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

Trên thực tế, bạn có thể thấy sự khác biệt giữa% và "true modulus" như sau:

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

Các kết quả:

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  

"Bây giờ ở đây tôi dựa vào thực tế là phép chia số nguyên trong C # tương đương với Math.Floor (tức là nó giảm phân số)" - Nhưng không phải vậy. Số nguyên làm tròn về phía 0, Math.Floor làm tròn về phía âm vô cùng.
Joren

@Joren Xin lỗi, nhưng không - hãy thử chạy cái này: Enumerable.Range(0, 10).Select(x => (double)x / 10.0).Select(x => (int)x).ToList().ForEach(x => Console.WriteLine(x));- tất cả là 0
JerKimball

2
Đầu tiên, tôi đang nói về phép chia số nguyên . Điều gì xảy ra nếu bạn thực hiện phép chia dấu phẩy động và sau đó ép kiểu thành số nguyên là không liên quan (mặc dù nó cho cùng một kết quả). Thứ hai, tôi không chắc tại sao bạn lại mong đợi các số nguyên từ 0 đến 9 cho bất kỳ giá trị nào khác 0 sau khi chia cho 10 và cắt bớt phần nguyên. Nếu điều đó dẫn đến 1 sẽ làm tròn đi từ 0 hoặc về phía dương vô cùng. Thứ ba, không có sự khác biệt nào giữa việc làm tròn về 0 và làm tròn về âm vô cực cho các số dương, vì vậy bạn thậm chí không giải quyết được vấn đề.
Joren

Math.Floor(-10.0 / 3.0)-10 / 3không giống nhau.
Joren

@joren à, tôi thấy sự ngắt kết nối ở đây - không, tôi không thực hiện phép chia số nguyên , tôi đang thực hiện phép chia đôi, sau đó truyền kết quả thành số nguyên - rất khác.
JerKimball

14

Phép chia được thực hiện bằng /toán tử:

result = a / b;

Phép chia modulo được thực hiện bằng cách sử dụng %toán tử:

result = a % b;

1
+1: Bỏ qua loại này một cách thuận tiện khiến nó trở thành một câu trả lời tốt hơn :-) Tôi tin rằng điều này cũng hoạt động với System.Numeric.BigInteger trong 4.0.

5
% -> như Cor_Blimey đã nói, nó trả về phần còn lại không phải mô đun. Ví dụ: (-5% 3) == -2 [C #], -5 mod 3 = 1 [wolframalpha.com].
khải huyền ngày

2
Lưu ý: Modulo không giống với Modulus. Modulo là phần còn lại, Modulus là giá trị tuyệt đối.
Ryan

-4

Đọc hai số nguyên từ người dùng. Sau đó, tính toán / hiển thị phần còn lại và thương số,

// 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();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.