首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C-矩阵按值传递?

C-矩阵按值传递?
EN

Stack Overflow用户
提问于 2013-03-29 00:27:13
回答 4查看 337关注 0票数 2

我正在为一个C项目设计矩阵处理函数。我正在考虑按价值或参考来传递矩阵。我通过值和引用创建了一个基准传递矩阵,两者在gcc中的优化标志-O0和-O2中似乎都执行了相同的操作。考虑到我的基准可能给出了不正确的结果,我想知道使用C来传递矩阵进出函数调用的最有效的方法是什么。

代码语言:javascript
复制
#include <stdio.h>
#include <time.h>

// Compiled on OSX 10.6.8 using: cc -o matrix matrix.c -std=c99 -O2

typedef struct {
    float m0;
    float m1;
    float m2;
    float m3;
    float m4;
    float m5;
    float m6;
    float m7;
    float m8;
    float m9;
    float m10;
    float m11;
    float m12;
    float m13;
    float m14;
    float m15;
} Matrix;

// ================================================
//                 Pass By Value
// ------------------------------------------------

Matrix PassByValue (Matrix a, Matrix b) {
    Matrix matrix;

    matrix.m0  = a.m0 * b.m0  + a.m4 * b.m1  + a.m8  * b.m2  + a.m12 * b.m3;
    matrix.m1  = a.m1 * b.m0  + a.m5 * b.m1  + a.m9  * b.m2  + a.m13 * b.m3;
    matrix.m2  = a.m2 * b.m0  + a.m6 * b.m1  + a.m10 * b.m2  + a.m14 * b.m3;
    matrix.m3  = a.m3 * b.m0  + a.m7 * b.m1  + a.m11 * b.m2  + a.m15 * b.m3;

    matrix.m4  = a.m0 * b.m4  + a.m4 * b.m5  + a.m8  * b.m6  + a.m12 * b.m7;
    matrix.m5  = a.m1 * b.m4  + a.m5 * b.m5  + a.m9  * b.m6  + a.m13 * b.m7;
    matrix.m6  = a.m2 * b.m4  + a.m6 * b.m5  + a.m10 * b.m6  + a.m14 * b.m7;
    matrix.m7  = a.m3 * b.m4  + a.m7 * b.m5  + a.m11 * b.m6  + a.m15 * b.m7;

    matrix.m8  = a.m0 * b.m8  + a.m4 * b.m9  + a.m8  * b.m10 + a.m12 * b.m11;
    matrix.m9  = a.m1 * b.m8  + a.m5 * b.m9  + a.m9  * b.m10 + a.m13 * b.m11;
    matrix.m10 = a.m2 * b.m8  + a.m6 * b.m9  + a.m10 * b.m10 + a.m14 * b.m11;
    matrix.m11 = a.m3 * b.m8  + a.m7 * b.m9  + a.m11 * b.m10 + a.m15 * b.m11;

    matrix.m12 = a.m0 * b.m12 + a.m4 * b.m13 + a.m8  * b.m14 + a.m12 * b.m15;
    matrix.m13 = a.m1 * b.m12 + a.m5 * b.m13 + a.m9  * b.m14 + a.m13 * b.m15;
    matrix.m14 = a.m2 * b.m12 + a.m6 * b.m13 + a.m10 * b.m14 + a.m14 * b.m15;
    matrix.m15 = a.m3 * b.m12 + a.m7 * b.m13 + a.m11 * b.m14 + a.m15 * b.m15;

    return matrix;
}


// ================================================
//               Pass By Reference
// ------------------------------------------------

