2012-03-08 19 views
11

मैं एक सिमुलेशन प्रोग्राम लिख रहा हूं जो अलग-अलग चरणों में आगे बढ़ता है। अनुकरण में कई नोड्स होते हैं, जिनमें से प्रत्येक के साथ एक फ्लोटिंग-पॉइंट मान होता है जिसे प्रत्येक चरण पर फिर से गणना की जाती है। नतीजा सकारात्मक, नकारात्मक या शून्य हो सकता है।फ्लोट्स का उपयोग करते समय मैं लगातार प्रोग्राम व्यवहार कैसे प्राप्त कर सकता हूं?

उस स्थिति में जहां परिणाम शून्य या उससे कम होता है। अभी तक यह स्पष्ट लगता है - मैं तो बस प्रत्येक नोड के लिए कुछ इस तरह कर सकते हैं:

if (value <= 0.0f) something_happens(); 

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

float f1 = 0.000001f, f2 = 0.000002f; 
f1 += 0.000004f; // This part happens first here 
f1 += (f2 * 0.000003f); 
printf("%.16f\n", f1); 

f1 = 0.000001f, f2 = 0.000002f; 
f1 += (f2 * 0.000003f); 
f1 += 0.000004f; // This time this happens second 
printf("%.16f\n", f1); 

इस कार्यक्रम का उत्पादन

0.0000050000057854 
0.0000050000062402 

है भले ही इसके विनिमेय इसलिए दोनों परिणाम एक ही होना चाहिए है:

यहाँ एक सरल उदाहरण कार्यक्रम है कि घटना को दर्शाता है मैं वर्णन कर रहा हूँ है । नोट: मैं पूरी तरह से समझता हूं कि यह क्यों हो रहा है - यह मुद्दा नहीं है। समस्या यह है कि इन भिन्नताओं का अर्थ यह हो सकता है कि कभी-कभी एक मान जो चरण एन पर नकारात्मक हो जाता है, कुछ_happens() को ट्रिगर करता है, अब पहले या बाद में एक या दो नकारात्मक नकारात्मक हो सकता है, जो समग्र सिमुलेशन परिणामों को बहुत अलग कर सकता है क्योंकि something_happens() का एक बड़ा प्रभाव है।

मैं क्या जानना चाहता हूं कि यह तय करने का एक अच्छा तरीका है कि कुछ_happens() को ट्रिगर किया जाना चाहिए जो गणना परिणामों में छोटे बदलावों से प्रभावित नहीं होगा, जो व्यवहार को पुन: क्रमबद्ध करने के परिणामस्वरूप होते हैं ताकि व्यवहार मेरे कार्यक्रम के नए संस्करणों के पुराने संस्करणों के अनुरूप होगा।

एकमात्र समाधान मैं अब तक के बारे में सोच कर लिया है इस तरह की कुछ मूल्य एप्सिलॉन उपयोग करने के लिए है:

if (value < epsilon) something_happens(); 

लेकिन क्योंकि परिणामों में छोटे बदलाव के समय के साथ जमा मैं एप्सिलॉन काफी बनाने की जरूरत है बड़े (अपेक्षाकृत बोलते हुए) यह सुनिश्चित करने के लिए कि विविधताएं किसी भिन्न चरण पर ट्रिगर होने पर कुछ_happens() नतीजे न हों। क्या कोई बेहतर तरीका है?

मैंने this excellent article को फ़्लोटिंग पॉइंट तुलना पर पढ़ा है, लेकिन मुझे नहीं लगता कि वर्णित तुलनात्मक तरीकों में से कोई भी इस स्थिति में मेरी मदद कर सकता है।

नोट: इसके बजाय पूर्णांक मानों का उपयोग करना एक विकल्प नहीं है।


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

+4

यदि छोटे बदलावों में आउटपुट में बड़े बदलाव आते हैं, तो क्या यह सिर्फ आपको नहीं बता रहा है कि आपके परिणामों की कम सटीकता है? (इसके अलावा: क्यों नहीं तैरना डबल?) –

+3

