C语言中的内联向量操作

3

我正在使用C语言进行科学计算,需要处理很多向量。

我已经定义了一些基本的乘法和加法函数,形式如下所示:

add(int size, double *out, double *x, double *y)

但对于复杂的操作,代码很快变得冗长且难以阅读。

是否可以定义内联运算符(V1 + V2)?或者有没有一些通用的最佳实践,使得更容易检查数学错误的代码?也许可以使用一些 #define 的技巧?


6
你是否考虑过使用C++? - Greg Hewgill
尝试使用以下代码:inline void add(int size, double *out, double *x, double *y) - 或者我是否误读了问题? - Mysticial
@Mysticial:他想从 add(sizeof(foo), out, foo, bar); 改为 out=foo+bar - sarnold
4个回答

4

一开始我以为这是一个C++相关的问题!

如果你能使用C ++,可能可以使用STL数组(其中大小是模板参数,而不是存储值)。

代码可能如下所示:

std::array<double, 7> a = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0};
std::array<double, 7> b = {0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0};
auto c = a + b;
auto d = a + b + c;

您可以为operator+定义操作符重载。例如:

#include <array>
// ...
// (version 1) returns a new copy/temporary
template <class T, size_t size>
std::array<T, size> operator+(const std::array<T, size>& a, 
                              const std::array<T, size>& b)
{
    std::array<T, size> c;
    // add them however you want; simple version:
    for (size_t i = 0; i < size; ++i)
    {
        c[i] = a[i] + b[i];
    }
    return c;
}

// (version 2) no temporaries via rvalue ref/move semantic
template <class T, size_t size>
std::array<T, size>&& operator+(std::array<T, size>&& a, 
                                const std::array<T, size>& b)
{
    for (size_t i = 0; i < size; ++i)
    {
        a[i] += b[i];
    }
    return std::move(a);
}

所以:

auto c = a + b;       // invokes version 1
auto d = a + b + c;   // invokes version 1 for (b+c) 
                      // and then version 2 for a+(temp)

所以在任何操作链中,您最多只使用一个临时变量。

std::array的内存布局应该与本地数组相同,因此如果您想尽可能少地触及现有代码(通过滥用转换、typedef或预处理器),则应该能够轻松“注入”此代码到您的现有程序中。


问题的标题和标签为 C,而不是 C++。 - dreamlax
这是一个很好的答案,我认为它不需要被删除,只需要提到它是一个C++解决方案即可。 - dreamlax

3

如果您不介意采用非标准解决方案,英特尔编译器支持C语言中的数组符号扩展。以下是链接:

http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011/compiler_c/optaps/common/optaps_par_cean_prog.htm

基本上,您可以像这样编写代码:
int A[4] = { 1, 2, 3, 4 };
int B[4] = { 4, 3, 2, 1 };
int C[4];
C[:] = A[:] + B[:];

它还提供许多数学函数的向量版本,因此您可以执行以下操作:
B[:] = cosf(C[:]);

作为额外的奖励,如果您像这样编写代码,它将在SSE / AVX指令中进行向量化。

这应该是答案。您知道这是否适用于新的AVX512吗? - Thomas Browne

2

这被称为“运算符重载”,它不是C语言的特性,但是它是C++的一个特性。如果您可以选择使用C++,那么有很多关于如何重载运算符的教程。有些人认为它是一种邪恶,因为:

  1. When code is taken out of context it is difficult to tell what will actually happen. For example, you can see operators there but how do you know whether they are the built-in ones or overloaded ones?

  2. It is possible to overload operators and apply meaning to them that is not common, for example (and this is something I have seen in actual code), you can overload the “/” operator (division operator) to act as a path separator for a class that handles filenames in an OS-independent way:

    Filename f = Filename::MainFileSystem() / "folder1" / "folder2" / "file.txt";
    

    Don't do this.

使用重载运算符也有其好处:

  1. Code can be heavily simplified. Rather than multiple function calls, you can use

    result = vec1 + vec2 + vec3;
    

    Note that as above, it is difficult to tell just from looking at that line of code whether any functions will be called but whether that difficulty outweighs the benefit of simplification is subjective.

  2. You can perform some nifty tricks, such as smart pointers, that give you added functionality without modifying the original semantics of the operators.


1
能否定义内联运算符(V1 + V2)?
不行。但在C++中可以。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接