解释 Python 中的算术乘法、数组乘法和矩阵乘法
(1)算术乘法,整数、实数、复数、高精度实数之间的乘法。
(2)列表、元组、字符串这几种类型的对象与整数之间的乘法,表示对列表、元组或字符串进行重复,返回新列表、元组、字符串。
需要特别注意的是,列表、元组、字符串与整数相乘,是对其中的元素的引用进行复用,如果元组或列表中的元素是列表、字典、集合这样的可变对象,得到的新对象与原对象之间会互相干扰。
(3)numpy数组与数字num相乘,表示原数组中每个数字与num相乘,返回新数组,类似的规则也适用于加、减、真除、整除、幂运算等。
(4)numpy数组与类似于数组的对象(array-like,包括Python列表、元组和numpy数组)相乘(同样适用于加、减、真除、整除和幂运算),需要满足广播的条件:两个数组的shape属性的元组右对齐之后要求两个元组在垂直方向的两个数字要么相等、要么其中一个为1、要么其中一个对应位置上没有数字(没有对应的维度),结果数组中该维度的大小与二者之中最大的一个相等。在(3)中介绍的数组与标量的四则运算实际上也属于广播。例如,(m,n)的数组可以和(1,)、(n,)、(1,n)、(m,1)、(m,n)的数组进行相乘。
下面再演示几种可以广播的情况:
(5)numpy数组与array-like对象的点积,通过numpy数组的dot()方法或numpy的dot()函数实现。
数组与标量相乘,等价于乘法运算符或numpy.multiply()函数:
如果两个数组是长度相同的一维数组,计算结果为两个向量的内积:
如果两个数组是形状分别为(m,n)和(n,)的二维数组和一维数组,计算结果为二维数组每行分别与一维数组的内积组成的数组:
如果一个任意多维数组和一个一维数组(要求大小与多维数组最后一个维度相等)相乘,多维数组的最后一个维度分别与一维数组计算内积,计算内积的维度消失:
如果两个数组是形状分别为(m,k)和(k,n)的二维数组,表示两个矩阵相乘,结果为(m,n)的二维数组,此时一般使用等价的矩阵乘法运算符@或者numpy的函数matmul():
如果一个n维数组和一个m(>=2)维数组进行dot()运算,第一个数组的最后一个维度与第二个数组的倒数第二个维度计算内积。
在这种情况下,第一个数组的最后一个维度和第二个数组的倒数第二个维度将会消失,如下图所示,划红线的维度消失:
6)numpy矩阵与矩阵相乘时,运算符*和@功能相同,都表示线性代数里的矩阵乘法。
7)连乘,计算所有数值相乘的结果,可以使用标准库函数math.prod(),Python 3.8之后支持。
扩展库函数numpy.prod()提供了更强大的功能。
8)累乘,每个数字与前面的所有数字相乘,可以使用扩展库函数numpy.cumprod()
下一篇: 还原法实现了加法乘法的方法
推荐阅读
-
解释 Python 中的算术乘法、数组乘法和矩阵乘法
-
《【算法导论】动态规划在矩阵链乘法中的应用》 #include
void printParentheses(int s[6][6], int i, int j); // 打印加括号的位置 void matrixOrder(int* p, int n, int m[6][6], int s[6][6]); // 计算最佳加括号的方式 int main() { int p[7] = {30, 35, 15, 5, 10, 20, 25}; // 记录6个矩阵的行和列,注意相邻矩阵的行和列是相同的 int m[6][6] = {0}; // 存储第i个矩阵到第j个矩阵的计算代价(以乘法次数来表示) int s[6][6] = {0}; // 存储第i个矩阵到第j个矩阵的最小代价时的分为两部分的位置 int n = 6; // 矩阵个数 matrixOrder(p, n, m, s); printf("最终加括号的形式为:\n"); // 输出加括号的位置 printParentheses(s, 0, 5); return 0; } /****************************************************\ 函数功能:计算最佳的加括号的方式,得到m和s矩阵 输入: 矩阵的行和列p, 初始化的m和s矩阵 输出: 无 \****************************************************/ void matrixOrder(int* p, int n, int m[6][6], int s[6][6]) { int q = 0; int j = 0; for (int i = 0; i < n; i++) m[i][i] = 0; for (int l = 2; l <= n; l++) for (int i = 0; i < n - l + 1; i++) { j = i + l - 1; m[i][j] = 1000000; for (int k = i; k < j; k++) // 在i,j中遍历每一个分割的位置 { q = m[i][k] + m[k + 1][j] + p[i] * p[k + 1] * p[j + 1]; // 计算代价 if (q < m[i][j]) { m[i][j] = q; s[i][j] = k; } } } } /****************************************************\ 函数功能:打印加括号的位置 输入: s矩阵,想要计算的矩阵链的起始和结尾位置 输出: 无 \****************************************************/ void printParentheses(int s[6][6], int i, int j) { if (i == j) printf("A%d", i); else { printf("("); printParentheses(s, i, s[i][j]); printParentheses(s, s[i][j] + 1, j); // 递归调用 printf(")"); } }