सी ++ वेलरेयर बनाम वेक्टर


159

मुझे वैक्टर बहुत पसंद हैं। वे निफ्टी और तेज हैं। लेकिन मुझे पता है कि इस बात को एक वैलेर्रे कहा जाता है। मैं एक वेक्टर के बजाय एक वैलेर का उपयोग क्यों करूंगा? मुझे पता है कि वैलेरेज़ में कुछ सिंटैक्टिक शुगर है, लेकिन इसके अलावा, वे कब उपयोगी हैं?


2
बस दूसरे दिन, यह भी विचार था। जहाँ तक मुझे पता है, यह वास्तव में विशेष गणित वेक्टर के रूप में है।
GMANNICKG

क्या वेलार्रे अभिव्यक्ति टेम्पलेट नहीं करते हैं?
मूविंग डक

भौतिक विज्ञानी उलरिच मुत्जे valarray यहां और यहां के
जीवनशैली

जवाबों:


70

वेलेरेज़ (मूल्य सरणियाँ) का उद्देश्य फोरट्रान की कुछ गति C ++ तक लाना है। आप पॉइंटर्स का एक बड़ा हिस्सा नहीं बना सकते हैं ताकि कंपाइलर कोड के बारे में धारणा बना सके और इसे बेहतर तरीके से ऑप्टिमाइज़ कर सके। (मुख्य कारण यह है कि फोरट्रान इतना तेज़ है कि कोई पॉइंटर प्रकार नहीं है, इसलिए कोई पॉइंटर एलियासिंग नहीं हो सकता है।)

वैलेरेज़ में भी कक्षाएं होती हैं जो आपको एक उचित तरीके से उन्हें स्लाइस करने की अनुमति देती हैं, हालांकि मानक का वह हिस्सा थोड़ा और काम कर सकता है। उनका आकार बदलना विनाशकारी है और उनके पास पुनरावृत्तियों की कमी है।

इसलिए, यदि यह संख्या है जिसके साथ आप काम कर रहे हैं और सुविधा सभी महत्वपूर्ण उपयोग वैलेरीज़ नहीं है। अन्यथा, वैक्टर अभी बहुत अधिक सुविधाजनक हैं।


11
वे संकेत से बचने के लिए डिज़ाइन नहीं किए गए हैं। सी ++ 11 परिभाषित करना शुरू () और अंत () वीरता में जो कि पुनरावृत्तियों को उनके पास लौटाते हैं
मोहम्मद अल-नकीब

3
@ user2023370: यही कारण है कि इतने सारे फोरट्रान उपयोगकर्ता फोरट्रान 77 को पसंद करते हैं। :)
माइकल

152

valarrayएक अनाथ की तरह है जो गलत समय पर गलत जगह पैदा हुआ था। यह अनुकूलन का एक प्रयास है, विशेष रूप से उन मशीनों के लिए जो भारी शुल्क वाले गणित के लिए उपयोग किए जाते थे, जब इसे लिखा गया था - विशेष रूप से, क्रैस जैसे वेक्टर प्रोसेसर।

एक वेक्टर प्रोसेसर के लिए, जो आप आम तौर पर करना चाहते थे, वह एक पूरे ऑपरेशन को एक पूरे ऐरे पर लागू करता है, फिर अगले ऑपरेशन को पूरे ऐरे पर लागू करता है, और इस तरह जब तक आप वह सब कुछ कर लेते हैं जो आपको करने की आवश्यकता होती है।

जब तक आप काफी छोटे सरणियों के साथ काम नहीं कर रहे हैं, हालांकि, यह कैशिंग के साथ खराब काम करता है। अधिकांश आधुनिक मशीनों पर, आप आमतौर पर क्या पसंद करेंगे (संभव हद तक) सरणी का हिस्सा लोड करना होगा, उस पर सभी ऑपरेशन करें जो आप करने जा रहे हैं, फिर सरणी के अगले भाग पर जाएं।

valarrayएलियासिंग की किसी भी संभावना को समाप्त करने के लिए भी माना जाता है, जो (कम से कम सैद्धांतिक रूप से) कंपाइलर को गति में सुधार करने देता है क्योंकि यह रजिस्टरों में मूल्यों को संग्रहीत करने के लिए अधिक स्वतंत्र है। हकीकत में, मैं बिल्कुल भी निश्चित नहीं हूं कि कोई भी वास्तविक कार्यान्वयन किसी भी महत्वपूर्ण डिग्री का लाभ उठाता है। मुझे संदेह है कि यह चिकन-और-अंडे की तरह की समस्या है - संकलक समर्थन के बिना यह लोकप्रिय नहीं हुआ, और जब तक यह लोकप्रिय नहीं है, किसी को भी इसका समर्थन करने के लिए अपने संकलक पर काम करने की परेशानी में नहीं जाना है।

