点乘和叉乘及其物理意义(C++STL实现)
2015-11-14 20:42
288 查看
一些错误观念的澄清,比如数学意义上的
内积的物理意义
一种向量到标量的映射
两向量的夹角的计算
两向量是否正交的判断
两向量的相似性(similarity)的度量
叉积的意义
如何使用C++语言(STL容器,运算符重载):
表示向量
计算内积
计算叉积
计算模长
计算两向量的夹角
计算点到直线的距离
代数定义
向量x=[x1,x2,…,xn]x=[x_1, x_2, \ldots, x_n]和y=[y1,y2,…,yn]y=[y_1, y_2, \ldots, y_n]的内积定义为:
x⋅y=∑inxiyi=x1y1+x2y2+⋯+xnyn
x\cdot y=\sum_i^nx_iy_i=x_1y_1+x_2y_2+\dots+x_ny_n
也即:内积等于向量的对应位相乘再相加,如果从函数的观点来看的话,即是两个矢量相互作用得到一个标量。
内积对相互作用的两个向量x,yx,y的长度也即各自所含元素的个数是没有限制的。这点不同于向量叉积,叉积所要的向量长度最高为3.
几何定义
欧式空间中,向量是一个同时拥有长度和方向的几何对象。向量xx的长度记为∥x∥\|x\|,两个向量的内积定义为:
x⋅y=∥x∥∥y∥cosθ
x\cdot y=\|x\|\|y\|cos\theta
θ\theta标识着两向量的夹角。可见当向量正交时,θ=90∘\theta = 90^\circ,x⋅y=0x\cdot y = 0。
当向量yy被归一化为长度为1的单位向量时,x⋅y=∥x∥cosθx\cdot y=\|x\|cos\theta,我们来考察x,yx,y均为二维的情形:
如上图所示,此时二者的内积表示的恰是其中一个向另外一个的投影,投影长度越小,说明二者的夹角越大,反之亦然。当两向量同时归一化为1时,此时内积的定义为:x⋅y=cosθx\cdot y = cos\theta,内积越大,说明两者夹角越小,也间接地说明两者也就越相似,故在许多机器学习的算法,常用余弦相似性来度量两特征向量的逼近程度。内积既然能够表征两向量的夹角,自然判断两向量是否正交(值为0)就更不在话下了。
x×y=x1y2−x2y1
x\times y = x_1y_2-x_2y_1
三维时
根据如图的计算方法可得:
u×v====∣∣∣∣iu1v1ju2v2ku3v3∣∣∣∣(u2v3i+u3v1j+u1v2k)−(u3v2i+u1v3j+u2v1k)(u2v3−u3v2)i+(u3v1−u1v3)j+(u1v2−u2v1)k(u2v3−u3v2,u3v1−u1v3,u1v2−u2v1)\begin{eqnarray}
\begin{split}
\textbf{u}\times \textbf{v}=&
\begin{vmatrix}
\textbf {i} & \textbf{j} & \textbf{k} \\
u_1 & u_2 & u_3 \\
v_1 & v_2 & v_3
\end{vmatrix}\\
=&(u_2v_3\textbf{i}+u_3v_1\textbf{j}+u_1v_2\textbf{k})-(u_3v_2\textbf{i}+u_1v_3\textbf{j}+u_2v_1\textbf{k})\\
=&(u_2v_3-u_3v_2)\textbf{i}+(u_3v_1-u_1v_3)\textbf{j}+(u_1v_2-u_2v_1)\textbf{k}\\
=&(u_2v_3-u_3v_2, u_3v_1-u_1v_3, u_1v_2-u_2v_1)
\end{split}
\end{eqnarray}
x\times y = \|x\|\|y\|sin\theta \vec{n}
n⃗ \vec{n}表示叉积方向上的单位向量。
中学知识告诉我们三角形的面积计算公式为:
S=∥x∥∥y∥sinθ2=∥z∥h2S=\dfrac{\|x\|\|y\|sin\theta}{2}=\dfrac{\|z\|h}{2}
其中θ\theta表示的是x,yx, y之间的夹角,由以上两个公式我们可得到
h=∥x×y∥/∥z∥
h=\|x\times y\|/\|z\|
矩阵减法
内积和叉积的定义
为了形式的简单,我们在C++中以
模长或者范数的计算
向量夹角的计算
点到直线的距离
客户端程序:
点积和
叉积并不对应matlab程序中的
.*(按位相乘)和
*(矩阵乘法)
内积的物理意义
一种向量到标量的映射
两向量的夹角的计算
两向量是否正交的判断
两向量的相似性(similarity)的度量
叉积的意义
如何使用C++语言(STL容器,运算符重载):
表示向量
计算内积
计算叉积
计算模长
计算两向量的夹角
计算点到直线的距离
prerequisites
内积(inner product)
又叫点乘,点积(dot product),数量积,顾名思义得到的是一个标量(scalar)。代数定义
向量x=[x1,x2,…,xn]x=[x_1, x_2, \ldots, x_n]和y=[y1,y2,…,yn]y=[y_1, y_2, \ldots, y_n]的内积定义为:
x⋅y=∑inxiyi=x1y1+x2y2+⋯+xnyn
x\cdot y=\sum_i^nx_iy_i=x_1y_1+x_2y_2+\dots+x_ny_n
也即:内积等于向量的对应位相乘再相加,如果从函数的观点来看的话,即是两个矢量相互作用得到一个标量。
内积对相互作用的两个向量x,yx,y的长度也即各自所含元素的个数是没有限制的。这点不同于向量叉积,叉积所要的向量长度最高为3.
几何定义
欧式空间中,向量是一个同时拥有长度和方向的几何对象。向量xx的长度记为∥x∥\|x\|,两个向量的内积定义为:
x⋅y=∥x∥∥y∥cosθ
x\cdot y=\|x\|\|y\|cos\theta
θ\theta标识着两向量的夹角。可见当向量正交时,θ=90∘\theta = 90^\circ,x⋅y=0x\cdot y = 0。
当向量yy被归一化为长度为1的单位向量时,x⋅y=∥x∥cosθx\cdot y=\|x\|cos\theta,我们来考察x,yx,y均为二维的情形:
如上图所示,此时二者的内积表示的恰是其中一个向另外一个的投影,投影长度越小,说明二者的夹角越大,反之亦然。当两向量同时归一化为1时,此时内积的定义为:x⋅y=cosθx\cdot y = cos\theta,内积越大,说明两者夹角越小,也间接地说明两者也就越相似,故在许多机器学习的算法,常用余弦相似性来度量两特征向量的逼近程度。内积既然能够表征两向量的夹角,自然判断两向量是否正交(值为0)就更不在话下了。
叉积
又叫叉乘(cross product)或者外积,它的计算结果是一个向量而非标量。叉积所在的向量与参与运算的两个向量都正交,也即正交于原来的两个向两边所决定的平面,也即两向量所决定的平面的法向量可通过计算叉积的方式得以确定。当参与运算的两向量是平行的两个向量时,得到的叉积为0,也即可通过计算叉积的方式判断两向量是否平行。代数定义
二维时x×y=x1y2−x2y1
x\times y = x_1y_2-x_2y_1
三维时
根据如图的计算方法可得:
u×v====∣∣∣∣iu1v1ju2v2ku3v3∣∣∣∣(u2v3i+u3v1j+u1v2k)−(u3v2i+u1v3j+u2v1k)(u2v3−u3v2)i+(u3v1−u1v3)j+(u1v2−u2v1)k(u2v3−u3v2,u3v1−u1v3,u1v2−u2v1)\begin{eqnarray}
\begin{split}
\textbf{u}\times \textbf{v}=&
\begin{vmatrix}
\textbf {i} & \textbf{j} & \textbf{k} \\
u_1 & u_2 & u_3 \\
v_1 & v_2 & v_3
\end{vmatrix}\\
=&(u_2v_3\textbf{i}+u_3v_1\textbf{j}+u_1v_2\textbf{k})-(u_3v_2\textbf{i}+u_1v_3\textbf{j}+u_2v_1\textbf{k})\\
=&(u_2v_3-u_3v_2)\textbf{i}+(u_3v_1-u_1v_3)\textbf{j}+(u_1v_2-u_2v_1)\textbf{k}\\
=&(u_2v_3-u_3v_2, u_3v_1-u_1v_3, u_1v_2-u_2v_1)
\end{split}
\end{eqnarray}
几何定义
x×y=∥x∥∥y∥sinθn⃗x\times y = \|x\|\|y\|sin\theta \vec{n}
n⃗ \vec{n}表示叉积方向上的单位向量。
中学知识告诉我们三角形的面积计算公式为:
S=∥x∥∥y∥sinθ2=∥z∥h2S=\dfrac{\|x\|\|y\|sin\theta}{2}=\dfrac{\|z\|h}{2}
其中θ\theta表示的是x,yx, y之间的夹角,由以上两个公式我们可得到
三角形的高或者
点到其所对的边的距离,也即点到直线的距离,的计算公式:
h=∥x×y∥/∥z∥
h=\|x\times y\|/\|z\|
C++ STL实现
向量的定义:typedef vector<double> Vec;
矩阵减法
Vec operator-(const Vec& x, const Vec& y) { assert(x.size() == y.size()); // #include <cassert> Vec tmp; for(size_t i = 0; i < x.size(); ++i) tmp.push_back(x[i] - y[i]); return tmp; // 返回局部变量的拷贝 }
内积和叉积的定义
为了形式的简单,我们在C++中以
*表示内积,以
^表示叉积,分别对二者进行运算符重载:
double operator*(const Vec& x, const Vec& y) { assert(x.size() == y.size()); // #include <cassert> double sum = 0.; for (size_t i = 0; i < x.size(); ++i) sum += x[i]*y[i]; return sum; } // 三维的情况 Vec operator^(const Vec& x, const Vec& y) { assert(x.size() == y.size() && x.size() == 3); return Vec{x[1]*y[2]-x[2]*y[1], x[2]*y[0]-x[0]*y[2], x[0]*y[1]-x[1]*y[0]}; // uniform initialization, C++11新特性 } // 二维就姑且返回其模长吧 double twoDCrossProd(const Vec& x, const Vec& y) { return x[0]*y[1]-x[1]*y[0]; }
模长或者范数的计算
double norm(const Vec& x) { double val = 0.; for(auto elem: x) val += elem*elem; return sqrt(val); // #include <cmath> }
向量夹角的计算
#define PI 3.14159265358979323846 // 弧长向弧度的转换 double toDegree(double val) { return val*180/PI; } double angle(const Vec& x, const Vec& y) { return toDegree(acos(x*y/norm(x)/norm(y))); // x*y, 计算二者的内积 }
点到直线的距离
// x0, x1, x2 分别表示三角形的三个顶点的坐标 // 这里计算的是点x0到x1和x2构成的直线的距离 double distance(const Vec& x0, const Vec& x1, const Vec& x2) { return twoDCrossProd(x1-x0, x2-x0)/norm(x1-x2); }
客户端程序:
int main(int, char**) { Vec x{1, 0, 0}, y{0, 1, 0}; Vec z = x^y; // 计算叉乘 copy(z.begin(), z.end(), ostream_iterator<double>(cout, " ")); cout << endl; // 0 0 1 Vec alpha{1, 0}, beta{1, 1}; cout << angle(alpha, beta) << endl; // 45 Vec x0{0, 0}, x1{1, 0}, x2{0, 1}; cout << distance(x0, x1, x2) << endl; // 1/sqrt(2) return 0; }
相关文章推荐
- 学习SystemC应具备的C++基本语法
- 【转】C++ 智能指针详解
- C++指针详解
- 软件工程(C编码实践篇)心得体会
- C++指针与引用在传递函数参数时的作用
- Bezier曲线曲面的C++实现
- #include<>与#include“ ”的区别
- [温故而知新] 《深度探索c++对象模型》——对象数据成员的内存布局
- C/C++内存泄漏及检测
- C++函数模板重载
- 在c++中怎么实现把char实现int形输出
- C++如何向函数传递数组
- C++爬坑日记(1) undefined reference to `vtable for
- c++primer第十章习题(1)
- C++ typedef用法小结 (※不能不看※)
- C语言中typedef 与结构体
- 水滴石穿C语言之typedef的问题
- 学习笔记1—C语言的基本语法
- java Windows平台 调用c++
- STL: unordered_map 自定义键值类型的使用(C++)