MKL學習——基本操作C++實現
前言
前面介紹了各種向量-向量,矩陣-向量,矩陣-矩陣的函式簡介。根據自身目前狀況,主要使用實數域的操作,也就是說關注單精度float型別的s
和雙精度double型別的d
。還有就是用的基本都是全矩陣,沒有經過壓縮,也不是對稱、三角、帶狀的某一種情況。所以主要還是總結一般的乘法、加法操作。
【注】程式碼都以單精度float的情況書寫,主要流程要記住,使用mkl_malloc
申請記憶體,使用mkl_free
釋放記憶體。n年沒用過C++了,湊合看看吧。
學MKL的肯定對程式設計有一定程度瞭解,智慧提示是一個很好的工具,在VS中,輸入cblas_s
以後,會自動補全所有的單精度操作函式,那麼根據常規經驗,就能判斷出它到底用於做什麼以及需要的引數;比如提示axpby
a*x
加b*y
。還有就是函式有兩種,一種是有返回值,一種無返回值,怎麼辦,只能提示看函式的宣告是void
還是float
或者是double
型別即可。
向量-向量
加法
運算
程式碼
#include<stdio.h>
#include<stdlib.h>
#include<mkl.h>
int main()
{
float *A, *B;//兩個向量
int a=1, b=1;//標量
int n = 5;//向量大小
A = (float *)mkl_malloc(n * 1 * sizeof (float), 64);
B = (float *)mkl_malloc(n * 1 * sizeof(float), 64);
printf("The 1st vector is ");
for (int i = 0; i < n; i++){
A[i] = i;
printf("%2.0f", A[i]);
}
printf("\n");
printf("The 2st vector is ");
for (int i = 0; i < n; i++){
B[i] =i+1;
printf ("%2.0f", B[i]);
}
printf("\n");
//計算a*A+b*B
cblas_saxpby(n, a, A, 1, b, B, 1);
printf("The a*A+b*B is ");
for (int i = 0; i < n; i++){
printf("%2.0f", B[i]);
}
printf("\n");
mkl_free(A);
mkl_free(B);
getchar();
return 0;
}
結果
The 1st vector is 0 1 2 3 4
The 2st vector is 1 2 3 4 5
The a*A+b*B is 1 3 5 7 9
乘法
運算:向量點乘
程式碼:
//乘法
#include<stdio.h>
#include<stdlib.h>
#include <mkl.h>
int main()
{
float *A, *B;//兩個向量
int a = 1, b = 1;//標量
int n = 5;//向量大小
float res;
A = (float *)mkl_malloc(n * 1 * sizeof(float), 64);
B = (float *)mkl_malloc(n * 1 * sizeof(float), 64);
printf("The 1st vector is ");
for (int i = 0; i < n; i++){
A[i] = i;
printf("%2.0f", A[i]);
}
printf("\n");
printf("The 2st vector is ");
for (int i = 0; i < n; i++){
B[i] = i + 1;
printf("%2.0f", B[i]);
}
printf("\n");
//乘法:對應元素乘積的加和
res=cblas_sdot(n, A, 1, B, 1);
printf("點乘結果: %2.0f",res);
printf("\n");
mkl_free(A);
mkl_free(B);
getchar();
return 0;
}
結果:
The 1st vector is 0 1 2 3 4
The 2st vector is 1 2 3 4 5
點乘結果: 40
二範數
運算:二範數或者歐幾里得範數,是所有元素平方和開根號
程式碼
//計算向量二範數
#include<stdio.h>
#include<stdlib.h>
#include<mkl.h>
void main()
{
float *A;
int n = 5;
float res;
A = (float *)mkl_malloc(n*sizeof(float), 64);
printf("The original vector:\n");
for (int i = 0; i < n; i++)
{
A[i] = i + 1;
printf("%2.0f ", A[i]);
}
printf("\n");
res = cblas_snrm2(n, A, 1);//計算二範數
printf("The norm2 of vector is:%2.6f", res);
mkl_free(A);
getchar();
}
結果:
The original vector:
1 2 3 4 5
The norm2 of vector is:7.416198
旋轉
運算:將空間中一個點,繞原點旋轉的角度
程式碼:以二維座標點Cblas
函式,可以直接把指向陣列的指標丟進去。暫時先這樣理解吧,等把C++複習一遍再來看看分析的對不對。
//旋轉,以二維空間中的一個點(2,0)繞原點旋轉45°
#include<stdio.h>
#include<stdlib.h>
#include<mkl.h>
#include<math.h>
#define M_PI 3.14159265358979323846
int main()
{
float *A, *B;//A是座標點,B是旋轉矩陣
float point1[] = { 2 };//旋轉點x座標
float point2[] = { 0 };//旋轉點y座標
float rotpoint[] = { cos(45.0*M_PI / 180), sin(45.0*M_PI / 180) };
//A = (float *)mkl_malloc(1 * sizeof(float), 64);
//B = (float *)mkl_malloc(1 * sizeof(float), 64);
A = point1;
B = point2;
printf("The point is (%2.0f,%2.0f)",point1[0],point2[0]);
printf("\n");
//計算旋轉後的點
cblas_srot(1, A, 1, B, 1, rotpoint[0], rotpoint[1]);
printf("The rotated is (%2.6f,%2.6f)", A[0], B[0]);
printf("\n");
//mkl_free(A);
//mkl_free(B);
getchar();
return 0;
}
結果:還是比較正確的
The point is ( 2, 0)
The rotated is (1.414214,-1.414214)
縮放
運算
程式碼
//計算向量縮放
#include<stdio.h>
#include<stdlib.h>
#include<mkl.h>
void main()
{
float *A;
int n = 5;
float scal=0.1;
A = (float *)mkl_malloc(n*sizeof(float), 64);
printf("The original vector:\n");
for (int i = 0; i < n; i++)
{
A[i] = i + 1;
printf("%2.0f ", A[i]);
}
printf("\n");
cblas_sscal(n, scal, A, 1);//縮放
printf("The scaled vector:\n");
for (int i = 0; i < n; i++)
{
printf("%2.1f ", A[i]);
}
mkl_free(A);
getchar();
}
結果
The original vector:
1 2 3 4 5
The scaled vector:
0.1 0.2 0.3 0.4 0.5
交換
運算:交換兩個向量
程式碼
//交換
#include<stdio.h>
#include<stdlib.h>
#include<mkl.h>
int main()
{
float *A, *B;//兩個向量
int a = 1, b = 1;//標量
int n = 5;//向量大小
A = (float *)mkl_malloc(n * 1 * sizeof(float), 64);
B = (float *)mkl_malloc(n * 1 * sizeof(float), 64);
printf("The 1st vector is ");
for (int i = 0; i < n; i++){
A[i] = i;
printf("%2.0f", A[i]);
}
printf("\n");
printf("The 2st vector is ");
for (int i = 0; i < n; i++){
B[i] = i + 1;
printf("%2.0f", B[i]);
}
printf("\n");
//交換AB
cblas_sswap(n, A, 1, B, 1);
printf("The 1st swapped vctor is");
for (int i = 0; i < n; i++){
printf("%2.0f", A[i]);
}
printf("\n");
printf("The 2st swapped vctor is");
for (int i = 0; i < n; i++){
printf("%2.0f", B[i]);
}
printf("\n");
mkl_free(A);
mkl_free(B);
getchar();
return 0;
}
結果
The 1st vector is 0 1 2 3 4
The 2st vector is 1 2 3 4 5
The 1st swapped vctor is 1 2 3 4 5
The 2st swapped vctor is 0 1 2 3 4
最值
運算:求最大最小值
程式碼
//求最大最小值
#include<stdlib.h>
#include<stdio.h>
#include<mkl.h>
void main()
{
float *A;//向量
int n = 5;//向量大小
int max, min;
A = (float *)mkl_malloc(n * 1 * sizeof(float), 64);
printf("The 1st vector is ");
for (int i = 0; i < n; i++){
A[i] = i;
printf("%2.0f", A[i]);
}
printf("\n");
//計算最值位置
max=cblas_isamax(n, A, 1);
min = cblas_isamin(n, A, 1);
printf("The max value is %2.0f, position is %d\n", A[max], max + 1);
printf("The min value is %2.0f, position is %d\n", A[min], min + 1);
mkl_free(A);
getchar();
}
結果
The 1st vector is 0 1 2 3 4
The max value is 4, position is 5
The min value is 0, position is 1
矩陣-向量
乘法1
運算:
程式碼
//矩陣-向量乘積
#include<stdio.h>
#include<stdlib.h>
#include<mkl.h>
int main()
{
float *A, *B,*C;//A是矩陣,B是向量,C是向量
int m = 2;//矩陣行數
int n = 5;//向量維度,矩陣列數
int a = 1, b = 1;//縮放因子
A = (float *)mkl_malloc(m*n*sizeof(float), 64);
B = (float *)mkl_malloc(n*sizeof(float), 64);
C = (float *)mkl_malloc(m*sizeof(float), 64);
//賦值,按行儲存?
printf("陣列為\n");
for (int i = 0; i < m*n; i++){
if (i%n == 0 && i != 0)
printf("\n");
A[i] = i;
printf("%2.0f",A[i]);
}
printf("\n");
printf("向量為\n");
for (int i = 0; i < n; i++)
{
B[i] = i + 1;
printf("%2.0f", B[i]);
}
printf("\n");
for (int i = 0; i < m*n; i++)
C[i] = 0;
//2*5的矩陣與5*1的向量相乘
cblas_sgemv(CblasRowMajor, CblasNoTrans, m, n, a, A, n, B, 1, b, C, 1);
printf("矩陣-向量乘法結果\n");
for (int i = 0; i < m; i++){
printf("%2.0f ", C[i]);
}
mkl_free(A);
mkl_free(B);
mkl_free(C);
getchar();
return 0;
}
結果
陣列為
0 1 2 3 4
5 6 7 8 9
向量為
1 2 3 4 5
矩陣-向量乘法結果
40 115
乘法2
運算
程式碼
//矩陣-向量乘積
#include<stdio.h>
#include<stdlib.h>
#include<mkl.h>
int main()
{
float *A, *B, *C;//A是矩陣,B是向量
int m=2,n = 5;//B,C向量維度
int a = 1;//縮放因子
A = (float *)mkl_malloc(m*n*sizeof(float), 64);
B = (float *)mkl_malloc(m*sizeof(float), 64);
C = (float *)mkl_malloc(n*sizeof(float), 64);
//賦值,按行儲存?
printf("陣列為\n");
for (int i = 0; i < m*n; i++){
if (i%n == 0 && i != 0)
printf("\n");
A[i] = 1;
printf("%2.0f", A[i]);
}
printf("\n");
printf("向量1為\n");
for (int i = 0; i < m; i++)
{
B[i] = i + 1;
printf("%2.0f", B[i]);
}
printf("\n");
printf("向量2為\n");
for (int i = 0; i < n; i++)
{
C[i] = i+2;
printf("%2.0f", C[i]);
}
printf("\n");
//5*1向量乘以1*5向量,加上5*5矩陣
cblas_sger(CblasRowMajor, m, n, a, B, 1, C, 1, A, n);
printf("向量-向量相乘+矩陣的結果\n");
for (int i = 0; i < m*n; i++){
if (i%n == 0 && i != 0)
printf("\n");
printf("%2.0f ", A[i]);
}
mkl_free(A);
mkl_free(B);
mkl_free(C);
getchar();
return 0;
}
結果
陣列為
1 1 1 1 1
1 1 1 1 1
向量1為
1 2
向量2為
2 3 4 5 6
向量-向量相乘+矩陣的結果
3 4 5 6 7
5 7 9 11 13
矩陣-矩陣
乘法1
運算
程式碼
#include<stdio.h>
#include<stdlib.h>
#include<mkl.h>
int main()
{
float *A, *B, *C;
int m = 2, n = 3, k = 2;//A維度2*3,B維度2*3(計算時候轉置),C維度2*2
int a = 1, b = 1;//縮放因子
A = (float *)mkl_malloc(m*n*sizeof(float), 64);
B = (float *)mkl_malloc(n*k*sizeof(float), 64);
C = (float *)mkl_malloc(m*k*sizeof(float), 64);
printf("矩陣1為\n");
for (int i = 0; i < m*n; i++)
{
if (i != 0 && i%n == 0)
printf("\n");
A[i] = i + 1;
printf("%2.0f", A[i]);
}
printf("\n");
printf("矩陣2為\n");
for (int i = 0; i < n*k; i++)
{
if (i != 0 && i%k == 0)
printf("\n");
B[i] = 1;
printf("%2.0f", B[i]);
}
printf("\n");
printf("矩陣3為\n");
for (int i = 0; i < m*k; i++)
{
if (i != 0 && i%k == 0)
printf("\n");
C[i] = i;
printf("%2.0f", C[i]);
}
printf("\n");
printf("結果矩陣\n");
cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, m, k, n, a, A, n, B, k, b, C, k);//注意mkn的順序☆
for (int i = 0; i < m*k; i++)
{
if (i != 0 && i%k == 0)
printf("\n");
printf("%2.0f", C[i]);
}
printf("\n");
mkl_free(A);
mkl_free(B);
mkl_free(C);
getchar();
return 0;
}
結果
矩陣1為
1 2 3
4 5 6
矩陣2為
1 1
1 1
1 1
矩陣3為
0 1
2 3
結果矩陣
6 7
1718
乘法2
依舊是上述的功能,此處嘗試一下
#include<stdio.h>
#include<stdlib.h>
#include<mkl.h>
int main()
{
float *A, *B, *C;
int m = 2, n = 3, k = 2;//A維度2*3,B維度2*3(計算時候轉置),C維度2*2
int a = 1, b = 1;//縮放因子
A = (float *)mkl_malloc(m*n*sizeof(float), 64);
B = (float *)mkl_malloc(k*n*sizeof(float), 64);
C = (float *)mkl_malloc(m*k*sizeof(float), 64);
printf("矩陣1為\n");
for (int i = 0; i < m*n; i++)
{
if (i != 0 && i%n == 0)
printf("\n");
A[i] = i + 1;
printf("%2.0f", A[i]);
}
printf("\n");
printf("矩陣2為\n");
for (int i = 0; i < k*n; i++)
{
if (i != 0 && i%n == 0)
printf("\n");
B[i] = 1;
printf("%2.0f", B[i]);
}
printf("\n");
printf("矩陣3為\n");
for (int i = 0; i < m*k; i++)
{
if (i != 0 && i%k == 0)
printf("\n");
C[i] = i;
printf("%2.0f", C[i]);
}
printf("\n");
printf("結果矩陣\n");
cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, k, n, a, A, n, B, n, b, C, k);//注意mkn的順序☆
for (int i = 0; i < m*k; i++)
{
if (i != 0 && i%k == 0)
printf("\n");
printf("%2.0f", C[i]);
}
printf("\n");
mkl_free(A);
mkl_free(B);
mkl_free(C);
getchar();
return 0;
}
結果
矩陣1為
1 2 3
4 5 6
矩陣2為
1 1 1
1 1 1
矩陣3為
0 1
2 3
結果矩陣
6 7
1718
注意點
最主要的是記住引數順序,首先是矩陣
而且丟入函式的引數,並不一定是mkl_malloc
開闢的空間,也可以是其它陣列,用指標指向陣列地址,然後丟到函式就行了。
奉上code(vs2013): MKL -C++基本操作