आदेशित संख्याओं का कुशल स्थिर योग


12

मेरे पास फ्लोटिंग पॉइंट पॉजिटिव नंबर ( std::vector<float>, आकार ~ 1000) की काफी लंबी सूची है । क्रम घटने में क्रमबद्ध होते हैं। यदि मैं उन्हें इस आदेश का पालन करता हूं:

for (auto v : vec) { sum += v; }

मुझे लगता है कि मुझे कुछ संख्यात्मक स्थिरता की समस्या हो सकती है, क्योंकि वेक्टर के अंत के करीब की sumतुलना में बहुत बड़ा होगा v। सबसे आसान उपाय यह होगा कि वेक्टर को उल्टे क्रम में पार किया जाए। मेरा प्रश्न है: क्या यह कुशल और साथ ही आगे का मामला है? मेरे पास अधिक कैश गायब होगा?

क्या कोई और स्मार्ट समाधान है?


1
गति प्रश्न का उत्तर देना आसान है। बेंचमार्क इसे।
डेविड स्पैत्रो

क्या सटीकता की तुलना में गति अधिक महत्वपूर्ण है?
स्टार्क

काफी डुप्लिकेट नहीं है, लेकिन बहुत समान प्रश्न: फ्लोट का उपयोग करके श्रृंखला का योग
acraig5075

4
आपको नकारात्मक संख्याओं पर ध्यान देना पड़ सकता है।
एपीग्रामग्राम

3
यदि आप वास्तव में उच्च डिग्री की शुद्धता के बारे में परवाह करते हैं, तो कहन योग की जाँच करें ।
मैक्स लैंगहॉफ

जवाबों:


3

मुझे लगता है कि मुझे कुछ संख्यात्मक स्थिरता की समस्या हो सकती है

इसलिए इसके लिए परीक्षण करें। वर्तमान में आपको एक काल्पनिक समस्या है, जो कहना है, कोई समस्या नहीं है।

यदि आप परीक्षण करते हैं, और काल्पनिक एक वास्तविक समस्या में बदल जाता है, तो आपको वास्तव में इसे ठीक करने के बारे में चिंता करनी चाहिए।

वह है - फ्लोटिंग-पॉइंट प्रिसिजन से समस्याएँ पैदा हो सकती हैं, लेकिन आप पुष्टि कर सकते हैं कि क्या यह आपके डेटा के लिए वास्तव में करता है, इससे पहले कि सब कुछ खत्म हो जाए।

... मेरे पास अधिक कैश गायब होगा?

एक हजार फ्लोट्स 4Kb है - यह एक आधुनिक मास-मार्केट सिस्टम पर कैश में फिट होगा (यदि आपके पास कोई अन्य प्लेटफॉर्म है, तो हमें बताएं कि यह क्या है)।

केवल जोखिम यह है कि पूर्ववर्ती आपको पीछे की ओर पुनरावृत्त करते समय मदद नहीं करेगा, लेकिन निश्चित रूप से आपका वेक्टर पहले से ही कैश में हो सकता है। जब तक आप अपने पूरे कार्यक्रम के संदर्भ में प्रोफाइल नहीं बनाते, तब तक आप वास्तव में इसका निर्धारण नहीं कर सकते, इसलिए जब तक आपके पास एक पूर्ण कार्यक्रम न हो, तब तक इसके बारे में चिंता करने का कोई फायदा नहीं है।

क्या कोई और स्मार्ट समाधान है?

उन चीजों के बारे में चिंता न करें जो समस्याएँ बन सकती हैं, जब तक कि वे वास्तव में समस्याएँ न बन जाएँ। अधिक से अधिक यह संभव मुद्दों पर ध्यान देने योग्य है, और आपके कोड को संरचित करता है ताकि आप सरलतम संभव समाधान को एक सावधानी से अनुकूलित बाद में बदल सकें, बाकी सब कुछ फिर से लिखे बिना।


5

मैंने आपके उपयोग के मामले को चिह्नित किया है और परिणाम (संलग्न छवि देखें) उस दिशा की ओर इशारा करते हैं जो आगे या पीछे लूप के लिए कोई प्रदर्शन अंतर नहीं करता है।

आप अपने हार्डवेयर + कंपाइलर को भी माप सकते हैं।


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

रिवर्स संचय के लिए निम्नलिखित का उपयोग करें:

std::accumulate(rbegin(data), rend(data), 0.0f);

आगे संचय के लिए:

std::accumulate(begin(data), end(data), 0.0f);

यहां छवि विवरण दर्ज करें


वह वेबसाइट सुपर कूल है। बस यह सुनिश्चित करने के लिए: आप यादृच्छिक पीढ़ी का समय नहीं ले रहे हैं, है ना?
रग्गरो तुर्रा