void PassByReference (Matrix* matrix, Matrix* a, Matrix* b) {
    if (!matrix) return;
    if (!a) return;
    if (!b) return;

    matrix->m0  = a->m0 * b->m0  + a->m4 * b->m1  + a->m8  * b->m2  + a->m12 * b->m3;
    matrix->m1  = a->m1 * b->m0  + a->m5 * b->m1  + a->m9  * b->m2  + a->m13 * b->m3;
    matrix->m2  = a->m2 * b->m0  + a->m6 * b->m1  + a->m10 * b->m2  + a->m14 * b->m3;
    matrix->m3  = a->m3 * b->m0  + a->m7 * b->m1  + a->m11 * b->m2  + a->m15 * b->m3;

    matrix->m4  = a->m0 * b->m4  + a->m4 * b->m5  + a->m8  * b->m6  + a->m12 * b->m7;
    matrix->m5  = a->m1 * b->m4  + a->m5 * b->m5  + a->m9  * b->m6  + a->m13 * b->m7;
    matrix->m6  = a->m2 * b->m4  + a->m6 * b->m5  + a->m10 * b->m6  + a->m14 * b->m7;
    matrix->m7  = a->m3 * b->m4  + a->m7 * b->m5  + a->m11 * b->m6  + a->m15 * b->m7;

    matrix->m8  = a->m0 * b->m8  + a->m4 * b->m9  + a->m8  * b->m10 + a->m12 * b->m11;
    matrix->m9  = a->m1 * b->m8  + a->m5 * b->m9  + a->m9  * b->m10 + a->m13 * b->m11;
    matrix->m10 = a->m2 * b->m8  + a->m6 * b->m9  + a->m10 * b->m10 + a->m14 * b->m11;
    matrix->m11 = a->m3 * b->m8  + a->m7 * b->m9  + a->m11 * b->m10 + a->m15 * b->m11;

    matrix->m12 = a->m0 * b->m12 + a->m4 * b->m13 + a->m8  * b->m14 + a->m12 * b->m15;
    matrix->m13 = a->m1 * b->m12 + a->m5 * b->m13 + a->m9  * b->m14 + a->m13 * b->m15;
    matrix->m14 = a->m2 * b->m12 + a->m6 * b->m13 + a->m10 * b->m14 + a->m14 * b->m15;
    matrix->m15 = a->m3 * b->m12 + a->m7 * b->m13 + a->m11 * b->m14 + a->m15 * b->m15;
}

// ================================================
//                  Benchmark
// ------------------------------------------------

#define LOOPS 100000

int main () {
    Matrix result;
    Matrix a;
    Matrix b;
    clock_t begin;
    clock_t end;
    int index;

    // ------------------------------------------
    //          Pass By Reference
    // ------------------------------------------
    begin = clock();
    for (index = 0; index < LOOPS; index++) {

        PassByReference(&result,&a,&b);
        a.m0 += index;
        b.m0 += index;

    }
    end = clock();
    printf("Pass By Ref: %f\n",(double)(end - begin) / CLOCKS_PER_SEC);

    // ------------------------------------------
    //            Pass By Value
    // ------------------------------------------
    begin = clock();
    for (index = 0; index < LOOPS; index++) {

        result = PassByValue(a,b);
        a.m0 += index;
        b.m0 += index;

    }
    end = clock();
    printf("Pass By Val: %f\n",(double)(end - begin) / CLOCKS_PER_SEC);


    // The following line along with the above
    // additions in the loops hopefully prevent
    // the matrices from being optimized into
    // nothing.
    printf("%0.1f\n",result.m0);

    return 0;
}

结果:

代码语言:javascript
复制
Pass By Ref: 0.489226
Pass By Val: 0.488882
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-03-29 01:45:36

你在这里有两个相互竞争的利益:

  1. 通过按值传递结构,这将被键入为数据存储类,并通过x86调用约定推到堆栈上,这比将被卡在寄存器中的by ref调用慢一点。
  2. 这几乎完全被一堆指针推理所平衡.

将每一部分分开,并分别轮廓。

如果您试图使这类代码更快一些,那么您可能能够在某种SIMD代码、AltiVec、SSE或OpenCL中编写更快的实现。

票数 0
EN

Stack Overflow用户

发布于 2013-03-29 01:16:20

来自有效的C++:

与按值传递相比,更倾向于按引用传递,这通常更有效,并且避免了切片问题。该规则不适用于内置类型、STL迭代器和函数对象类型。对他们来说,按值传递通常是合适的.

我知道您是用C而不是C++编程的,但我认为这条规则仍然适用。这两个示例的执行非常接近的原因可能是,结构只包含浮点,并且由于它是通过值传递的,所以复制成本很低。

然而,正如“有效C++”一书的作者所说

有些编译器拒绝将只有双倍组成的对象放入寄存器中,尽管他们很高兴地定期将裸双放在那里。当这种情况发生时,您可以更好地通过引用传递这些对象,因为编译器肯定会将指针放入寄存器“。

在您的例子中,也许机器不介意将结构放在寄存器中,但是很难判断何时在其他机器上运行您的程序。由于他们的表现非常接近,所以我会投票通过。

票数 0
EN

Stack Overflow用户

发布于 2013-03-29 01:49:15

无论如何,32种浮点值都不适合寄存器。编译器将被迫将数据从内存中推送到堆栈上,堆栈只是内存的另一部分。根据数据访问的次数,复制数据甚至可能更慢,而不是取消引用指针。

我建议对任何非标量数据使用随引用传递和const修饰符.编译器的工作是为特定平台优化代码。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15694495

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档