वैलेयर के साथ उपयोग करने के लिए सहायक कक्षाओं का एक शानदार (सचमुच) सरणी भी है। आप प्राप्त slice, slice_array, gsliceऔर gslice_arrayएक के टुकड़े के साथ खेलने के लिए valarrayहै, और यह एक बहु-आयामी सरणी की तरह काम करते हैं। आपको mask_arrayएक ऑपरेशन "मास्क" करने के लिए भी मिलता है (उदाहरण के लिए x में y में आइटम जोड़ें, लेकिन केवल उन स्थानों पर जहां z गैर-शून्य है)। के तुच्छ उपयोग से अधिक बनाने के लिए valarray, आपको इन सहायक वर्गों के बारे में बहुत कुछ सीखना होगा, जिनमें से कुछ बहुत जटिल हैं और जिनमें से कोई भी (कम से कम मुझे) बहुत अच्छी तरह से प्रलेखित लगता है।

निचला रेखा: जबकि इसमें चमक के क्षण हैं, और कुछ चीजें बहुत करीने से कर सकते हैं, कुछ बहुत अच्छे कारण भी हैं कि यह (और लगभग निश्चित रूप से रहेगा) अस्पष्ट है।

संपादित करें (आठ साल बाद, 2017 में): पूर्ववर्ती में से कुछ कम से कम कुछ डिग्री तक अप्रचलित हो गए हैं। एक उदाहरण के लिए, इंटेल ने अपने संकलक के लिए वैलेरे का एक अनुकूलित संस्करण लागू किया है। यह प्रदर्शन को बेहतर बनाने के लिए इंटेल इंटीग्रेटेड परफॉर्मेंस प्राइमिटिव्स (Intel IPP) का उपयोग करता है। यद्यपि सटीक प्रदर्शन सुधार निस्संदेह बदलता है, सरल कोड के साथ एक त्वरित परीक्षण "मानक" के कार्यान्वयन के साथ संकलित समान कोड की तुलना में, 2: 1 की गति में सुधार दिखाता है valarray

इसलिए, जब मैं पूरी तरह से आश्वस्त नहीं हूं कि सी ++ प्रोग्रामर valarrayभारी संख्या में उपयोग करना शुरू कर देंगे , तो कम से कम कुछ परिस्थितियां हैं जिनमें यह एक गति सुधार प्रदान कर सकता है।


1
क्या यह विशेष रूप से वैलेयर के अंदर मनमानी वस्तु प्रकारों को संग्रहीत करने के लिए अस्वीकृत है?
user541686

6
@ मेहरदाद: हां - [न्यूमेरिक.प्रतिबंधों] पर प्रतिबंधों की एक (बल्कि लंबी) सूची है। केवल कुछ उदाहरणों के लिए, सभी अमूर्त वर्ग और अपवाद निषिद्ध हैं। यह भी (उदाहरण के लिए) प्रतिलिपि निर्माण और असाइनमेंट के बाद डिफ़ॉल्ट निर्माण के अनुक्रम के बीच तुल्यता की आवश्यकता है।
जेरी कॉफिन

@JerryCoffin शीश कि डरावना है। हम वादा करते हैं कि हम इसका इस्तेमाल नहीं करेंगे।
हानी गोक

4
मैं यह तय नहीं करूंगा कि डर पर आधारित है। मैं इसे इस आधार पर तय करूंगा कि आपको उन तत्वों को संग्रहीत करने की आवश्यकता है जो इसका उपयोग करने वाली सुविधाओं का उपयोग करते हैं।
जेरी कॉफिन 20

3
@annoying_squid: यदि आपके पास जोड़ने के लिए अधिक विशिष्ट और (आप विश्वास करते हैं) सटीक जानकारी है, तो कृपया इसका उत्तर देने के लिए स्वतंत्र महसूस करें। जैसा कि यह अभी खड़ा है, आपकी टिप्पणी किसी भी उपयोगी जानकारी को जोड़ने के लिए प्रतीत नहीं होती है।
जेरी कॉफिन

39

