書接上文,麥子帶大傢簡單看瞭下向量是什麼以及向量的加減法,到目前為止所有的結論都是很直觀的,但是講到向量的乘法時我們遇到瞭兩個問題:
- 兩個向量相乘是個什麼含義呢?
- 兩個向量相乘,結果是個標量呢?還是個向量呢?如果是向量,方向是指向哪兒的呢?
從第二個問題我們能看出一些端倪,這並不是一個很簡單的問題。但是如果僅僅是要使用向量之間的乘法,不去太過在意做法來源的話,就能很輕易地講完。(關於做法來源,大傢可以在學會矩陣以及理解矩陣與空間轉換關系之後去看下3Blue1Brown線性代數系列第7、第8集)
對於3D空間而言,我們會有兩種向量相乘的做法:
- 點乘
- 叉乘
其中點乘的做法對任意維度都適用,但叉乘僅適用與3D或7D的情況。如果你對7D的叉乘感興趣,請自行閱讀《Cross Products of Vectors in Higher Dimensional Euclidean Spaces》(麥子我沒接觸過)
今天我們先來講講點乘。
註:這篇裡部分地方會用到矩陣,我們還沒討論過,我會在有矩陣的段落開頭加上(*)做為標記,對矩陣不熟的朋友可以之後返回來看,但是不會也並不影響閱讀。
點乘(Dot Product)
點乘的結果會是一個標量,同時可以看成一個向量在另一個向量方向上的投影長度與另一個向量長度相乘。聽起來拗口啊,但是看到數學表達式應該就很清楚瞭。
vec v cdot vec u = left| vec v right| left| vec u right| cos(theta)
其中 theta 是兩個向量之間的夾角,因此 ( left| vec u right| cos(theta) ) 就是向量 vec u 在向量 vec v 方向上的投影長度,之後這個長度再與 left| vec v right| 進行最平常的相乘。同理,也可以認為 ( left| vec v right| cos(theta) ) 是 vec v 在 vec u 方向上的投影長度。
如果 vec v = begin{pmatrix} v_x \ v_y \ v_z end{pmatrix} , vec u = begin{pmatrix} u_x \ u_y \ u_z end{pmatrix} ,那麼我們還可以用如下方法進行點乘計算:
vec v cdot vec u = v_x u_x + v_y u_y + v_z u_z = sum_{iin(x, y, z)}{v_i u_i} ,
值得一提的是,為什麼這兩種表達方式是向等的呢?這裡給大傢看個三角形應該可以簡要說明下這個問題。
3e57f40740fd7dd8a8d76c202d04a12c
如圖所示,這個三角形由三個向量包圍而成, vec v , vec u 以及 ( vec v – vec u ) ,餘弦定理(不記得這個定理瞭,可以看看文章最下面)告訴我們
left| vec v – vec u right|^2 = left| vec v right|^2 + left| vec u right|^2 – 2 left| vec v right| left| vec u right| cos(theta)
相信你已經看到瞭點乘結果的那一部分瞭,接下來就是一些基本數學操作瞭。回顧下上一篇文章中我們提過 left| vec v right| = (sum_{iin(x, y, z)}{v_i^2})^frac{1}{2} ,
由此我們就有瞭
sum_{i in (x, y, z)}{(v_i – u_i)^2} = sum_{i in (x, y, z)}{v_i^2} + sum_{i in (x, y, z)}{u_i^2} – 2 left| vec v right| left| vec u right| cos(theta) \ Rightarrow sum_{i in (x, y, z)}{v_i^2 – 2 v_i u_i + u_i^2} = sum_{i in (x, y, z)}{v_i^2} + sum_{i in (x, y, z)}{u_i^2} – 2 left| vec v right| left| vec u right| cos(theta) \ Rightarrow -2 sum_{i in (x, y, z)}{v_i u_i} = -2 left| vec v right| left| vec u right| cos(theta)
最後就是我們想要的點乘公式瞭:
vec v cdot vec u = sum_{iin(x, y, z)}{v_i u_i} = left| vec v right| left| vec u right| cos(theta)
希望你也能看出來,整個證明流程實際上並不隻限於3D。
(*) 如上一講提到過的,在計算機中常把向量之間的操作直接看成矩陣操作。熟悉矩陣的朋友應該一眼就看出來,這個點乘可以被看成 vec v cdot vec u equiv mathbf{v^T} mathbf{u} 這樣的矩陣操作。(不熟悉的朋友也沒事,快講到瞭)
點乘也具有一些很重要但是不難想到的性質,可以自己去思考下為啥它們是對的
- vec v cdot vec u = vec u cdot vec v
- (a vec v) cdot vec u = a (vec v cdot vec u)
- vec v cdot (vec u + vec w) = vec v cdot vec u + vec v cdot vec w
- vec v cdot vec v = left| vec v right|^2
- left| vec v cdot vec u right| leq left| vec v right| left| vec u right|
留意下第四點,它直接來源於一個向量自己在自己方向的投影自然還是它自己。同時也說明 cos(theta) 和點乘的大小也反應瞭兩個向量有多“平行”。兩個向量越“平行“,絕對值越大;反之,兩個向量越“垂直”,絕對值越小。
這也是為什麼點乘在物理裡也是無處不在,最直接的例子就是初中物理裡強調過的
雖然那個時候還沒講點乘,但是也能看出這個概念並不是很遙遠。
關於點乘最後講兩個點。如果你就是想知道一個向量在另一個向量方向的投影向量,怎麼辦?相信你能很自然地告訴我, vec v 在 vec u 方向上的投影就是
proj_u vec v = (vec v cdot hat u) hat u = frac{vec v cdot vec u}{left| vec u right|^2} vec u ,
同時vec v 垂直於 vec u 方向的向量就可以用 vec v 和 proj_u vec v 的差值來得到
perp_u vec v = vec v – proj_u vec v ,
沒看出來的小夥伴最好自己畫畫圖看看。
(*) 最後,關於投影向量可以用矩陣一步到位地求出來,有興趣的小夥伴可以自己試一試
proj_u vec v = frac{1}{left| vec u right|^2} begin{bmatrix} u_x^2 & u_x u_y & u_x u_z \ u_x u_y & u_y^2 & u_y u_z \ u_x u_z & u_y u_z & u_z^2 end{bmatrix} begin{bmatrix} v_x \ v_y \ v_z end{bmatrix} 。
繼續補下Python那Class
class vector_3d(object):
def __init__(self, x, y, z, ifTransposed=False):
# 默認是豎向量
super(vector_3d, self).__init__()
self.x = x
self.y = y
self.z = z
self.ifTransposed = ifTransposed
# ......
def dot(self, another_vector):
assert type(another_vector) is Vector_3d
assert another_vector.ifTransposed == False
return self.x * another_vector.x +
self.y * another_vector.y +
self.z * another_vector.z
def proj(self, project_to):
assert type(project_to) is Vector_3d
return self.dot(project_to)/abs(project_to) * project_to.unit()
def perp(self, perpendicular_to):
assert type(perpendicular_to) is Vector_3d
return self - self.proj(perpendicular_to)