मुझे वैक्टर बहुत पसंद हैं। वे निफ्टी और तेज हैं। लेकिन मुझे पता है कि इस बात को एक वैलेर्रे कहा जाता है। मैं एक वेक्टर के बजाय एक वैलेर का उपयोग क्यों करूंगा? मुझे पता है कि वैलेरेज़ में कुछ सिंटैक्टिक शुगर है, लेकिन इसके अलावा, वे कब उपयोगी हैं?
मुझे वैक्टर बहुत पसंद हैं। वे निफ्टी और तेज हैं। लेकिन मुझे पता है कि इस बात को एक वैलेर्रे कहा जाता है। मैं एक वेक्टर के बजाय एक वैलेर का उपयोग क्यों करूंगा? मुझे पता है कि वैलेरेज़ में कुछ सिंटैक्टिक शुगर है, लेकिन इसके अलावा, वे कब उपयोगी हैं?
जवाबों:
वेलेरेज़ (मूल्य सरणियाँ) का उद्देश्य फोरट्रान की कुछ गति C ++ तक लाना है। आप पॉइंटर्स का एक बड़ा हिस्सा नहीं बना सकते हैं ताकि कंपाइलर कोड के बारे में धारणा बना सके और इसे बेहतर तरीके से ऑप्टिमाइज़ कर सके। (मुख्य कारण यह है कि फोरट्रान इतना तेज़ है कि कोई पॉइंटर प्रकार नहीं है, इसलिए कोई पॉइंटर एलियासिंग नहीं हो सकता है।)
वैलेरेज़ में भी कक्षाएं होती हैं जो आपको एक उचित तरीके से उन्हें स्लाइस करने की अनुमति देती हैं, हालांकि मानक का वह हिस्सा थोड़ा और काम कर सकता है। उनका आकार बदलना विनाशकारी है और उनके पास पुनरावृत्तियों की कमी है।
इसलिए, यदि यह संख्या है जिसके साथ आप काम कर रहे हैं और सुविधा सभी महत्वपूर्ण उपयोग वैलेरीज़ नहीं है। अन्यथा, वैक्टर अभी बहुत अधिक सुविधाजनक हैं।
valarray
एक अनाथ की तरह है जो गलत समय पर गलत जगह पैदा हुआ था। यह अनुकूलन का एक प्रयास है, विशेष रूप से उन मशीनों के लिए जो भारी शुल्क वाले गणित के लिए उपयोग किए जाते थे, जब इसे लिखा गया था - विशेष रूप से, क्रैस जैसे वेक्टर प्रोसेसर।
एक वेक्टर प्रोसेसर के लिए, जो आप आम तौर पर करना चाहते थे, वह एक पूरे ऑपरेशन को एक पूरे ऐरे पर लागू करता है, फिर अगले ऑपरेशन को पूरे ऐरे पर लागू करता है, और इस तरह जब तक आप वह सब कुछ कर लेते हैं जो आपको करने की आवश्यकता होती है।
जब तक आप काफी छोटे सरणियों के साथ काम नहीं कर रहे हैं, हालांकि, यह कैशिंग के साथ खराब काम करता है। अधिकांश आधुनिक मशीनों पर, आप आमतौर पर क्या पसंद करेंगे (संभव हद तक) सरणी का हिस्सा लोड करना होगा, उस पर सभी ऑपरेशन करें जो आप करने जा रहे हैं, फिर सरणी के अगले भाग पर जाएं।
valarray
एलियासिंग की किसी भी संभावना को समाप्त करने के लिए भी माना जाता है, जो (कम से कम सैद्धांतिक रूप से) कंपाइलर को गति में सुधार करने देता है क्योंकि यह रजिस्टरों में मूल्यों को संग्रहीत करने के लिए अधिक स्वतंत्र है। हकीकत में, मैं बिल्कुल भी निश्चित नहीं हूं कि कोई भी वास्तविक कार्यान्वयन किसी भी महत्वपूर्ण डिग्री का लाभ उठाता है। मुझे संदेह है कि यह चिकन-और-अंडे की तरह की समस्या है - संकलक समर्थन के बिना यह लोकप्रिय नहीं हुआ, और जब तक यह लोकप्रिय नहीं है, किसी को भी इसका समर्थन करने के लिए अपने संकलक पर काम करने की परेशानी में नहीं जाना है।
वैलेयर के साथ उपयोग करने के लिए सहायक कक्षाओं का एक शानदार (सचमुच) सरणी भी है। आप प्राप्त slice
, slice_array
, gslice
और gslice_array
एक के टुकड़े के साथ खेलने के लिए valarray
है, और यह एक बहु-आयामी सरणी की तरह काम करते हैं। आपको mask_array
एक ऑपरेशन "मास्क" करने के लिए भी मिलता है (उदाहरण के लिए x में y में आइटम जोड़ें, लेकिन केवल उन स्थानों पर जहां z गैर-शून्य है)। के तुच्छ उपयोग से अधिक बनाने के लिए valarray
, आपको इन सहायक वर्गों के बारे में बहुत कुछ सीखना होगा, जिनमें से कुछ बहुत जटिल हैं और जिनमें से कोई भी (कम से कम मुझे) बहुत अच्छी तरह से प्रलेखित लगता है।
निचला रेखा: जबकि इसमें चमक के क्षण हैं, और कुछ चीजें बहुत करीने से कर सकते हैं, कुछ बहुत अच्छे कारण भी हैं कि यह (और लगभग निश्चित रूप से रहेगा) अस्पष्ट है।
संपादित करें (आठ साल बाद, 2017 में): पूर्ववर्ती में से कुछ कम से कम कुछ डिग्री तक अप्रचलित हो गए हैं। एक उदाहरण के लिए, इंटेल ने अपने संकलक के लिए वैलेरे का एक अनुकूलित संस्करण लागू किया है। यह प्रदर्शन को बेहतर बनाने के लिए इंटेल इंटीग्रेटेड परफॉर्मेंस प्राइमिटिव्स (Intel IPP) का उपयोग करता है। यद्यपि सटीक प्रदर्शन सुधार निस्संदेह बदलता है, सरल कोड के साथ एक त्वरित परीक्षण "मानक" के कार्यान्वयन के साथ संकलित समान कोड की तुलना में, 2: 1 की गति में सुधार दिखाता है valarray
।
इसलिए, जब मैं पूरी तरह से आश्वस्त नहीं हूं कि सी ++ प्रोग्रामर valarray
भारी संख्या में उपयोग करना शुरू कर देंगे , तो कम से कम कुछ परिस्थितियां हैं जिनमें यह एक गति सुधार प्रदान कर सकता है।
C ++ 98 के मानकीकरण के दौरान, वैलेरे को कुछ प्रकार के तेज़ गणितीय संगणनाओं की अनुमति देने के लिए डिज़ाइन किया गया था। हालाँकि, उस समय के आसपास टॉड वेल्डहुइज़न ने एक्सप्रेशन टेम्प्लेट का आविष्कार किया और ब्लिट्ज ++ बनाया , और इसी तरह के टेम्प्लेट-मेटा तकनीक का आविष्कार किया गया था, जो मानक से पहले भी जारी होने से पहले वैलेरीज़ को बहुत अप्रचलित बना देता था। IIRC, वेलर्रे के मूल प्रस्तावक (ओं) ने इसे मानकीकरण में आधा छोड़ दिया, जो (यदि सच है) ने भी इसकी मदद नहीं की।
ISTR कि मुख्य कारण इसे मानक से नहीं हटाया गया था, किसी ने भी इस मुद्दे का पूरी तरह से मूल्यांकन करने और इसे हटाने के लिए प्रस्ताव लिखने के लिए समय नहीं लिया।
हालाँकि, कृपया ध्यान रखें कि यह सब अस्पष्ट याद दिलाना है। नमक के एक दाने के साथ इसे लें और आशा करें कि कोई इसे ठीक करता है या पुष्टि करता है।
मुझे पता है कि वैलेरेज़ में कुछ सिंटैक्टिक शुगर होती है
मुझे कहना है कि मुझे नहीं लगता कि std::valarrays
सिंटैक्टिक शुगर के रास्ते में बहुत कुछ है। वाक्यविन्यास अलग है, लेकिन मैं अंतर को "चीनी" नहीं कहूंगा। एपीआई अजीब है। C ++ प्रोग्रामिंग लैंग्वेजstd::valarray
में s पर दिए गए खंड में इस असामान्य API और इस तथ्य का उल्लेख किया गया है कि, चूंकि s को अत्यधिक अनुकूलित होने की उम्मीद है, इसलिए इनका उपयोग करते समय आपको मिलने वाले किसी भी त्रुटि संदेश संभवतः गैर-सहज होंगे।std::valarray
जिज्ञासा से बाहर, के बारे में एक साल पहले मैं std::valarray
खिलाफ खड़ा था std::vector
। मेरे पास अब कोड या सटीक परिणाम नहीं हैं (हालांकि इसे खुद लिखना मुश्किल नहीं होना चाहिए)। जीसीसी मैं का उपयोग किया था का उपयोग करते समय एक छोटे से प्रदर्शन लाभ मिलेगा std::valarray
सरल गणित के लिए हूं, लेकिन अपने कार्यान्वयन मानक विचलन की गणना करने के लिए (और, ज़ाहिर है, मानक विचलन है कि जटिल नहीं, जहाँ तक गणित चला जाता है के रूप में)। मुझे संदेह है कि बड़े पैमाने पर प्रत्येक आइटम ( नोट , musiphil से सलाह के बाद , मैं लगभग समान प्रदर्शन पाने में कामयाब रहा हूं ) std::vector
पर ऑपरेशन, कैश ऑन ऑपरेशन से बेहतर है std::valarray
। vector
और valarray
।
अंत में, मैंने std::vector
मेमोरी आवंटन और अस्थायी ऑब्जेक्ट निर्माण जैसी चीजों पर करीब ध्यान देते हुए उपयोग करने का निर्णय लिया ।
दोनों std::vector
और std::valarray
एक सन्निहित ब्लॉक में डेटा स्टोर। हालाँकि, वे अलग-अलग पैटर्न का उपयोग करके उस डेटा तक पहुँचते हैं, और इससे भी महत्वपूर्ण बात, एपीआई के लिए एपीआई की 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
। अब पांच साल से अधिक हो गए हैं।
के लिए 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 लंबोदर का लाभ उठाऊंगा।
यह स्पष्ट है कि कोड के ये दो स्निपेट अलग-अलग काम करते हैं। एक के लिए, std::vector
उदाहरण एक मध्यवर्ती संग्रह नहीं बनाता है जैसे कि std::valarray
उदाहरण करता है। हालाँकि, मुझे लगता है कि उनकी तुलना करना उचित है क्योंकि अंतर std::vector
और के बीच के अंतर से बंधे हैं std::valarray
।
जब मैंने यह उत्तर लिखा था, मुझे संदेह था कि दो std::valarray
एस ( 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
उदाहरण के रूप में एक ही बात करता है , और लगभग समान प्रदर्शन है। अंत में, सवाल यह है कि आप किस एपीआई को पसंद करते हैं।
std::vector
बजाय कैश के साथ बेहतर खेलेंगे std::valarray
; वे दोनों अपने तत्वों के लिए स्मृति के एक एकल सन्निहित ब्लॉक आवंटित करते हैं।
valarray
ऊपर आपके उदाहरण के लिए, आपको एक temp
valarray
ऑब्जेक्ट का निर्माण नहीं करना था , लेकिन आप बस कर सकते थे std::valarray<double> differences_from_mean = original_values - mean;
, और फिर कैश व्यवहार vector
उदाहरण के समान होना चाहिए । (वैसे, यदि mean
आप वास्तव में हैं int
, नहीं double
, तो आपको इसकी आवश्यकता हो सकती है static_cast<double>(mean)
।)
valarray
। मुझे यह देखने की आवश्यकता होगी कि क्या प्रदर्शन में सुधार होता है। जैसा कि mean
होने के लिए int
: यह एक गलती थी। मैंने मूल रूप से int
s का उपयोग करके उदाहरण लिखा था , और तब महसूस किया कि mean
तब ट्रंकेशन के कारण वास्तविक अर्थ से बहुत दूर होगा। लेकिन मैं अपने पहले दौर के संपादन में कुछ आवश्यक बदलाव करने से चूक गया।
वैलेर को कुछ फोरट्रान वेक्टर-प्रोसेसिंग अच्छाई को C ++ पर रगड़ने देना चाहिए था। किसी भी तरह आवश्यक संकलक समर्थन वास्तव में कभी नहीं हुआ।
जोसुटिस की किताबों में वेलार्रे ( यहां और यहां ) पर कुछ दिलचस्प (कुछ हद तक निराशाजनक) टिप्पणी शामिल है ।
हालाँकि, इंटेल अब अपने हालिया संकलक रिलीज (उदाहरण 9 स्लाइड देखें ) में वैलेरी को फिर से देख रहा है ; यह एक दिलचस्प विकास है कि उनके 4-वे SIMD SSE इंस्ट्रक्शन सेट को 8-वे AVX और 16-वे लार्बी निर्देशों द्वारा शामिल किया जाने वाला है और पोर्टेबिलिटी के हितों में इसे अमूर्त के साथ कोड करना बेहतर होगा। (कहना) आंतरिक से अधिक वैलेरी।
मुझे वैलेरे के लिए एक अच्छा उपयोग मिला। यह बिल्कुल वैराग्य की तरह वैलेरे का उपयोग करना है।
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<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;
}
इसके अलावा, हमें अजगर स्क्रिप्ट की आवश्यकता है।
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()
C ++ 11 मानक कहता है:
वैलेयर सरणी वर्गों को अलियासिंग के कुछ रूपों से मुक्त होने के लिए परिभाषित किया गया है, इस प्रकार इन वर्गों पर संचालन को अनुकूलित करने की अनुमति मिलती है।
C ++ 11 26.6.1-2 देखें।
साथ std::valarray
आप की तरह मानक गणितीय संकेतन का उपयोग कर सकते v1 = a*v2 + v3
बॉक्स से बाहर। यह वैक्टर के साथ संभव नहीं है जब तक कि आप अपने स्वयं के ऑपरेटरों को परिभाषित न करें।
std :: valarray भारी संख्यात्मक कार्यों के लिए अभिप्रेत है, जैसे कम्प्यूटेशनल फ़्लूइड डायनामिक्स या कम्प्यूटेशनल स्ट्रक्चर डायनेमिक्स, जिसमें आपने लाखों, कभी-कभी दसियों लाख आइटमों के साथ सरणियाँ ली हैं, और आप उन पर एक लूप में लाखों टाइमस्टेप के साथ पुनरावृति करते हैं। शायद आज std :: वेक्टर का तुलनात्मक प्रदर्शन है, लेकिन कुछ 15 साल पहले, वैलेर्रे लगभग अनिवार्य था यदि आप एक कुशल संख्यात्मक सॉल्वर लिखना चाहते थे।