C ++ 98 के मानकीकरण के दौरान, वैलेरे को कुछ प्रकार के तेज़ गणितीय संगणनाओं की अनुमति देने के लिए डिज़ाइन किया गया था। हालाँकि, उस समय के आसपास टॉड वेल्डहुइज़न ने एक्सप्रेशन टेम्प्लेट का आविष्कार किया और ब्लिट्ज ++ बनाया , और इसी तरह के टेम्प्लेट-मेटा तकनीक का आविष्कार किया गया था, जो मानक से पहले भी जारी होने से पहले वैलेरीज़ को बहुत अप्रचलित बना देता था। IIRC, वेलर्रे के मूल प्रस्तावक (ओं) ने इसे मानकीकरण में आधा छोड़ दिया, जो (यदि सच है) ने भी इसकी मदद नहीं की।

ISTR कि मुख्य कारण इसे मानक से नहीं हटाया गया था, किसी ने भी इस मुद्दे का पूरी तरह से मूल्यांकन करने और इसे हटाने के लिए प्रस्ताव लिखने के लिए समय नहीं लिया।

हालाँकि, कृपया ध्यान रखें कि यह सब अस्पष्ट याद दिलाना है। नमक के एक दाने के साथ इसे लें और आशा करें कि कोई इसे ठीक करता है या पुष्टि करता है।


अभिव्यक्ति के टेम्पलेट्स को समान रूप से वंदेवोर्डे को भी श्रेय दिया जा सकता है, है ना?
निकोस अथानासीउ

@ निकोस: ऐसा नहीं है कि मुझे पता है। मुझसे गलती भी हो सकती है। आपके पास उस पढ़ने के पक्ष में क्या है?
sbi

1
इसका उल्लेख "सी ++ टेम्प्लेट्स - द कम्प्लीट गाइड" पुस्तक में किया गया है, मुझे लगता है कि यह आमतौर पर स्वीकार किया जाता है कि उन दोनों ने स्वतंत्र रूप से आविष्कार किया था ।
निकोस अथानासीउ

27

मुझे पता है कि वैलेरेज़ में कुछ सिंटैक्टिक शुगर होती है

मुझे कहना है कि मुझे नहीं लगता कि std::valarraysसिंटैक्टिक शुगर के रास्ते में बहुत कुछ है। वाक्यविन्यास अलग है, लेकिन मैं अंतर को "चीनी" नहीं कहूंगा। एपीआई अजीब है। C ++ प्रोग्रामिंग लैंग्वेजstd::valarray में s पर दिए गए खंड में इस असामान्य API और इस तथ्य का उल्लेख किया गया है कि, चूंकि s को अत्यधिक अनुकूलित होने की उम्मीद है, इसलिए इनका उपयोग करते समय आपको मिलने वाले किसी भी त्रुटि संदेश संभवतः गैर-सहज होंगे।std::valarray

जिज्ञासा से बाहर, के बारे में एक साल पहले मैं std::valarrayखिलाफ खड़ा था std::vector। मेरे पास अब कोड या सटीक परिणाम नहीं हैं (हालांकि इसे खुद लिखना मुश्किल नहीं होना चाहिए)। जीसीसी मैं का उपयोग किया था का उपयोग करते समय एक छोटे से प्रदर्शन लाभ मिलेगा std::valarrayसरल गणित के लिए हूं, लेकिन अपने कार्यान्वयन मानक विचलन की गणना करने के लिए (और, ज़ाहिर है, मानक विचलन है कि जटिल नहीं, जहाँ तक गणित चला जाता है के रूप में)। मुझे संदेह है कि बड़े पैमाने पर प्रत्येक आइटम std::vectorपर ऑपरेशन, कैश ऑन ऑपरेशन से बेहतर है std::valarray( नोट , musiphil से सलाह के बाद , मैं लगभग समान प्रदर्शन पाने में कामयाब रहा हूं ) 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; वे दोनों अपने तत्वों के लिए स्मृति के एक एकल सन्निहित ब्लॉक आवंटित करते हैं।
मुसीफिल

1
@musiphil मेरी प्रतिक्रिया एक टिप्पणी के लिए बहुत लंबी है, इसलिए मैंने जवाब अपडेट कर दिया है।
मैक्स लिबर्ट रॉबर्ट

1
valarrayऊपर आपके उदाहरण के लिए, आपको एक temp valarrayऑब्जेक्ट का निर्माण नहीं करना था , लेकिन आप बस कर सकते थे std::valarray<double> differences_from_mean = original_values - mean;, और फिर कैश व्यवहार vectorउदाहरण के समान होना चाहिए । (वैसे, यदि meanआप वास्तव में हैं int, नहीं double, तो आपको इसकी आवश्यकता हो सकती है static_cast<double>(mean)।)
मसिफिल

