1. 程式人生 > 其它 >踩坑之路--負數取模、取模與取餘

踩坑之路--負數取模、取模與取餘

兩種判斷奇偶的方式

正常判斷一個數為奇數還是偶數的常見思路便是通過對2取模進行判斷,比如通過x%2!=0x%2==1判斷是否為奇數。但這兩種方法真的都不會出錯嗎?下面用一段簡單的程式碼測試下:

#include <bits/stdc++.h>
using namespace std;
int main() {
    while (1) {
        int n;
        cin >> n;
        cout << "n: " << n << endl;

        cout << "n % 2 != 0 : ";
        if (n % 2 != 0) {
            cout << "奇數" << endl;
        } else {
            cout << "偶數" << endl;
        }

        cout << "n % 2 == 1 : ";
        if (n % 2 == 1) {
            cout << "奇數" << endl;
        } else {
            cout << "偶數" << endl;
        }
        cout << endl << endl;
    }
}

最終結果如下:

n: 3
n % 2 != 0 : 奇數
n % 2 == 1 : 奇數

n: 4
n % 2 != 0 : 偶數
n % 2 == 1 : 偶數

n: -3
n % 2 != 0 : 奇數
n % 2 == 1 : 偶數

n: -4
n % 2 != 0 : 偶數
n % 2 == 1 : 偶數

可以看出此時用x%2==1判斷出錯,難道負數取模和正數取模有什麼不同?下面簡要分析一下。

負數取模

通過C++(gcc 8.1.0)編寫一段程式碼可以測試出如下結果

 4 %  3 =  1
 4 % -3 =  1
-4 %  3 = -1
-4 % -3 = -1

而用python 3.6.1 測試結果如下

>>>  4 %  3
1
>>>  4 % -3
-2
>>> -4 %  3
2
>>> -4 % -3
-1

用windows自帶計算機計算結果如下

 4 %  3 =  1
 4 % -3 =  1
-4 %  3 = -1
-4 % -3 = -1

通過查資料可知這裡的主要區別原因是取整方式的選擇(具體可見維基百科 中的定義)。C++採用的是向零取整,而python採用的是向下取整,因此導致了餘數的歧義進而導致了模數的不同。

取模與取餘

取模運算(“Modulo Operation”)和取餘運算(“Remainder Operation ”)兩個概念有重疊的部分但又不完全一致。主要的區別在於對負整數進行除法運算時操作不同。取模主要是用於計算機術語中。取餘則更多是數學概念。

  • 取餘,遵循儘可能讓商向0靠近的原則(即上文C++向零取整)

  • 取模,遵循儘可能讓商向負無窮靠近的原則(即上文python向負無窮取整)

針對x%y的結果,當 x 和 y 的正負號一樣的時候,兩種運算結果是等同的;當 x 和 y 的符號不同時,取餘結果的符號和 x 的一樣,而 取模 和 y 一樣。所以可以看出C++中的% 嚴格上應該稱為取餘運算而不是取模運算。

所以通過上文中可以看出利用x%2==1判斷數字的奇偶性是會出錯的,那麼除了x%2!=0還有別的方式嗎?答案就是x&1,詳細可見位運算總結


參考連結

帶符號整數的除法與餘數

取餘和取模的區別

負數究竟是如何取模的?

維基百科--模除