Bardzo lubię wektory. Są sprytne i szybkie. Ale wiem, że istnieje coś takiego jak valarray. Dlaczego miałbym używać valarray zamiast wektora? Wiem, że valarrays mają trochę cukru syntaktycznego, ale poza tym, kiedy są przydatne?
159
valarray
tu i tutajOdpowiedzi:
Valarrays (tablice wartości) mają na celu zwiększenie szybkości języka Fortran do C ++. Nie tworzyłbyś tablicy wskaźników, aby kompilator mógł przyjąć założenia dotyczące kodu i lepiej go zoptymalizować. (Głównym powodem, dla którego Fortran jest tak szybki, jest brak typu wskaźnika, więc nie może być aliasingu wskaźnika).
Valarrays mają również klasy, które pozwalają ci je pokroić w dość łatwy sposób, chociaż ta część standardu może wymagać trochę więcej pracy. Zmiana ich rozmiaru jest destrukcyjna i brakuje im iteratorów.
Tak więc, jeśli chodzi o liczby, z którymi pracujesz, a wygoda nie jest tak ważna, użyj wartości. W przeciwnym razie wektory są po prostu znacznie wygodniejsze.
źródło
valarray
jest sierotą, która urodziła się w niewłaściwym miejscu o niewłaściwym czasie. Jest to próba optymalizacji, całkiem konkretnie dla maszyn, które były używane do ciężkiej matematyki, kiedy została napisana - w szczególności procesorów wektorowych, takich jak Crays.W przypadku procesora wektorowego zwykle chciałeś zastosować jedną operację do całej tablicy, a następnie zastosować następną operację do całej tablicy i tak dalej, aż zrobisz wszystko, co trzeba.
Jeśli jednak nie masz do czynienia z dość małymi tablicami, to zwykle źle działa z buforowaniem. W przypadku większości nowoczesnych maszyn, generalnie wolisz (w miarę możliwości) załadować część tablicy, wykonać wszystkie operacje na niej, które zamierzasz, a następnie przejść do następnej części tablicy.
valarray
ma również wyeliminować jakąkolwiek możliwość aliasingu, co (przynajmniej teoretycznie) pozwala kompilatorowi zwiększyć szybkość, ponieważ ma większą swobodę przechowywania wartości w rejestrach. W rzeczywistości jednak nie jestem wcale pewien, czy jakakolwiek rzeczywista implementacja wykorzystuje to w jakikolwiek sposób. Podejrzewam, że jest to raczej problem typu kura i jajko - bez wsparcia kompilatora nie stał się popularny i dopóki nie jest popularny, nikt nie będzie zadawać sobie trudu pracy nad ich kompilatorem, aby go wspierać.Istnieje również oszałamiająca (dosłownie) tablica klas pomocniczych do użycia z valarray. Masz
slice
,slice_array
,gslice
igslice_array
bawić się z kawałkówvalarray
, i sprawiają, że zachowują się jak wielowymiarowej tablicy. Możesz takżemask_array
„zamaskować” operację (np. Dodać elementy w x do y, ale tylko w pozycjach, w których z jest niezerowe). Aby zrobić więcej niż trywialny użytekvalarray
, musisz się wiele nauczyć o tych klasach pomocniczych, z których niektóre są dość złożone i żadna z nich nie wydaje się (przynajmniej mi) dobrze udokumentowana.Podsumowując: chociaż ma momenty błyskotliwości i może robić pewne rzeczy całkiem zgrabnie, istnieją również bardzo dobre powody, dla których jest (i prawie na pewno pozostanie) niejasne.
Edycja (osiem lat później, w 2017 r.): Niektóre z powyższych stały się przynajmniej w pewnym stopniu przestarzałe. Na przykład Intel wdrożył zoptymalizowaną wersję valarray dla swojego kompilatora. Używa Intel Integrated Performance Primitives (Intel IPP), aby poprawić wydajność. Chociaż dokładna poprawa wydajności jest niewątpliwie różna, szybki test z prostym kodem pokazuje poprawę szybkości około 2: 1 w porównaniu z identycznym kodem skompilowanym przy użyciu „standardowej” implementacji
valarray
.Tak więc, chociaż nie jestem do końca przekonany, że programiści C ++ zaczną używać
valarray
w ogromnych ilościach, są przynajmniej pewne okoliczności, w których może to zapewnić poprawę szybkości.źródło
Podczas standaryzacji C ++ 98 valarray został zaprojektowany, aby umożliwić pewnego rodzaju szybkie obliczenia matematyczne. Jednak mniej więcej w tym czasie Todd Veldhuizen wynalazł szablony wyrażeń i stworzył blitz ++ , a także wynaleziono podobne techniki szablonów-meta, które sprawiły, że valarrays stały się przestarzałe, zanim jeszcze standard został wydany. IIRC, pierwotny projektodawca Valarray porzucił ją w połowie procesu standaryzacji, co (jeśli to prawda) też jej nie pomogło.
ISTR, że głównym powodem, dla którego nie został usunięty ze standardu, jest to, że nikt nie poświęcił czasu na dogłębną ocenę problemu i napisanie propozycji jego usunięcia.
Należy jednak pamiętać, że wszystko to jest niejasno zapamiętane z pogłosek. Weź to z przymrużeniem oka i miej nadzieję, że ktoś to poprawi lub potwierdzi.
źródło
Muszę powiedzieć, że nie sądzę
std::valarrays
, aby mieć dużo cukru syntaktycznego. Składnia jest inna, ale nie nazwałbym tej różnicy „cukrem”. API jest dziwne. Sekcja na tematstd::valarray
s w C ++ Programming Language wspomina o tym niezwykłym API oraz o fakcie, że ponieważstd::valarray
oczekuje się , że s będą wysoce zoptymalizowane, wszelkie komunikaty o błędach, które otrzymasz podczas ich używania, będą prawdopodobnie nieintuicyjne.Z ciekawości mniej więcej rok temu walczyłem
std::valarray
przeciwkostd::vector
. Nie mam już kodu ani dokładnych wyników (chociaż napisanie własnego nie powinno być trudne). Używając GCC, odniosłem niewielką korzyść w zakresie wydajności, gdy używamstd::valarray
do prostej matematyki, ale nie w moich implementacjach do obliczania odchylenia standardowego (i oczywiście odchylenie standardowe nie jest tak skomplikowane, jeśli chodzi o matematykę).Podejrzewam, że operacje na każdym elemencie w dużej( UWAGA , po porady od musiphil , udało mi się dostać niemal identycznej wydajnościstd::vector
grze działają lepiej z pamięciami podręcznymi niż operacje nastd::valarray
s.vector
ivalarray
).W końcu zdecydowałem się użyć
std::vector
, zwracając szczególną uwagę na takie rzeczy, jak alokacja pamięci i tworzenie tymczasowych obiektów.Oba
std::vector
istd::valarray
przechowują dane w ciągłym bloku. Jednak uzyskują dostęp do tych danych przy użyciu innych wzorców, a co ważniejsze, API forstd::valarray
zachęca do innych wzorców dostępu niż API forstd::vector
.W przypadku przykładu odchylenia standardowego na określonym kroku musiałem znaleźć średnią zbioru i różnicę między wartością każdego elementu a średnią.
Dla tego
std::valarray
zrobiłem coś takiego:Mogłem być mądrzejszy z
std::slice
lubstd::gslice
. Minęło już ponad pięć lat.Bo
std::vector
zrobiłem coś w stylu:Dziś na pewno napisałbym to inaczej. Jeśli nic więcej, skorzystałbym z lambd C ++ 11.
Jest oczywiste, że te dwa fragmenty kodu robią różne rzeczy. Po pierwsze,
std::vector
przykład nie tworzy pośredniej kolekcji, jak wstd::valarray
przykładzie. Uważam jednak, że warto je porównać, ponieważ różnice są powiązane z różnicami międzystd::vector
istd::valarray
.Kiedy pisałem tę odpowiedź, podejrzewałem, że odjęcie wartości elementów od dwóch
std::valarray
s (ostatnia linia wstd::valarray
przykładzie) byłoby mniej przyjazne dla pamięci podręcznej niż odpowiadająca jej linia wstd::vector
przykładzie (która jest również ostatnią linią).Okazuje się jednak, że
Robi to samo, co
std::vector
przykład i ma prawie identyczną wydajność. Na koniec pozostaje pytanie, który interfejs API preferujesz.źródło
std::vector
miałby grać lepiej z pamięciami podręcznymi niżstd::valarray
; oboje przydzielają pojedynczy ciągły blok pamięci dla swoich elementów.valarray
powyższym przykładzie nie musiałeś konstruowaćtemp
valarray
obiektu, ale mogłeś to zrobićstd::valarray<double> differences_from_mean = original_values - mean;
, a zachowanie pamięci podręcznej powinno być podobne do tego zvector
przykładu. (Nawiasem mówiąc, jeślimean
tak naprawdęint
nie jestdouble
, możesz potrzebowaćstatic_cast<double>(mean)
.)valarray
. Muszę sprawdzić, czy to poprawi wydajność. A jeśli chodzi omean
bycieint
: to był błąd. Pierwotnie napisałem przykład używającint
s, a potem zdałem sobie sprawę,mean
że wtedy byłby bardzo daleko od rzeczywistej średniej z powodu obcięcia. Ale przegapiłem kilka potrzebnych zmian podczas mojej pierwszej rundy edycji.Valarray miał pozwolić niektórym zaletom przetwarzania wektorów FORTRAN na C ++. W jakiś sposób niezbędne wsparcie kompilatora tak naprawdę nigdy się nie wydarzyło.
Książki Josuttisa zawierają interesujące (nieco lekceważące) komentarze na temat valarray ( tu i tutaj ).
Jednak obecnie wydaje się, że Intel ponownie odwiedza valarray w swoich ostatnich wydaniach kompilatorów (np. Patrz slajd 9 ); jest to interesujący rozwój, biorąc pod uwagę, że do ich 4-kierunkowego zestawu instrukcji SIMD SSE dołączą 8-kierunkowe instrukcje AVX i 16-kierunkowe instrukcje Larrabee, a ze względu na przenośność prawdopodobnie znacznie lepiej będzie kodować z abstrakcją valarray niż (powiedzmy) wewnętrzne.
źródło
Znalazłem jedno dobre zastosowanie dla valarray. Używa valarray tak jak numpy tablic.
Powyższe możemy wdrożyć za pomocą valarray.
Potrzebujemy również skryptu Python.
źródło
Standard C ++ 11 mówi:
Zobacz C ++ 11 26.6.1-2.
źródło
Dzięki temu
std::valarray
możesz użyć standardowej notacji matematycznej jak pov1 = a*v2 + v3
wyjęciu z pudełka. Nie jest to możliwe w przypadku wektorów, chyba że zdefiniujesz własne operatory.źródło
std :: valarray jest przeznaczony do ciężkich zadań numerycznych, takich jak obliczeniowa dynamika płynów lub obliczeniowa dynamika struktur, w których masz tablice z milionami, czasem dziesiątkami milionów elementów i iterujesz po nich w pętli z milionami kroków czasowych. Może dzisiaj std :: vector ma porównywalną wydajność, ale jakieś 15 lat temu valarray był prawie obowiązkowy, jeśli chciałeś napisać wydajne rozwiązanie numeryczne.
źródło