C++ valarray 与向量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1602451/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C++ valarray vs. vector
提问by rlbond
I like vectors a lot. They're nifty and fast. But I know this thing called a valarray exists. Why would I use a valarray instead of a vector? I know valarrays have some syntactic sugar, but other than that, when are they useful?
我非常喜欢矢量。它们既漂亮又快速。但我知道这个叫做 valarray 的东西存在。为什么我要使用 valarray 而不是向量?我知道 valarrays 有一些语法糖,但除此之外,它们什么时候有用?
采纳答案by Tim Allman
Valarrays (value arrays) are intended to bring some of the speed of Fortran to C++. You wouldn't make a valarray of pointers so the compiler can make assumptions about the code and optimise it better. (The main reason that Fortran is so fast is that there is no pointer type so there can be no pointer aliasing.)
Valarrays(值数组)旨在将 Fortran 的某些速度带入 C++。您不会创建一个 valarray 指针,因此编译器可以对代码做出假设并更好地优化它。(Fortran 如此之快的主要原因是没有指针类型,因此不能有指针别名。)
Valarrays also have classes which allow you to slice them up in a reasonably easy way although that part of the standard could use a bit more work. Resizing them is destructive and they lack iterators.
Valarrays 也有允许你以相当简单的方式将它们切片的类,尽管标准的那部分可能需要更多的工作。调整它们的大小是破坏性的,而且它们缺乏迭代器。
So, if it's numbers you are working with and convenience isn't all that important use valarrays. Otherwise, vectors are just a lot more convenient.
因此,如果是您正在使用的数字并且便利性并不是那么重要,请使用 valarrays。否则,向量就方便多了。
回答by Jerry Coffin
valarray
is kind of an orphan that was born in the wrong place at the wrong time. It's an attempt at optimization, fairly specifically for the machines that were used for heavy-duty math when it was written -- specifically, vector processors like the Crays.
valarray
有点像在错误的时间出生在错误的地方的孤儿。这是一种优化尝试,特别是针对在编写时用于重型数学的机器——特别是像 Crays 这样的向量处理器。
For a vector processor, what you generally wanted to do was apply a single operation to an entire array, then apply the next operation to the entire array, and so on until you'd done everything you needed to do.
对于向量处理器,您通常想要做的是将单个操作应用于整个数组,然后将下一个操作应用于整个数组,依此类推,直到完成您需要做的所有事情。
Unless you're dealing with fairly small arrays, however, that tends to work poorly with caching. On most modern machines, what you'd generally prefer (to the extent possible) would be to load part of the array, do all the operations on it you're going to, then move on to the next part of the array.
但是,除非您正在处理相当小的数组,否则它在缓存时往往效果不佳。在大多数现代机器上,您通常更喜欢(在可能的范围内)加载数组的一部分,对其执行所有操作,然后移至数组的下一部分。
valarray
is also supposed to eliminate any possibility of aliasing, which (at least theoretically) lets the compiler improve speed because it's more free to store values in registers. In reality, however, I'm not at all sure that any real implementation takes advantage of this to any significant degree. I suspect it's rather a chicken-and-egg sort of problem -- without compiler support it didn't become popular, and as long as it's not popular, nobody's going to go to the trouble of working on their compiler to support it.
valarray
还应该消除任何混叠的可能性,这(至少在理论上)让编译器提高速度,因为在寄存器中存储值更自由。然而,实际上,我完全不确定任何真正的实现会在多大程度上利用这一点。我怀疑这是一个先有鸡还是先有蛋的问题——如果没有编译器支持,它就不会流行,而且只要它不流行,没有人会费心去开发他们的编译器来支持它。
There's also a bewildering (literally) array of ancillary classes to use with valarray. You get slice
, slice_array
, gslice
and gslice_array
to play with pieces of a valarray
, and make it act like a multi-dimensional array. You also get mask_array
to "mask" an operation (e.g. add items in x to y, but only at the positions where z is non-zero). To make more than trivial use of valarray
, you have to learn a lot about these ancillary classes, some of which are pretty complex and none of which seems (at least to me) very well documented.
还有一个令人眼花缭乱的(字面意思)数组与 valarray 一起使用的辅助类。你得到slice
,slice_array
,gslice
并gslice_array
用一个个打valarray
,并使其像一个多维数组。您还可以mask_array
“屏蔽”操作(例如,将 x 中的项目添加到 y,但仅限于 z 非零的位置)。为了不只是简单地使用valarray
,您必须了解很多关于这些辅助类的知识,其中一些非常复杂,而且没有一个看起来(至少对我而言)有很好的文档记录。
Bottom line: while it has moments of brilliance, and can do some things pretty neatly, there are also some very good reasons that it is (and will almost certainly remain) obscure.
底线:虽然它有辉煌的时刻,并且可以非常整洁地做一些事情,但也有一些很好的理由让它(并且几乎肯定会保持)默默无闻。
Edit (eight years later, in 2017): Some of the preceding has become obsolete to at least some degree. For one example, Intel has implemented an optimized version of valarray for their compiler. It uses the Intel Integrated Performance Primitives (Intel IPP) to improve performance. Although the exact performance improvement undoubtedly varies, a quick test with simple code shows around a 2:1 improvement in speed, compared to identical code compiled with the "standard" implementation of valarray
.
编辑(八年后,2017 年):前面的一些内容至少在某种程度上已经过时了。例如,英特尔为其编译器实施了 valarray 的优化版本。它使用 Intel Integrated Performance Primitives (Intel IPP) 来提高性能。尽管确切的性能改进无疑会有所不同,但与使用valarray
.
So, while I'm not entirely convinced that C++ programmers will be starting to use valarray
in huge numbers, there are least some circumstances in which it can provide a speed improvement.
因此,虽然我并不完全相信 C++ 程序员将开始大量使用valarray
,但至少在某些情况下它可以提高速度。
回答by sbi
During the standardization of C++98, valarray was designed to allow some sort of fast mathematical computations. However, around that time Todd Veldhuizen invented expression templates and created blitz++, and similar template-meta techniques were invented, which made valarrays pretty much obsolete before the standard was even released. IIRC, the original proposer(s) of valarray abandoned it halfway into the standardization, which (if true) didn't help it either.
在 C++98 的标准化过程中,valarray 被设计为允许进行某种快速的数学计算。然而,在那个时候 Todd Veldhuizen 发明了表达式模板并创建了blitz++,并且发明了类似的模板元技术,这使得 valarrays 在标准发布之前就已经过时了。IIRC,valarray 的原始提议者在标准化中途放弃了它,这(如果为真)也无济于事。
ISTR that the main reason it wasn't removed from the standard is that nobody took the time to evaluate the issue thoroughly and write a proposal to remove it.
ISTR 认为它没有从标准中删除的主要原因是没有人花时间彻底评估该问题并编写提案以将其删除。
Please keep in mind, however, that all this is vaguely remembered hearsay.Take this with a grain of salt and hope someone corrects or confirms this.
但是请记住,这一切都是依稀记得的道听途说。对此持保留态度,希望有人纠正或确认这一点。
回答by Max Lybbert
I know valarrays have some syntactic sugar
我知道 valarrays 有一些语法糖
I have to say that I don't think std::valarrays
have much in way of syntactic sugar. The syntax is different, but I wouldn't call the difference "sugar." The API is weird. The section on std::valarray
s in The C++ Programming Languagementions this unusual API and the fact that, since std::valarray
s are expected to be highly optimized, any error messages you get while using them will probably be non-intuitive.
我不得不说,我认为std::valarrays
没有太多的语法糖。语法不同,但我不会称这种差异为“糖”。API 很奇怪。The C++ Programming Language中关于std::valarray
s的部分提到了这个不寻常的 API 以及这样一个事实,因为s 应该是高度优化的,因此您在使用它们时得到的任何错误消息都可能是不直观的。std::valarray
Out of curiosity, about a year ago I pitted std::valarray
against std::vector
. I no longer have the code or the precise results (although it shouldn't be hard to write your own). Using GCC I didget a little performance benefit when using std::valarray
for simple math, but not for my implementations to calculate standard deviation (and, of course, standard deviation isn't that complex, as far as math goes). I suspect that operations on each item in a large (NOTE, following advice from musiphil, I've managed to get almost identical performance from std::vector
play better with caches than operations on std::valarray
s.vector
and valarray
).
出于好奇,大约一年前,我std::valarray
与std::vector
. 我不再有代码或精确的结果(尽管编写自己的代码应该不难)。使用 GCC在用于简单的数学运算时确实获得了一些性能优势std::valarray
,但对于我的实现来计算标准偏差却没有(当然,就数学而言,标准偏差并不那么复杂)。 我怀疑对大型项目中的每个项目的(注意,根据musiphil 的建议,我设法从std::vector
操作对缓存的作用比对std::valarray
s 的操作更好。vector
和获得几乎相同的性能valarray
)。
In the end, I decided to use std::vector
while paying close attention to things like memory allocation and temporary object creation.
最后,我决定使用,std::vector
同时密切关注内存分配和临时对象创建等事情。
Both std::vector
and std::valarray
store the data in a contiguous block. However, they access that data using different patterns, and more importantly, the API for std::valarray
encourages different access patterns than the API for std::vector
.
二者std::vector
并std::valarray
存储在一个连续的块中的数据。然而,他们使用不同的模式访问数据,更重要的是,API forstd::valarray
鼓励不同的访问模式,而不是std::vector
.
For the standard deviation example, at a particular step I needed to find the collection's mean and the difference between each element's value and the mean.
对于标准偏差示例,在特定步骤中,我需要找到集合的均值以及每个元素的值与均值之间的差值。
For the std::valarray
, I did something like:
对于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;
I may have been more clever with std::slice
or std::gslice
. It's been over five years now.
我可能更聪明地使用std::slice
或std::gslice
。到现在已经五年多了。
For std::vector
, I did something along the lines of:
对于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));
Today I would certainly write that differently. If nothing else, I would take advantage of C++11 lambdas.
今天我肯定会写不同的。如果不出意外,我会利用 C++11 lambdas。
It's obvious that these two snippets of code do different things. For one, the std::vector
example doesn't make an intermediate collection like the std::valarray
example does. However, I think it's fair to compare them because the differences are tied to the differences between std::vector
and std::valarray
.
很明显,这两个代码片段做了不同的事情。一方面,该std::vector
示例不像示例那样创建中间集合std::valarray
。但是,我认为比较它们是公平的,因为差异与std::vector
和之间的差异有关std::valarray
。
When I wrote this answer, I suspected that subtracting the value of elements from two std::valarray
s (last line in the std::valarray
example) would be less cache-friendly than the corresponding line in the std::vector
example (which happens to also be the last line).
当我写这个答案时,我怀疑从两个std::valarray
s中减去元素的值(std::valarray
示例中的最后一行)会比std::vector
示例中的相应行(恰好也是最后一行)对缓存不太友好。
It turns out, however, that
然而,事实证明,
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;
Does the same thing as the std::vector
example, and has almost identical performance. In the end, the question is which API you prefer.
与std::vector
示例执行相同的操作,并且具有几乎相同的性能。最后,问题是您更喜欢哪种 API。
回答by timday
valarray was supposed to let some FORTRAN vector-processing goodness rub off on C++. Somehow the necessary compiler support never really happened.
valarray 应该让一些 FORTRAN 向量处理的优点在 C++ 上消失。不知何故,必要的编译器支持从未真正发生过。
The Josuttis books contains some interesting (somewhat disparaging) commentary on valarray (hereand here).
Josuttis 书籍包含一些关于 valarray 的有趣(有点贬低)评论(这里和这里)。
However, Intel now seem to be revisiting valarray in their recent compiler releases (e.g see slide 9); this is an interesting development given that their 4-way SIMD SSE instruction set is about to be joined by 8-way AVX and 16-way Larrabee instructions and in the interests of portability it'll likely be much better to code with an abstraction like valarray than (say) intrinsics.
然而,英特尔现在似乎正在他们最近的编译器版本中重新审视 valarray(例如,参见幻灯片 9);这是一个有趣的发展,因为他们的 4 路 SIMD SSE 指令集即将加入 8 路 AVX 和 16 路 Larrabee 指令,并且为了可移植性,使用抽象编码可能会更好,例如valarray 比(说)内在函数。
回答by Zeta
I found one good usage for valarray. It's to use valarray just like numpy arrays.
我发现了 valarray 的一个很好的用法。它就像使用 numpy 数组一样使用 valarray。
auto x = linspace(0, 2 * 3.14, 100);
plot(x, sin(x) + sin(3.f * x) / 3.f + sin(5.f * x) / 5.f);
We can implement above with valarray.
我们可以用 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;
}
Also, we need python script.
另外,我们需要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()
回答by Lingxi
The C++11 standard says:
C++11 标准说:
The valarray array classes are defined to be free of certain forms of aliasing, thus allowing operations on these classes to be optimized.
valarray 数组类被定义为没有某些形式的别名,从而允许优化对这些类的操作。
See C++11 26.6.1-2.
参见 C++11 26.6.1-2。
回答by Paul Jurczak
With std::valarray
you can use the standard mathematical notation like v1 = a*v2 + v3
out of the box. This is not possible with vectors unless you define your own operators.
有了std::valarray
你可以使用标准的数学符号像v1 = a*v2 + v3
开箱。除非您定义自己的运算符,否则这对于向量是不可能的。
回答by mrpivello
std::valarray is intended for heavy numeric tasks, such as Computational Fluid Dynamics or Computational Structure Dynamics, in which you have arrays with millions, sometimes tens of millions of items, and you iterate over them in a loop with also millions of timesteps. Maybe today std::vector has a comparable performance but, some 15 years ago, valarray was almost mandatory if you wanted to write an efficient numeric solver.
std::valarray 适用于繁重的数值任务,例如计算流体动力学或计算结构动力学,在这些任务中,您有数百万甚至数千万项的数组,并且您在循环中迭代它们,也有数百万个时间步长。也许今天 std::vector 具有相当的性能,但是,大约 15 年前,如果您想编写一个高效的数值求解器,valarray 几乎是强制性的。