C ++ valarray vs. 벡터
나는 벡터를 많이 좋아한다. 그들은 깔끔하고 빠릅니다. 그러나 나는 valarray라는 것이 존재한다는 것을 알고 있습니다. 왜 벡터 대신에 valarray를 사용해야합니까? 나는 valarrays에 약간의 구문 설탕이 있다는 것을 알고 있지만, 그 외에는 언제 유용합니까?
Valarray (값 배열)는 Fortran의 속도 중 일부를 C ++로 가져 오도록 고안되었습니다. 컴파일러는 포인터에 대한 valarray를 만들지 않으므로 컴파일러가 코드에 대한 가정을하고 더 잘 최적화 할 수 있습니다. (Fortran이 너무 빠른 주된 이유는 포인터 유형이 없으므로 포인터 별칭이 없기 때문입니다.)
Valarrays에는 표준의 일부가 약간 더 많은 작업을 사용할 수 있지만 합리적으로 쉬운 방법으로 클래스를 슬라이스 할 수있는 클래스가 있습니다. 그것들의 크기를 조정하는 것은 파괴적이며 반복자가 없습니다.
따라서 숫자로 작업하고 편리함이 중요한 용도로 사용되는 것은 아닙니다. 그렇지 않으면 벡터가 훨씬 더 편리합니다.
valarray
잘못된 시간에 잘못된 장소에서 태어난 고아의 일종입니다. 최적화, 특히 Crays와 같은 벡터 프로세서가 쓰여질 때 강력한 수학에 사용 된 기계에 대한 최적화 시도입니다.
벡터 프로세서의 경우 일반적으로 수행하려는 작업은 전체 배열에 단일 작업을 적용한 다음 다음 작업을 전체 배열에 적용하는 등 필요한 모든 작업을 수행 할 때까지 계속되었습니다.
그러나 상당히 작은 배열을 다루지 않는 한 캐싱에는 제대로 작동하지 않는 경향이 있습니다. 대부분의 최신 컴퓨터에서 일반적으로 선호하는 것은 배열의 일부를로드하고 모든 작업을 수행 한 다음 배열의 다음 부분으로 이동하는 것입니다.
valarray
또한 (적어도 이론적으로는) 레지스터에 값을 더 자유롭게 저장할 수 있기 때문에 컴파일러가 속도를 향상시킬 수있는 앨리어싱 가능성을 제거해야합니다. 그러나 실제로는 실제 구현이이 점을 어느 정도 활용하는지 확실하지 않습니다. 나는 그것이 일종의 닭과 계란 종류의 문제라고 생각합니다. 컴파일러 지원이 없으면 인기를 얻지 못했지만 인기가 없다면 컴파일러를 지원하는 데 어려움을 겪지는 않을 것입니다.
valarray와 함께 사용할 어리석은 (문자 그대로) 보조 클래스가 있습니다. 당신은 얻을 slice
, slice_array
, gslice
그리고 gslice_array
(A)의 조각과 재생 valarray
, 그리고 그것은 다차원 배열처럼 행동합니다. 또한 mask_array
연산을 "마스크"할 수 있습니다 (예 : x에 y의 항목을 추가하지만 z가 0이 아닌 위치에만). 을 사소하게 사용하려면 valarray
이 보조 클래스에 대해 많은 것을 배워야합니다. 그 중 일부는 꽤 복잡하고 그 중 어느 것도 매우 잘 문서화되지 않은 것 같습니다.
결론 : 그것은 광채의 순간을 가지고 있으며 꽤 깔끔하게 어떤 일을 할 수 있지만, 그것이 모호한 (그리고 거의 확실하게 남아있을) 매우 좋은 이유가 있습니다.
편집 (8 년 후, 2017 년) : 위의 일부 중 적어도 일부는 더 이상 사용되지 않습니다. 일례로, 인텔은 컴파일러에 최적화 된 버전의 valarray를 구현했습니다. 인텔 IPP (Integrated Performance Primitives)를 사용하여 성능을 향상시킵니다. 정확한 성능 향상은 의심 할 여지없이 다양하지만, 간단한 코드를 사용한 빠른 테스트는 "표준"구현으로 컴파일 된 동일한 코드와 비교하여 속도가 약 2 : 1 개선되었음을 보여줍니다 valarray
.
따라서 C ++ 프로그래머가 valarray
많은 수 를 사용할 것이라고 확신하지는 않지만 속도 향상을 제공 할 수있는 상황은 최소한 있습니다.
C ++ 98을 표준화하는 동안 valarray는 일종의 빠른 수학적 계산을 허용하도록 설계되었습니다. 그러나 그 당시 Todd Veldhuizen은 발현 템플릿을 발명하고 blitz ++를 만들었 으며 유사한 템플릿 메타 기술이 개발되어 표준이 출시되기 전에는 valarray를 거의 쓸모 없게 만들었습니다. valarray의 최초 제안자 인 IIRC는 표준화에 반을 버렸으며, 사실 인 경우에도 도움이되지 않았습니다.
ISTR이 표준에서 제거되지 않은 주된 이유는 아무도 문제를 철저히 평가하고 제거 제안을 작성하지 않았기 때문입니다.
그러나이 모든 것이 모호하게 기억 된 정보라는 점을 명심하십시오. 소금 한 알로 이것을 가지고 누군가가 이것을 수정하거나 확인하기를 바랍니다.
valarrays에 약간의 구문 설탕이 있다는 것을 알고 있습니다
나는 std::valarrays
구문 설탕을 많이 가지고 있다고 생각하지 않는다고 말해야합니다 . 구문은 다르지만 그 차이를 "설탕"이라고 부르지는 않습니다. API가 이상합니다. C ++ 프로그래밍 언어std::valarray
의 s 섹션 에서는이 비정상적인 API에 대해 언급하고 있으며,이 API 는 고도로 최적화 될 것으로 예상 되므로 사용 중에 발생하는 모든 오류 메시지는 직관적이지 않을 수 있습니다.std::valarray
약 1 년 전에 호기심에서 나는 std::valarray
대항했다 std::vector
. 더 이상 코드 나 정확한 결과를 얻지 못합니다 (자체를 작성하는 것이 어렵지는 않지만). GCC 내가 사용 했던 사용할 때 약간의 성능 이점을 얻을 std::valarray
내 구현 표준 편차를 계산하는 간단한 수학을 위해,하지만 (물론,과, 표준 편차가되지 복잡한 즉, 지금까지의 수학 간다).
큰 항목의 각 항목에 대한 ( 참고 , 조언을 다음 musiphil , 나는 거의 동일한에서 성능을 얻기 위해 관리했습니다 std::vector
작업이 std::valarray
s의 작업보다 캐시에서 더 잘
작동한다고 생각합니다
.
vector
과 valarray
).
결국 std::vector
메모리 할당 및 임시 객체 생성과 같은 것에주의를 기울이면서 사용하기로 결정했습니다 .
모두 std::vector
와 std::valarray
연속 된 블록에 데이터를 저장합니다. 그러나 이들은 다른 패턴을 사용하여 해당 데이터에 액세스하며,보다 중요한 API는에 대한 API와 std::valarray
다른 액세스 패턴 을 권장합니다 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::slice
또는 로 더 영리했을 수도 있습니다 std::gslice
. 5 년이 지났습니다.
에 대해 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.
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
.
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).
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.
valarray was supposed to let some FORTRAN vector-processing goodness rub off on C++. Somehow the necessary compiler support never really happened.
The Josuttis books contains some interesting (somewhat disparaging) commentary on valarray (here and here).
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.
I found one good usage for valarray. It's to use valarray just like numpy arrays.
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<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.
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()
The C++11 standard says:
The valarray array classes are defined to be free of certain forms of aliasing, thus allowing operations on these classes to be optimized.
See C++11 26.6.1-2.
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.
참고URL : https://stackoverflow.com/questions/1602451/c-valarray-vs-vector
'IT' 카테고리의 다른 글
Android SSL 연결에 대한 신뢰 앵커를 찾을 수 없습니다 (0) | 2020.06.10 |
---|---|
URL에서 Bower와의 종속성 설치 및 버전 지정 (0) | 2020.06.10 |
Ruby / Rails : int를 시간으로 변환하거나 정수에서 시간을 얻습니까? (0) | 2020.06.10 |
iPhone Safari Web App이 새 창에서 링크를 엽니 다 (0) | 2020.06.09 |
Eclipse IDE에서 키보드 단축키를 수정하는 방법은 무엇입니까? (0) | 2020.06.09 |