Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 矩阵和向量乘法优化算法_C_Optimization_Openmp_Matrix Multiplication_Divide And Conquer - Fatal编程技术网

C 矩阵和向量乘法优化算法

C 矩阵和向量乘法优化算法,c,optimization,openmp,matrix-multiplication,divide-and-conquer,C,Optimization,Openmp,Matrix Multiplication,Divide And Conquer,假设维度非常大(矩阵中最多有10亿个元素)。如何实现矩阵向量积的缓存无关算法?基于维基百科,我需要递归地分而治之,但我觉得这会有很多开销。。这样做是否有效率 后续问题和答案:因此,“如何使这个基本线性代数运算快速”这个问题的答案总是可以在任何地方找到,并链接到您平台的优化BLAS库。例如,(其工作正在继续),或较慢的自动调谐,或像英特尔的MKL这样的商业软件包。线性代数对于许多其他操作来说都是非常基础的,因此需要花费大量精力为各种平台优化这些软件包,而在几天下午的工作中,你根本不可能想出有竞争力

假设维度非常大(矩阵中最多有10亿个元素)。如何实现矩阵向量积的缓存无关算法?基于维基百科,我需要递归地分而治之,但我觉得这会有很多开销。。这样做是否有效率


后续问题和答案:

因此,“如何使这个基本线性代数运算快速”这个问题的答案总是可以在任何地方找到,并链接到您平台的优化BLAS库。例如,(其工作正在继续),或较慢的自动调谐,或像英特尔的MKL这样的商业软件包。线性代数对于许多其他操作来说都是非常基础的,因此需要花费大量精力为各种平台优化这些软件包,而在几天下午的工作中,你根本不可能想出有竞争力的东西。对于一般稠密矩阵向量乘法,您需要的特定子例程调用是SGEMV/DGEMV/CGEMV/ZGEMV

缓存不经意算法,或自动调整,适用于您无法为系统的特定缓存体系结构进行调整的情况——通常情况下,这可能很好,但由于人们愿意为BLAS例程进行调整,然后使调整后的结果可用,这意味着您最好只使用这些例程

GEMV的内存访问模式非常简单,您实际上不需要分而治之(与矩阵转置的标准情况相同)——您只需找到缓存块大小并使用它。在GEMV(y=Ax)中,您仍然需要扫描整个矩阵一次,因此在那里没有什么可重复使用(从而有效地使用缓存)的方法,但是您可以尽可能多地尝试重复使用x,以便加载它一次而不是(行数)次,并且您仍然希望对缓存的访问是友好的。因此,要做的明显的缓存阻塞操作是沿块中断:

  A x -> [ A11 | A12 ] | x1 | = | A11 x1 + A12 x2 |
         [ A21 | A22 ] | x2 |   | A21 x1 + A22 x2 |
你当然可以递归地这样做。但是做一个简单的实现,它比简单的双循环慢,比正确的SGEMV库调用慢得多:

$ ./gemv
Testing for N=4096
Double Loop: time = 0.024995, error = 0.000000
Divide and conquer: time = 0.299945, error = 0.000000
SGEMV: time = 0.013998, error = 0.000000
守则如下:

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include "mkl.h"

float **alloc2d(int n, int m) {
    float *data = malloc(n*m*sizeof(float));
    float **array = malloc(n*sizeof(float *));
    for (int i=0; i<n; i++)
        array[i] = &(data[i*m]);
    return array;
}

void tick(struct timeval *t) {
    gettimeofday(t, NULL);
}

/* returns time in seconds from now to time described by t */
double tock(struct timeval *t) {
    struct timeval now;
    gettimeofday(&now, NULL);
    return (double)(now.tv_sec - t->tv_sec) + ((double)(now.tv_usec - t->tv_usec)/1000000.);
}

float checkans(float *y, int n) {
    float err = 0.;
    for (int i=0; i<n; i++)
        err += (y[i] - 1.*i)*(y[i] - 1.*i);
    return err;
}

/* assume square matrix */
void divConquerGEMV(float **a, float *x, float *y, int n,
                    int startr, int endr, int startc, int endc) {

    int nr = endr - startr + 1;
    int nc = endc - startc + 1;

    if (nr == 1 && nc == 1) {
        y[startc] += a[startr][startc] * x[startr];
    } else {
        int midr = (endr + startr+1)/2;
        int midc = (endc + startc+1)/2;
        divConquerGEMV(a, x, y, n, startr, midr-1, startc, midc-1);
        divConquerGEMV(a, x, y, n, midr,   endr,   startc, midc-1);
        divConquerGEMV(a, x, y, n, startr, midr-1, midc,   endc);
        divConquerGEMV(a, x, y, n, midr,   endr,   midc,   endc);
    }
}
int main(int argc, char **argv) {
    const int n=4096;
    float **a = alloc2d(n,n);
    float *x  = malloc(n*sizeof(float));
    float *y  = malloc(n*sizeof(float));
    struct timeval clock;
    double eltime;

    printf("Testing for N=%d\n", n);

    for (int i=0; i<n; i++) {
        x[i] = 1.*i;
        for (int j=0; j<n; j++)
            a[i][j] = 0.;
        a[i][i] = 1.;
    }

    /* naive double loop */
    tick(&clock);
    for (int i=0; i<n; i++) {
        y[i] = 0.;
        for (int j=0; j<n; j++) {
            y[i] += a[i][j]*x[j];
        }
    }
    eltime = tock(&clock);
    printf("Double Loop: time = %lf, error = %f\n", eltime, checkans(y,n));

    for (int i=0; i<n; i++) y[i] = 0.;

    /* naive divide and conquer */
    tick(&clock);
    divConquerGEMV(a, x, y, n, 0, n-1, 0, n-1);
    eltime = tock(&clock);
    printf("Divide and conquer: time = %lf, error = %f\n", eltime, checkans(y,n));

    /* decent GEMV implementation */
    tick(&clock);

    float alpha = 1.;
    float beta =  0.;
    int incrx=1;
    int incry=1;
    char trans='N';

    sgemv(&trans,&n,&n,&alpha,&(a[0][0]),&n,x,&incrx,&beta,y,&incry);
    eltime = tock(&clock);
    printf("SGEMV: time = %lf, error = %f\n", eltime, checkans(y,n));

    return 0;
}
#包括
#包括
#包括
#包括“mkl.h”
浮动**alloc2d(整数n,整数m){
float*data=malloc(n*m*sizeof(float));
浮点**数组=malloc(n*sizeof(float*);
对于(inti=0;itv_-sec)+(double)(now.tv_-usec-t->tv_-usec)/1000000);
}
浮点校验(浮点*y,整数n){
浮动误差=0。;
对于(int i=0;i?