C ++的valarray与矢量(C++ valarray vs. vector)

2019-08-31 06:54发布

我喜欢矢量很多。 他们是漂亮和快速。 但我知道存在这个东西叫做valarray中。 为什么要使用valarray中,而不是一个向量的? 我知道valarrays有一些语法糖,但除此之外,他们什么时候有用吗?

Answer 1:

Valarrays(值阵列)旨在带来一些的Fortran的速度与C ++。 你不会使指针valarray中这样编译器可以对代码假设,并更好地优化它。 (主要的原因在于Fortran的是如此之快的是,没有指针类型,以便可以有没有指针混叠。)

Valarrays也有课,让你可以切片他们,在一个合理的简单的方法虽然标准的那部分可以使用更多的工作。 调整他们是破坏性的,他们缺乏的迭代器。

所以,如果它的号码,你正在使用和方便是不是所有的重要用途valarrays。 否则,向量只是方便多了。



Answer 2:

valarray的是那种在错误的时间出生在错误的地方一个孤儿。 这是在优化的尝试,相当专为被用于当它是书面的重型数学,机器 - 具体而言,向量处理器一样Crays。

对于向量处理器,你通常想要做的是应用单一操作的整个阵列,然后再应用下一个操作的整个阵列,依此类推,直到你做你需要做的一切。

除非你在处理相当小的阵列,但是,往往与不良的缓存工作。 在最现代化的机器,你通常会喜欢什么(尽可能)会加载阵列的一部分,做就可以了你要去的操作,然后转移到阵列的一个部分。

的valarray还假设以消除混叠的任何可能性,这(至少在理论上)让编译器提高速度,因为它更自由地存储在寄存器中的值。 但在现实中,我不能肯定,任何真正的实现利用了这对任何显著的程度。 我怀疑这是相当有鸡还是先有蛋的问题也 - 没有编译器支持它没有成为流行,只要它不是受欢迎的,没有人愿意去上他们的编译工作,以支持它的麻烦。

还有辅助类令人眼花缭乱的(字面)阵列的valarray使用。 你得到切片,slice_array,Gslice上和gslice_array与valarray中的碎片玩耍,并使其像一个多维数组。 你也可以得到mask_array为“面具”的操作(例如,在X项目添加到Y,但只在其中z为非零的位置)。 为了比琐碎的valarray使用更多的,你一定要学会了很多关于这些辅助类,其中有些是非常复杂的,其中没有一个似乎是(至少对我来说)非常有据可查。

底线:虽然它有辉煌的时刻,并且可以做一些事情非常整齐,也有一些很好的理由,这是(几乎肯定会留)晦涩。

编辑(八年后,2017年):有些前面的已经过时了至少在一定程度。 举一个例子,英特尔已经实施的valarray的优化版本的编译器。 它采用了英特尔集成性能基元(英特尔IPP)以提高性能。 虽然确切的性能改进无疑而变化,快速测试以简单的代码示出了围绕2:在速度1的改进,与用“标准”的执行编译的代码相同valarray

所以,虽然我并不完全相信C ++程序员将开始使用valarray在巨大的数字,有至少一些情况中,它可以提供一个速度提升。



Answer 3:

在的C ++ 98的标准化,valarray中被设计为允许某种快速数学计算的。 但是,在那个时候托德Veldhuizen发明表达模板和创建热捧++ ,和类似的模板元技术被发明出来,这让valarrays非常过时的标准,甚至发布之前。 IIRC,valarray的原提案人(S)放弃了到一半的标准化,这(如果属实)并没有帮助它的。

ISTR,它不是从标准去除的主要原因是,没有人走上彻底评估的问题,并写将其删除的建议的时间。

请记住,但是,这一切都是依稀记得传闻。 用一粒盐拿这个,希望有人纠正或证实了这一点。



Answer 4:

我知道valarrays有一些语法糖

我不得不说,我不认为std::valarrays有语法糖的方法很多。 语法是不同的,但我不会把区别“糖”。 API是怪异。 在本节std::valarray的C ++编程语言小号提到了这个不寻常的API,并且,由于事实上std::valarray s的预期是高度优化的,您在使用它们将可能是不直观的得到任何错误消息。

出于好奇,大约一年前,我进站std::valarray反对std::vector 。 我不再有代码或精确的结果(尽管它不应该是很难写你自己的)。 使用GCC我没有使用时,得到一点点性能优势std::valarray简单的数学,而不是我的实现,以计算标准偏差(,当然,标准偏差不那么复杂,只要数学去)。 我怀疑,在一个大的每一项操作std::vector与缓存比行动中发挥更好std::valarray秒。注意 ,从下面的建议musiphil ,我已经成功地得到几乎相同的性能vectorvalarray )。

最后,我决定使用std::vector同时密切关注的事情,如内存分配和临时对象的创建。


