使用 c++使用 valarray 的标准库算法

发布于 2024-10-21 02:36:59 字数 1084 浏览 6 评论 0原文

我试图避免重新实现我自己的笨拙版本的标准算法,因此正在使用标准库版本。由于我不是 C++ 专家,因此我谨慎行事并打开了完整的调试选项。

具体来说,我在 valarray 容器上使用二分搜索。以下代码块似乎产生了正确的结果,并且 valgrind 没有抱怨。尽管如此,我确实觉得自己正处于滑坡状态,因为我不确定我所做的事情是否真的被允许,或者我只是被编译器放了出来。

一段有代表性的代码:

#include <iostream>
#include <valarray>
#include <algorithm>
#include <typeinfo>

using namespace std;

int main(){

 valarray<double> v(10);
 for (int i=0 ; i<10 ; ++i){
   v[i]=2. *i ; 
   cout<<v[i]<<"  ";
 }
 cout << "\n";

 double what=17;
 double* it=lower_bound(&v[0], &v[10],what) ; 

 cout<<it-&v[0]<<" "<<typeid(&v[0]).name()<<" ";
 cout<<typeid(it).name()<<" "<<typeid(it-&v[0]).name()<<"\n"; // ???

 int idx=it-&v[0];
 cout<<"v["<<idx<<"]="<<v[idx]<<"\n";
}

问题:

  1. 我在这里所做的真的合法吗?
  2. 为什么两个 double 指针之间的差异会变成 int ? (在带有 ??? 注释的行中)
  3. 类型转换的开销是多少? --- 我关心效率,因为此类功能将位于代码中,占用超过 90% 的计算时间。

I'm trying to avoid reimplementing my own clumsy versions of standard algorithms, and thus am playing with the standard library versions. Since I'm no expert in C++, I proceed with caution and full debug options switched on.

Specifically, I'm using a binary search on a valarray container. The following code block seems to produce correct results, and valgrind does not complain. Still, I do feel I'm on a slippery slope as I'm not sure if what I'm doing is really allowed or am I just being let out by the compiler.

A representative piece of code:

#include <iostream>
#include <valarray>
#include <algorithm>
#include <typeinfo>

using namespace std;

int main(){

 valarray<double> v(10);
 for (int i=0 ; i<10 ; ++i){
   v[i]=2. *i ; 
   cout<<v[i]<<"  ";
 }
 cout << "\n";

 double what=17;
 double* it=lower_bound(&v[0], &v[10],what) ; 

 cout<<it-&v[0]<<" "<<typeid(&v[0]).name()<<" ";
 cout<<typeid(it).name()<<" "<<typeid(it-&v[0]).name()<<"\n"; // ???

 int idx=it-&v[0];
 cout<<"v["<<idx<<"]="<<v[idx]<<"\n";
}

Questions:

  1. Is what I'm doing here really legal?
  2. How come the difference between two pointers to double becomes an int? (in the line with the ??? comment)
  3. What is the overhead for the type conversion? --- I am concerned with efficiency as this sort of functionality is going to sit in the part of the code which takes more than 90% of the computation time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

紫竹語嫣☆ 2024-10-28 02:36:59
  1. 您正在使用 int 来索引 valarray。这对于示例有效,但不适用于一般情况。使用 std::size_t 索引到 valarray。 (对于 std::vector 和普通数组也是如此。)

  2. 指向任何类型的两个指针之间的差异是未指定的整数类型,可能是 int 或 < code>long 并且总是足够小以适合 std::ptrdiff_t

  3. 哪种转化?

  1. You're using an int to index into the valarray. That's valid for the example, but not in general. Use an std::size_t to index into a valarray. (The same goes for std::vector and ordinary arrays.)

  2. The difference between two pointers to any type is of an unspecified integer type, likely int or long and always small enough to fit in an std::ptrdiff_t.

  3. Which conversion?

回忆躺在深渊里 2024-10-28 02:36:59