सावधान रहें: 'printf ("%। 16f \ n ", f1); 'यह एक अप्रत्याशित साइड इफेक्ट है: यह आपकी फ्लोट को डबल महत्वपूर्ण गैर-महत्वपूर्ण अंकों में परिवर्तित कर देगा। मुझे लगता है कि एक फ्लोट, अधिकतम पर 7 अंकों की सटीकता। –

+4

फ्लोटिंग पॉइंट मानों को समेटने का मानक तरीका यह है: उन्हें आदेश देने के लिए और कम से कम सबसे कम से कम इस कम से कम सटीकता को कम करें। डबल फ्लोट का भी उपयोग करें। –

उत्तर

0

मैं अनुशंसा करता हूं कि आप एक ही चरण - अधिमानतः असेंबली मोड में - गणना के माध्यम से गणनाकर्ताओं पर समान अंकगणित करते समय गणना के माध्यम से। आपको यह निर्धारित करने में सक्षम होना चाहिए कि कौन सी गणना आदेश अपेक्षाकृत कम गुणवत्ता के परिणाम उत्पन्न करते हैं और जो काम करते हैं। आप इससे सीखेंगे और शायद भविष्य में बेहतर क्रमबद्ध गणना लिखेंगे।

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

ईपीएसलॉन दृष्टिकोण के रूप में आपको आमतौर पर प्रत्येक संभावित एक्सपोनेंट के लिए एक ईपीएसलॉन की आवश्यकता होती है। सिंगल-प्रेसिजन फ्लोटिंग पॉइंट प्रारूप के लिए आपको 256 एकल परिशुद्धता फ़्लोटिंग पॉइंट मानों की आवश्यकता होगी क्योंकि एक्सपोनेंट 8 बिट चौड़ा है। कुछ घाटे अपवादों का परिणाम होंगे लेकिन सादगी के लिए 256 सदस्य वेक्टर भी बहुत से परीक्षण करने के लिए बेहतर है।

ऐसा करने का एक तरीका उस स्थिति में अपना बेस ईपीएसलॉन निर्धारित करना हो सकता है जहां एक्सपोनेंट 0 है, मैं प्रति 1.0 1.< = x < 2.0 में तुलना करने के लिए मूल्य की तुलना कर रहा हूं।अधिमानतः ईपीएसलॉन को आधार 2 अनुकूलित ईसा मान के रूप में चुना जाना चाहिए जिसे एक सटीक फ्लोटिंग पॉइंट प्रारूप में बिल्कुल दर्शाया जा सकता है - इस तरह आप जानते हैं कि आप वास्तव में क्या परीक्षण कर रहे हैं और इसे ईपीएसलॉन में समस्याओं को गोल करने के बारे में सोचना नहीं होगा कुंआ। एक्सपोनेंट -1 के लिए आप अपने बेस ईपीएसलॉन का इस्तेमाल दो से विभाजित करेंगे, -2 के लिए विभाजित 4 और इसी तरह से। जब आप एक्सपोनेंट रेंज के सबसे निचले और उच्चतम हिस्सों तक पहुंचते हैं तो आप धीरे-धीरे परिशुद्धता से बाहर निकलते हैं - थोड़ा सा - इसलिए आपको यह पता होना चाहिए कि अत्यधिक मूल्य ईपीएसलॉन विधि को विफल कर सकते हैं।

4

मैंने 2 साल के लिए सिमुलेशन मॉडल के साथ काम किया है और ईपीएसलॉन दृष्टिकोण आपकी फ्लोट की तुलना करने का सबसे अच्छा तरीका है।

0

यदि इसे पूरी तरह से फ़्लोट करना है तो एक ईपीएसलॉन मान का उपयोग करने से मदद मिल सकती है लेकिन सभी समस्याओं को खत्म नहीं किया जा सकता है। मैं उस कोड में स्पॉट्स के लिए युगल का उपयोग करने की अनुशंसा करता हूं जो आपको पता है कि इसमें भिन्नता होगी।