两者std::vectorstd::valarray将数据存储在一个连续的块。 然而,他们访问使用不同的模式,数据,更重要的是,对于API std::valarray鼓励比对API不同的访问模式std::vector

对于标准偏差例如,在一个特定的一步,我需要找到集合的平均值和各元素的值与平均值之间的差异。

对于std::valarray ,我不喜欢的东西:

std::valarray<double> original_values = ... // obviously I put something here
double mean = original_values.sum() / original_values.size();
std::valarray<double> temp(mean, original_values.size());
std::valarray<double> differences_from_mean = original_values - temp;

我可能已经有更聪明std::slicestd::gslice 。 它已经超过五年了。

对于std::vector ,我做线沿线的东西:

std::vector<double> original_values = ... // obviously, I put something here
double mean = std::accumulate(original_values.begin(), original_values.end(), 0.0) / original_values.size();

std::vector<double> differences_from_mean;
differences_from_mean.reserve(original_values.size());
std::transform(original_values.begin(), original_values.end(), std::back_inserter(differences_from_mean), std::bind1st(std::minus<double>(), mean));

今天,我一定会写不同。 如果不出意外,我会采取的C ++ 11个lambda表达式的优势。

很明显,代码这两个片段做不同的事情。 为一体,所述std::vector例如不会使像的中间收集std::valarray例子一样。 但是,我认为这是公平的,因为差异绑之间的差异比较它们std::vectorstd::valarray

当我写这个答案,我怀疑是从两个减去元素的值std::valarray S(在最后一行std::valarray例子)会比在相应线路较少的缓存友好std::vector例子(这恰好也是最后一行)。

事实证明,但是,

std::valarray<double> original_values = ... // obviously I put something here
double mean = original_values.sum() / original_values.size();
std::valarray<double> differences_from_mean = original_values - mean;

做同样的事情作为std::vector例子,并具有几乎相同的性能。 最后,问题是,你更喜欢哪API。



Answer 5:

的valarray应该让一些FORTRAN向量处理善擦掉C ++。 不知怎的,必要的编译器的支持从来没有真的发生了。

该约祖蒂斯书包含的valarray(一些有趣的(有点轻蔑)的评论在这里和这里 )。

但是,英特尔现在似乎在其最近发布的编译器进行重新审视的valarray(例如,见幻灯片9 ); 这是因为他们的4路SIMD SSE指令集即将被8路AVX和16路的Larrabee的指令和便携性的利益,这将有可能是更好地加入了与一个抽象的代码是一个有趣的发展比的valarray(说的)内部。



Answer 6:

我发现的valarray一个良好的使用。 它使用的valarray就像numpy的阵列。

auto x = linspace(0, 2 * 3.14, 100);
plot(x, sin(x) + sin(3.f * x) / 3.f + sin(5.f * x) / 5.f);

我们可以实现以上的valarray。

valarray<float> linspace(float start, float stop, int size)
{
    valarray<float> v(size);
    for(int i=0; i<size; i++) v[i] = start + i * (stop-start)/size;
    return v;
}

std::valarray<float> arange(float start, float step, float stop)
{
    int size = (stop - start) / step;
    valarray<float> v(size);
    for(int i=0; i<size; i++) v[i] = start + step * i;
    return v;
}

string psstm(string command)
{//return system call output as string
    string s;
    char tmp[1000];
    FILE* f = popen(command.c_str(), "r");
    while(fgets(tmp, sizeof(tmp), f)) s += tmp;
    pclose(f);
    return s;
}

string plot(const valarray<float>& x, const valarray<float>& y)
{
    int sz = x.size();
    assert(sz == y.size());
    int bytes = sz * sizeof(float) * 2;
    const char* name = "plot1";
    int shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
    ftruncate(shm_fd, bytes);
    float* ptr = (float*)mmap(0, bytes, PROT_WRITE, MAP_SHARED, shm_fd, 0);
    for(int i=0; i<sz; i++) {
        *ptr++ = x[i];
        *ptr++ = y[i];
    }

    string command = "python plot.py ";
    string s = psstm(command + to_string(sz));
    shm_unlink(name);
    return s;
}

此外,我们需要Python脚本。

import sys, posix_ipc, os, struct
import matplotlib.pyplot as plt

sz = int(sys.argv[1])
f = posix_ipc.SharedMemory("plot1")
x = [0] * sz
y = [0] * sz
for i in range(sz):
    x[i], y[i] = struct.unpack('ff', os.read(f.fd, 8))
os.close(f.fd)
plt.plot(x, y)
plt.show()


Answer 7:

在C ++ 11标准说:

所述的valarray数组类被定义为自由的混叠的某些形式中,因此允许这些类的操作进行优化。

见C ++ 11 26.6.1-2。



文章来源: C++ valarray vs. vector