numpy基礎屬性方法隨機整理(9):除法,餘數,商 以及 python的負數取餘問題

具體方法見如下代碼筆記:

# -*- coding: utf-8 -*-
"""
Created on Thu Jul 26 16:11:18 2018

@author: Administrator
"""

import numpy as np

a = np.array([5, 5, -5, -5])
b = np.array([2, -2, 2, -2])

# 真除
print(a / b)                    # [2.5 -2.5 -2.5 2.5]
print(np.true_divide(a, b))     # [2.5 -2.5 -2.5 2.5]
print(np.divide(a,b))           # [2.5 -2.5 -2.5 2.5]

# 地板除
print(a // b)                     # [ 2 -3 -3  2]
print(np.floor_divide(a, b))    # [ 2 -3 -3  2]

# 天花板除
print(np.ceil(a / b).astype(int))   # [ 3 -2 -2  3]
print(np.ceil(a / b))               # [ 3. -2. -2.  3.]  float
'''
np.ceil(a / b).astype(int)          # float --> int
'''

# 截斷除
print((a / b).astype(int))          # [ 2 -2 -2  2]
print(np.trunc(a / b).astype(int))  # [ 2 -2 -2  2]


# 地板除餘數
print(a % b)                # [ 1 -1  1 -1]
'''
餘數 = 被除數 - 除數 * 商 
  (理論上,對於負數除法,餘數會有2個,-7/3:3*(-3)+2;3*(-2)-1 餘數:(2,-1))
   對python而言,除法使商儘可能小,
   因此負數除法 -7/3 商會取-3而不是-2,餘數取負餘數-1  (詳情見下文)
'''
print(np.remainder(a, b))   # [ 1 -1  1 -1]
print(np.mod(a, b))         # [ 1 -1  1 -1]

# 截斷除餘數
print(np.fmod(a, b))        # [ 1  1 -1 -1]

轉載自:寧心勉學,慎思篤行
原文鏈接:實數範圍內的求模(求餘)運算:負數求餘究竟怎麼求

首先,看看自然數的取模運算(定義1):

如果a和d是兩個自然數,d非零,可以證明存在兩個唯一的整數 q 和 r,滿足 a = qd + r 且0 ≤ r < d。其中,q 被稱爲商,r 被稱爲餘數。

那麼對於負數,是否可以沿用這樣的定義呢?我們發現,假如我們按照正數求餘的規則求 (-7) mod 3 的結果,就可以表示 -7 爲 (-3)* 3 +2。其中,2是餘數,-3是商。

那麼,各種編程語言和計算器是否是按照這樣理解的呢?下面是幾種軟件中對此的理解。

語言 語句 輸出
C++(G++ 編譯) cout << (-7) % 3 -1
Java(1.6) System.out.println((-7) % 3); -1
Python 2.6 (-7) % 3 2
百度計算器 (-7) mod 3 2
Google 計算器 (-7) mod 3 2

可以看到,結果特別有意思。這個問題是百家爭鳴的。看來我們不能直接把正數的法則加在負數上。實際上,在整數範圍內,自然數的求餘法則並不被很多人所接受,大家大多認可的是下面的這個定義2

如果a 與d 是整數,d 非零,那麼餘數 r 滿足這樣的關係:
a = qd + r , q 爲整數,且0 ≤ |r| < |d|。

可以看到,這個定義導致了有負數的求餘並不是我們想象的那麼簡單,比如,-1 和 2 都是 (-7) mod 3 正確的結果,因爲這兩個數都符合定義。這種情況下,對於取模運算,可能有兩個數都可以符合要求。我們把 -1 和 2 分別叫做正餘數負餘數。通常

當除以d 時,如果正餘數爲r1,負餘數爲r2,那麼有r1 = r2 + d

對負數餘數不明確的定義可能導致嚴重的計算問題,對於處理關鍵任務的系統,錯誤的選擇會導致嚴重的後果。

看完了 (-7) mod 3,下面我們來看一看 7 mod (-3) 的情況(看清楚,前面是 7 帶負號,現在是 3 帶負號)。根據定義2

7 = (-3) * (-2) + 1  或 7 = (-3) * (-3) -2,所以餘數爲 1 或 -2。
語言 語句 輸出
C++(G++ 編譯) cout << 7 % (-3); 1
Java(1.6) System.out.println(7 % (-3)); 1
Python 2.6 7 % (-3) -2
百度計算器 7 mod (-3) -2
Google 計算器 7 mod (-3) -2

C++ 和 Java 通常會盡量讓商更大一些。比如在 (-7) mod 3中,他們以 -2 爲商,餘數爲 -1。在 Python 和 Google 計算器中,儘量讓商更小,所以以 -3 爲商。在 7 mod (-3) 中效果相同:C++ 選擇了 3 作爲商,Python 選擇了 2 作爲商。但是在正整數運算中,所有語言和計算器都遵循了儘量讓商小的原則,因此 7 mod 3 結果爲 1 不存在爭議,不會有人說它的餘數是-2。
如果按照第二點的推斷,我們測試一下 (-7) mod (-3),結果應該是前一組語言(C++,Java)返回 2,後一組返回 -1。

語言 語句 輸出
C++(G++ 編譯) cout << -7 % (-3); -1
Java(1.6) System.out.println(-7 % (-3)); -1
Python 2.6 -7 % (-3) -1
百度計算器 -7 mod (-3) -1
Google 計算器 -7 mod (-3) -1

結果讓人大跌眼鏡,所有語言和計算機返回結果完全一致。

總結

對於任何同號的兩個整數,其取餘結果沒有爭議,所有語言的運算原則都是使商儘可能小。
對於異號的兩個整數,C++/Java語言的原則是使商儘可能大,很多新型語言和網頁計算器的原則是使商儘可能小。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章