युगल का अनुकरण करने के लिए फ्लोट्स का उपयोग करने का एक और तरीका है, वहां कई तकनीकें हैं और सबसे बुनियादी बात 2 फ्लोट्स का उपयोग करना है और अधिकांश संख्या को एक फ्लोट में शेष और शेष में सहेजने के लिए गणित का थोड़ा सा हिस्सा है दूसरा (इस पर एक महान गाइड देखा, अगर मुझे लगता है कि मैं इसे लिंक करूंगा)।

3

आम तौर पर, उपयुक्त ईपीएसलॉन मानों का उपयोग करना आपको फ़्लोटिंग पॉइंट नंबरों का उपयोग करने की आवश्यकता है। यहां कुछ चीजें हैं जो मदद कर सकती हैं:

  • यदि आपके मान एक ज्ञात सीमा में हैं और आपको डिवीजनों की आवश्यकता नहीं है तो आप समस्या को स्केल करने और पूर्णांक पर सटीक संचालन का उपयोग करने में सक्षम हो सकते हैं। सामान्य रूप से, शर्तें लागू नहीं होती हैं।
  • सटीक गणना करने के लिए तर्कसंगत संख्याओं का उपयोग करना एक भिन्नता है। यह अभी भी उपलब्ध संचालन पर प्रतिबंध है और इसमें आम तौर पर गंभीर प्रदर्शन प्रभाव पड़ते हैं: आप सटीकता के लिए प्रदर्शन का व्यापार करते हैं।
  • राउंडिंग मोड बदला जा सकता है। इसका उपयोग किसी व्यक्तिगत मूल्य के बजाय अंतराल की गणना करने के लिए किया जा सकता है (संभवतः गोल मूल्य, गोल नीचे, और निकटतम दौर के परिणामस्वरूप 3 मानों के साथ)। दोबारा, यह सबकुछ के लिए काम नहीं करेगा लेकिन आपको इससे एक त्रुटि अनुमान मिल सकता है।
  • त्रुटि के वर्तमान आकार का आकलन करने के लिए मूल्य और कई संचालन (संभावित एकाधिक काउंटर) का ट्रैक रखना भी उपयोग किया जा सकता है।
  • संभवतः विभिन्न संख्यात्मक प्रस्तुतियों (float, double, अंतराल, आदि) के साथ प्रयोग करने के लिए आप शायद अपने सिमुलेशन को संख्यात्मक प्रकार के लिए पैरामीटर के रूप में कार्यान्वित करना चाहते हैं।
  • फ्लोटिंग पॉइंट अंकगणित का उपयोग करते समय त्रुटियों का अनुमान लगाने और कम करने पर कई किताबें लिखी गई हैं। यह संख्यात्मक गणित का विषय है।

अधिकांश मामलों में मैं ऊपर वर्णित कुछ विधियों के साथ संक्षेप में प्रयोग से अवगत हूं और निष्कर्ष निकाला हूं कि मॉडल किसी भी तरह से अपरिचित है और प्रयास से परेशान नहीं है। साथ ही, float का उपयोग करने से कुछ और करने से बेहतर परिणाम मिल सकता है लेकिन दोगुनी मेमोरी पदचिह्न और सिमड ऑपरेशंस का उपयोग करने के छोटे अवसर के कारण double का उपयोग करके भी बहुत धीमी है।

+0

कुछ मामलों में "सामान्यीकरण" (?) मदद कर सकता है। मान लीजिए कि कोई ऑब्जेक्ट चल रहा है या घुमा रहा है और अंतिम समन्वय के आधार पर हर बार इसके नए निर्देशांक पुन: गणना किए जाते हैं। समय के साथ, जैसे त्रुटियां जमा होती हैं, ऑब्जेक्ट अपना मूल आकार या आकार खोना शुरू कर सकता है। इसे अनुमानित आकार और आकार को ध्यान में रखते हुए समन्वय को पुन: गणना/समायोजित करके (प्रत्येक बार या एक बार में) समायोजित किया जा सकता है। –

0

निश्चित रूप से आपको फ्लोट्स के बजाय युगल का उपयोग करना चाहिए। यह शायद फ्लिप किए गए नोड्स की संख्या को कम कर देगा।

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

संबंधित मुद्दे

 संबंधित मुद्दे