我相信这是所有已定义的行为,将继续在任何实现中发挥作用。查看 valarray 的各种文档,看起来它必须是合法的,才能使有关 ::std::valarray 的所有其他内容成立。指向元素的裸指针应保持完全有效,直到调用 resize 成员函数或销毁 valarray 为止。

唯一真正的问题是是否需要 valarray 连续保存其元素。我在一篇文章中找到了该问题的答案。我将其摘录在这里:

是的,valarray也使用连续
贮存。具体措辞来自
标准是($26.3.2.3/3):
表达式 &a[i+j] == &a[i] + j
对于所有 size_t i 和
size_t j 使得 i+j 小于
非常量数组的长度
a.

当然,切片仍然无法直接与标准算法一起使用,尽管创建切片迭代器应该不会太难。制作一个双向迭代器非常容易,但创建一个随机访问迭代器则困难得多(您必须完全正确地完成许多棘手的数学运算)。

两个指针之间的差异变成(正如其他人所说)::std::ptrdiff_t。在不同的平台上这将是不同的类型。我在 64 位 Fedora 14 下使用 gcc,类型对我来说是 long 。这种“类型转换”没有任何开销。这甚至不是真正的转换。编译器只是进行减法,就好像两个指针是普通的旧数字一样,结果是某种类型的普通旧数字。使用 ::std::ptrdiff_t 作为类型是为了确保所使用的数字类型足够大以容纳系统中任意两个指针之间的差异。

I believe this is all defined behavior that will continue to work on any implementation. Looking at the various documentation for valarray, it looks like it has to be legal in order for all the other things about ::std::valarray to hold true. The bare pointers to the elements should remain perfectly valid until the resize member function is called or the valarray is destroyed.

The only real question is whether or not valarray is required to hold its elements contiguously or not. And I found the answer to that question in a post. I'll excerpt it here:

Yes, valarray also uses contiguous
storage. The specific wording from the
standard is ($26.3.2.3/3): The
expression &a[i+j] == &a[i] + j
evaluates as true for all size_t i and
size_t j such that i+j is less than
the length of the non-constant array
a.

Of course, slices still won't be able to be used directly with the standard algorithms, though creating a slice iterator shouldn't be too hard. It'd be pretty easy to make a bidirectional one, but much harder (lots of tricky math you have to get exactly right) to create a random access iterator.

The difference between two pointers becomes (as someone else said) ::std::ptrdiff_t. This will be a different type on different platforms. I use gcc under 64-bit Fedora 14, and the type is long for me. There is no overhead in this 'type conversion'. It isn't even a conversion really. The compiler just does the subtraction as if the two pointers were plain old numbers and the result is a plain old number of some type. The use of ::std::ptrdiff_t for the type is to ensure that the type of number used is big enough to hold the difference between any two pointers in the system.

叫嚣ゝ 2024-10-28 02:36:59

这些 it-&v[0] 真的吓到我了..你是说 it->v[0] 吗? lower_bound的返回值是valarray::iterator类型,请使用它而不是double*!所有其他解除引用问题将自动消失。例如,您可以执行 *itit++ 但不能执行 it->v[0],因为它不是指针而是一个迭代器。它很可能是一个 v.end() 迭代器,使得您获取其值的所有尝试都是非法的。

有关迭代器的更多信息:http://www.cppreference.com/wiki/iterator/start

编辑:哦,现在我明白了,你正在使用可怕的指针算术!那太棒了,我们不再这样做了;)

These it-&v[0] really scare me .. did you mean it->v[0]? The return value of lower_bound is of type valarray<double>::iterator, please use that instead of double*! All the other derefencing issues will go away automatically. For example you can do *it and it++ but you can't do it->v[0], because it's not a pointer but an iterator. It may very well be an v.end()-iterator making all your attemts to get its value illegal.

More info on iterators: http://www.cppreference.com/wiki/iterator/start

Edit: Oh now I see, you are using scary pointer arithmetic! That's sooo C, we don't do that anymore ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文