सफाई के सुझाव के लिए धन्यवाद valarray। मुझे यह देखने की आवश्यकता होगी कि क्या प्रदर्शन में सुधार होता है। जैसा कि meanहोने के लिए int: यह एक गलती थी। मैंने मूल रूप से ints का उपयोग करके उदाहरण लिखा था , और तब महसूस किया कि meanतब ट्रंकेशन के कारण वास्तविक अर्थ से बहुत दूर होगा। लेकिन मैं अपने पहले दौर के संपादन में कुछ आवश्यक बदलाव करने से चूक गया।
मैक्स लाइबबर्ट

@ मुसिफिल आप सही कह रहे हैं; उस परिवर्तन ने लगभग समान प्रदर्शन के लिए नमूना कोड लाया।
23:27 पर मैक्स लिबर्ट रॉबर्ट

23

वैलेर को कुछ फोरट्रान वेक्टर-प्रोसेसिंग अच्छाई को C ++ पर रगड़ने देना चाहिए था। किसी भी तरह आवश्यक संकलक समर्थन वास्तव में कभी नहीं हुआ।

जोसुटिस की किताबों में वेलार्रे ( यहां और यहां ) पर कुछ दिलचस्प (कुछ हद तक निराशाजनक) टिप्पणी शामिल है ।

हालाँकि, इंटेल अब अपने हालिया संकलक रिलीज (उदाहरण 9 स्लाइड देखें ) में वैलेरी को फिर से देख रहा है ; यह एक दिलचस्प विकास है कि उनके 4-वे SIMD SSE इंस्ट्रक्शन सेट को 8-वे AVX और 16-वे लार्बी निर्देशों द्वारा शामिल किया जाने वाला है और पोर्टेबिलिटी के हितों में इसे अमूर्त के साथ कोड करना बेहतर होगा। (कहना) आंतरिक से अधिक वैलेरी।


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()

2
मेरे पास वास्तव में ठीक वैसा ही विचार था जैसा आपने तब किया था जब मुझे काम पर आज वैलेर के बारे में पता चला था। मुझे लगता है कि अब से c ++ में मैथ्स प्रोसेसिंग प्रॉब्लम्स के लिए मैं वैलेर्रे का इस्तेमाल करूंगा क्योंकि कोड मैथ के नजरिए से स्टैंड के तहत सरल लगता है।
ज़ाचरी क्रूस

8

C ++ 11 मानक कहता है:

वैलेयर सरणी वर्गों को अलियासिंग के कुछ रूपों से मुक्त होने के लिए परिभाषित किया गया है, इस प्रकार इन वर्गों पर संचालन को अनुकूलित करने की अनुमति मिलती है।

C ++ 11 26.6.1-2 देखें।


चूंकि मुझे लगता है कि मानक किन रूपों को परिभाषित करता है, क्या आप उन्हें उद्धृत कर सकते हैं? इसके अलावा, क्या इन्हें कोडिंग ट्रिक्स का उपयोग करके लागू किया जाता है, या क्या ये भाषा में कहीं और नियमों का पालन करने के लिए कंपाइलर-आधारित अपवाद हैं?
अंडरस्कोर_ड

2

साथ std::valarrayआप की तरह मानक गणितीय संकेतन का उपयोग कर सकते v1 = a*v2 + v3बॉक्स से बाहर। यह वैक्टर के साथ संभव नहीं है जब तक कि आप अपने स्वयं के ऑपरेटरों को परिभाषित न करें।


0

std :: valarray भारी संख्यात्मक कार्यों के लिए अभिप्रेत है, जैसे कम्प्यूटेशनल फ़्लूइड डायनामिक्स या कम्प्यूटेशनल स्ट्रक्चर डायनेमिक्स, जिसमें आपने लाखों, कभी-कभी दसियों लाख आइटमों के साथ सरणियाँ ली हैं, और आप उन पर एक लूप में लाखों टाइमस्टेप के साथ पुनरावृति करते हैं। शायद आज std :: वेक्टर का तुलनात्मक प्रदर्शन है, लेकिन कुछ 15 साल पहले, वैलेर्रे लगभग अनिवार्य था यदि आप एक कुशल संख्यात्मक सॉल्वर लिखना चाहते थे।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.