2010-06-14 24 views
18

क्या मेरी समझ सही है कि रूबी BigDecimal प्रकारों (यहां तक ​​कि अलग-अलग परिशुद्धता और स्केल लम्बाई के साथ) के साथ सटीक गणना की जानी चाहिए या क्या मुझे फ्लोटिंग पॉइंट शेंगेनिग्स की उम्मीद करनी चाहिए?रूबी बिगडेसिमल सैनिटी चेक (फ्लोटिंग पॉइंट न्यूब)

रेल के आवेदन के भीतर मेरे सभी मूल्य BigDecimal प्रकार हैं और मुझे कुछ त्रुटियां दिखाई दे रही हैं (उनके पास अलग-अलग दशमलव लंबाई हैं), उम्मीद है कि यह सिर्फ मेरे तरीके हैं और मेरे ऑब्जेक्ट प्रकार नहीं हैं।

उत्तर

31

फ़्लोटिंग पॉइंट अंकगणित के साथ काम करते समय दो आम नुकसान हैं।

पहली समस्या यह है कि रूबी फ्लोटिंग पॉइंट्स ने सटीकता तय की है। अभ्यास में यह या तो 1 होगा) आपके लिए कोई समस्या नहीं है या 2) विनाशकारी, या 3) बीच में कुछ। निम्नलिखित पर विचार करें:

# float 
1.0e+25 - 9999999999999999900000000.0 
#=> 0.0 

# bigdecimal 
BigDecimal("1.0e+25") - BigDecimal("9999999999999999900000000.0") 
#=> 100000000 

100 मिलियन का सटीक अंतर! बहुत गंभीर, है ना?

सटीक त्रुटि को छोड़कर मूल संख्या के बारे में केवल 0.000000000000001% है। यह वास्तव में आप पर निर्भर है कि यह एक समस्या है या नहीं। लेकिन समस्या BigDecimal का उपयोग कर हटा दी गई है क्योंकि इसमें मनमाना सटीकता है। रूबी के लिए आपकी एकमात्र सीमा स्मृति उपलब्ध है।

दूसरी समस्या यह है कि फ़्लोटिंग पॉइंट सभी अंशों को सटीक रूप से व्यक्त नहीं कर सकते हैं। विशेष रूप से, उन्हें दशमलव अंशों के साथ समस्याएं हैं, क्योंकि रूबी (और अधिकतर अन्य भाषाओं) में तैरती बाइनरी फ़्लोटिंग पॉइंट्स हैं। उदाहरण के लिए, दशमलव अंश 0.2 एक सदा-दोहराने वाला बाइनरी अंश (0.001100110011...) है। इसे बाइनरी फ्लोटिंग पॉइंट में सटीक रूप से संग्रहीत नहीं किया जा सकता है, इससे कोई फर्क नहीं पड़ता कि सटीकता क्या है।

जब आप संख्याओं को गोल कर रहे हैं तो इससे बड़ा अंतर हो सकता है। पर विचार करें:

# float 
(0.29 * 50).round 
#=> 14 # not correct 

# bigdecimal 
(BigDecimal("0.29") * 50).round 
#=> 15 # correct 

एक BigDecimal ठीक दशमलव अंशों वर्णन कर सकते हैं। हालांकि, ऐसे भिन्नताएं हैं जिन्हें दशमलव अंश के साथ ठीक से वर्णित नहीं किया जा सकता है। उदाहरण के लिए 1/9 एक सदा-दोहराने वाला दशमलव अंश है (0.1111111111111...)।

फिर, जब आप किसी संख्या को गोल करते हैं तो यह आपको काट देगा। पर विचार करें: इस मामले में

# bigdecimal 
(BigDecimal("1")/9 * 9/2).round 
#=> 0 # not correct 

, दशमलव फ्लोटिंग अंक का उपयोग कर अभी भी एक गोलाई त्रुटि दे देंगे।

कुछ निष्कर्ष: यदि आप दशमलव भिन्न के साथ गणना करने (पैसा, उदाहरण के लिए)

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

"प्रैक्टिस में यह या तो 1 होगा) आपके लिए कोई समस्या नहीं है या 2) विनाशकारी, या 3) बीच में कुछ" - प्यार कैसे आपने इसे कम किया है :) –

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