नहीं, केवल stateलूप का हिस्सा समयबद्ध है।
डेविड स्पैत्रो

2

सबसे आसान उपाय यह होगा कि वेक्टर को उल्टे क्रम में पार किया जाए। मेरा प्रश्न है: क्या यह कुशल और साथ ही आगे का मामला है? मेरे पास अधिक कैश गायब होगा?

हाँ यह कुशल है। आपके हार्डवेयर से शाखा की भविष्यवाणी और स्मार्ट कैश रणनीति अनुक्रमिक पहुंच के लिए तैयार है। आप अपने वेक्टर को सुरक्षित रूप से संचित कर सकते हैं:

#include <numeric>

auto const sum = std::accumulate(crbegin(v), crend(v), 0.f);

2
क्या आप स्पष्ट कर सकते हैं: इस संदर्भ में "अनुक्रमिक पहुंच" का अर्थ है आगे, पीछे, या दोनों?
रग्गरो तुर्रा

1
@RuggeroTurra मैं तब तक नहीं कर सकता जब तक मुझे कोई स्रोत नहीं मिल सकता है, और मैं अभी सीपीयू डेटाशीट पढ़ने के मूड में नहीं हूं।
YSC

@RuggeroTurra आमतौर पर अनुक्रमिक पहुंच का मतलब होता है। सभी अर्ध-सभ्य मेमोरी प्रीफैचर्स आगे अनुक्रमिक पहुंच को पकड़ते हैं।
टूथब्रश

@Toothbrush, धन्यवाद। तो, अगर मैं पीछे की ओर, सिद्धांत रूप में, यह एक प्रदर्शन मुद्दा हो सकता है
रग्गरो तुर्रा

सिद्धांत रूप में, कम से कम कुछ हार्डवेयर पर, यदि पूरा वेक्टर पहले से ही एल 1 कैश में नहीं है ।
बेकार

2

इस प्रयोजन के लिए आप बिना किसी ट्रांसपोज़िशन के रिवर्स इटरेटर का उपयोग कर सकते हैं std::vector<float> vec:

float sum{0.f};
for (auto rIt = vec.rbegin(); rIt!= vec.rend(); ++rIt)
{
    sum += *rit;
}

या मानक algortithm का उपयोग करके समान कार्य करें:

float sum = std::accumulate(vec.crbegin(), vec.crend(), 0.f);

प्रदर्शन समान होना चाहिए, आपके वेक्टर की केवल बाईपास दिशा बदल गई है


अगर मैं गलत हूं तो मुझे सुधारें, लेकिन मुझे लगता है कि यह ओपीच स्टेटमेंट का उपयोग करने से भी अधिक कुशल है, क्योंकि यह एक ओवरहेड का परिचय देता है। YSC संख्यात्मक स्थिरता भाग, थियो के बारे में सही है।
सेफरथोथ

4
@sephiroth नहीं, कोई भी आधा-सभ्य संकलक वास्तव में परवाह नहीं करेगा कि आपने एक श्रेणी के लिए लिखा है या इसके लिए एक पुनरावृत्त।
मैक्स लैंगहॉफ

1
कैश / प्रीफ़ैचिंग के कारण वास्तविक दुनिया के प्रदर्शन का निश्चित रूप से समान होने की गारंटी नहीं है। ओपी के लिए उस से सावधान रहना उचित है।
मैक्स लैंगहॉफ

1

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

यदि आप उच्च सटीकता चाहते हैं, तो काहन योग पर विचार करें - यह त्रुटि क्षतिपूर्ति के लिए एक अतिरिक्त फ्लोट का उपयोग करता है। वहाँ भीजोड़ीदार योग

सटीकता और समय के बीच ट्रेडऑफ़ के विस्तृत विश्लेषण के लिए, इस लेख को देखें

C ++ 17 के लिए अद्यतन:

कुछ अन्य उत्तर का उल्लेख है std::accumulate। C ++ 17 के बाद से निष्पादन नीतियां हैं जो एल्गोरिदम को समानांतर करने की अनुमति देती हैं।

उदाहरण के लिए

#include <vector>
#include <execution>
#include <iostream>
#include <numeric>

int main()
{  
   std::vector<double> input{0.1, 0.9, 0.2, 0.8, 0.3, 0.7, 0.4, 0.6, 0.5};

   double reduceResult = std::reduce(std::execution::par, std::begin(input), std::end(input));

   std:: cout << "reduceResult " << reduceResult << '\n';
}

यह बड़े डेटासेट को तेज़ी से nondeterministic गोलाई त्रुटियों की कीमत पर बनाना चाहिए (मैं मान रहा हूं कि उपयोगकर्ता थ्रेड विभाजन को निर्धारित करने में सक्षम नहीं होगा)।

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