पैसा, चाहे वह किसी भी मुद्रा में हो, एक फ्लोटिंग-पॉइंट नंबर की तरह लगता है। लेकिन मुद्रा के लिए फ्लोट का उपयोग करना एक गलती है।
फ्लोट नंबर (इसलिए, फ्लोट ऑब्जेक्ट्स), परिभाषा के अनुसार, वास्तविक वास्तविक संख्याएं हैं जो मूल वास्तुकला की डबल-सटीक फ़्लोटिंग-पॉइंट प्रतिनिधित्व विशेषता का उपयोग करती हैं। गलत संख्याएं लेखाकारों को दुखी करती हैं।
इस लेख में, आपको कुछ त्वरित उदाहरणों के माध्यम से निर्देशित किया जाएगा जो रूबी और रेल में धन डेटा से निपटने के लिए उपलब्ध विकल्पों को संबोधित करने में आपकी सहायता करेंगे।
फ्लोट क्या है?
जैसा कि हमने कहा, float
वस्तुओं के अलग-अलग अंकगणित होते हैं। यह मुख्य कारण है कि वे अचूक संख्याएं हैं, खासकर क्योंकि रूबी (अधिकांश भाषाओं की तरह) फ्लोट का प्रतिनिधित्व करने के लिए निश्चित संख्या में बाइनरी अंकों का उपयोग करती है। दूसरे शब्दों में, रूबी फ्लोटिंग नंबरों को दशमलव से बाइनरी और इसके विपरीत में परिवर्तित करती है।
जब आप वास्तविक संख्याओं (उर्फ दशमलव संख्या) के द्विआधारी प्रतिनिधित्व में गहराई से गोता लगाते हैं, तो उनमें से कुछ का सटीक रूप से प्रतिनिधित्व नहीं किया जा सकता है, इसलिए सिस्टम के लिए एकमात्र शेष विकल्प उन्हें गोल करना है।
यदि आप आगे सोचते हैं और सामान्य गणित संरचनाओं पर विचार करते हैं, जैसे कि आवधिक दशमांश, तो आप समझ सकते हैं कि pi के बाद से उन्हें एक निश्चित संख्या के भीतर पूरी तरह से प्रदर्शित नहीं किया जा सकता है। संख्या, उदाहरण के लिए, अनंत है। फ़्लोट्स में आमतौर पर 32 या 64 बिट तक की सटीकता हो सकती है, जिसका अर्थ है कि जब संख्या सीमा तक पहुंच जाएगी तो संख्या काट दी जाएगी।
आइए एक क्लासिक उदाहरण का विश्लेषण करें:
1200 * (14.0/100)
किसी संख्या के प्रतिशत की गणना करने का यह एक सीधा तरीका है। 1200 का चौदह प्रतिशत 168 होना चाहिए; हालांकि, रूबी के भीतर इस निष्पादन का परिणाम होगा
1200 * (14.0/100)
=> 168.00000000000003
हालांकि, अगर आप फॉर्मूला में सिर्फ 0.1% जोड़ते हैं, तो आपको कुछ अलग मिलता है:
1200 * (14.1/100)
=> 169.2
वैकल्पिक रूप से, आप round
. कर सकते हैं कितने दशमलव स्थान वांछित हैं, यह परिभाषित करते हुए, निकटतम संभव एक का मान:
(my_calculation).round(2)
वास्तव में, जब अधिक जटिल गणनाओं की बात आती है, तो इसकी गारंटी नहीं होती है, खासकर यदि आप इन मूल्यों की तुलना करते हैं।
यदि आप इसके पीछे के वास्तविक विज्ञान को समझने में रुचि रखते हैं, तो मैं ओरेकल के परिशिष्ट को पढ़ने की अत्यधिक अनुशंसा करता हूं:फ़्लोटिंग-पॉइंट अंकगणित के बारे में प्रत्येक कंप्यूटर वैज्ञानिक को क्या पता होना चाहिए। यह विस्तार से बताता है कि फ्लोट नंबरों की गलत प्रकृति के पीछे का कारण क्या है।
विश्वसनीय BigDecimal
निम्नलिखित कोड स्निपेट पर विचार करें:
require "bigdecimal"
BigDecimal("45.99")
यह कोड आसानी से एक ईकामर्स कार्ट की राशि को अपनाने वाले वास्तविक तर्क का प्रतिनिधित्व कर सकता है। अंत में, हेरफेर किया जा रहा वास्तविक मूल्य हमेशा 45.9989 या 45.99000009 के बजाय 45.99 होगा, उदाहरण के लिए।
यह BigDecimal
. की सटीक प्रकृति है . सामान्य अंकगणितीय गणनाओं के लिए, float
उसी तरह प्रदर्शन करेंगे; हालांकि, यह अप्रत्याशित है, जो इसका उपयोग करने का खतरा है।
जब इसे BigDecimal
के साथ चलाया जाता है , वही प्रतिशत गणना जो हमने पिछले अनुभाग परिणामों में की थी
require "bigdecimal"
(BigDecimal(1200) * (BigDecimal(14)/BigDecimal(100))).to_s("F")
=> 168.0
irb . में तेजी से निष्पादन की अनुमति देने के लिए यह एक छोटा संस्करण है कंसोल.
मूल रूप से, जब आप सीधे BigDecimal
print प्रिंट करते हैं ऑब्जेक्ट, आपको इसका वैज्ञानिक संकेतन मिलेगा, जो कि हम यहां नहीं चाहते हैं। to_s
विधि स्वरूपण सेटिंग्स के कारण दिए गए तर्क को प्राप्त करती है और BigDecimal के समतुल्य फ़्लोटिंग मान प्रदर्शित करती है। इस विषय पर अधिक जानकारी के लिए, रूबी डॉक्स देखें।
यदि आपको दशमलव स्थानों के लिए एक सीमा निर्धारित करने की आवश्यकता है, तो इसमें truncate
. है विधि, जो आपके लिए काम करेगी:
(BigDecimal(1200) * (BigDecimal("14.12")/BigDecimal(100))).truncate(2).to_s("F")
=> 169.44
रूबीमनी प्रोजेक्ट
इन समस्याओं के बारे में सोचकर ही RubyMoney बनाया गया था। यह रूबी डेवलपर्स का एक ओपन-सोर्स समुदाय है, जिसका लक्ष्य रूबी इकोसिस्टम में पैसे के डेटा में हेरफेर करने के लिए महान पुस्तकालय प्रदान करके डेवलपर्स के जीवन को सुविधाजनक बनाना है।
यह परियोजना सात पुस्तकालयों से बनी है, जिनमें से तीन महत्वपूर्ण हैं:
- पैसा:पैसे और मुद्रा रूपांतरण से निपटने के लिए एक रूबी पुस्तकालय। यह मजबूत और आधुनिक अनुप्रयोगों में धन को संभालने के लिए कई वस्तु-उन्मुख विकल्प प्रदान करता है, चाहे वे वेब के लिए ही क्यों न हों।
- मनी-रेल:रूबी ऑन रेल्स के लिए रूबीमनी का एकीकरण, सभी
money
को मिलाकर रेल लचीलेपन के साथ पुस्तकालय की शक्ति। - मुद्रीकरण:विभिन्न वस्तुओं को
money
में परिवर्तित करने के लिए एक पुस्तकालय वस्तुओं। यह उन अनुप्रयोगों के लिए एक सहायक पुस्तकालय की तरह अधिक काम करता है जो बहुत सारे स्ट्रिंग पार्सिंग से निपटते हैं, उदाहरण के लिए।
परियोजना में चार अन्य दिलचस्प पुस्तकालय हैं:
- EU_central_bank:एक पुस्तकालय जो यूरोपीय सेंट्रल बैंक से प्रकाशित दरों का उपयोग करके विनिमय दरों की गणना करने में मदद करता है।
- Google_currency:संदर्भ के रूप में Google मुद्रा दरों का उपयोग करते हुए मुद्रा रूपांतरण के लिए एक दिलचस्प पुस्तकालय।
- धन-संग्रह:
money
के योग/मिनट/अधिकतम की सही गणना के लिए एक सहायक पुस्तकालय वस्तुओं। - मनी-हेयुरिस्टिक्स:मनी रत्न के लिए स्ट्रिंग इनपुट के अनुमानी विश्लेषण के लिए एक मॉड्यूल।
“मनी” जेम
आइए सबसे प्रसिद्ध से शुरू करें:मनी मणि। इसकी मुख्य विशेषताओं में निम्नलिखित हैं:
- एक
money
वह वर्ग जो प्रासंगिक मौद्रिक जानकारी रखता है, जैसे कि मूल्य, मुद्रा और दशमलव चिह्न। - एक और वर्ग जिसे
Money::Currency
कहा जाता है जो डेवलपर द्वारा उपयोग की जा रही मौद्रिक इकाई के बारे में जानकारी को लपेटता है। - डिफ़ॉल्ट रूप से, यह उपरोक्त त्रुटियों से बचने के लिए फ़्लोटिंग-पॉइंट नंबरों के बजाय पूर्णांकों के साथ काम करता है।
- एक मुद्रा से दूसरी मुद्रा में पैसे का आदान-प्रदान करने की क्षमता, जो बहुत बढ़िया है।
इसके अलावा, हमें आपकी परियोजनाओं के भीतर किसी भी अन्य मॉडल की तरह, पैसे के डेटा में हेरफेर करने के लिए सुसंगत और वस्तु-उन्मुख संरचनाओं द्वारा प्रदान की जाने वाली उच्च लचीलापन भी मिलती है।
इसका उपयोग बहुत आसान है, बस उचित रत्न स्थापित करें:
gem install money
एक निश्चित राशि को शामिल करने वाला एक त्वरित उदाहरण होगा
my_money = Money.new(1200, "USD")
my_money.cents #=> 1200
my_money.currency #=> Currency.new("USD")
जैसा कि आप देख सकते हैं, सेंट के आधार पर पैसे का प्रतिनिधित्व किया जाता है। बारह सौ सेंट 12 डॉलर के बराबर है।
जैसे आपने BigDecimal के साथ किया था, वैसे ही आप इन वस्तुओं के साथ भी खेल सकते हैं और कुछ बुनियादी गणित कर सकते हैं। उदाहरण के लिए,
cart_amount = Money.new(10000, "USD") #=> 100 USD
discount = Money.new(1000, "USD") #=> 10 USD
cart_amount - discount == Money.new(9000, "USD") #=> 90 USD
दिलचस्प है, है ना? यह उन वस्तुओं की प्रकृति है जिनका हमने उल्लेख किया है। कोडिंग करते समय, ऐसा लगता है कि आप अर्थहीन और साधारण संख्याओं के बजाय मौद्रिक मूल्यों में हेरफेर कर रहे हैं।
मुद्रा रूपांतरण
यदि आपके पास अपनी स्वयं की विनिमय दर प्रणाली है, तो आप विनिमय बैंक ऑब्जेक्ट के माध्यम से मुद्रा रूपांतरण कर सकते हैं। निम्नलिखित पर विचार करें:
Money.add_rate("USD", "BRL", 5.23995)
Money.add_rate("BRL", "USD", 0.19111)
जब भी आपको उनके बीच मूल्यों का आदान-प्रदान करने की आवश्यकता हो, तो आप निम्न कोड चला सकते हैं:
Money.us_dollar(100).exchange_to("BRL") #=> Money.new(523, "BRL")
यह किसी भी अंकगणित और तुलना मूल्यांकन पर लागू होता है जिसे आप करना चाहते हैं।
अधिक प्रदान की गई मुद्रा विशेषताओं, जैसे iso_code
के लिए दस्तावेज़ों को देखना सुनिश्चित करें (जो उस मुद्रा का अंतरराष्ट्रीय तीन अंकों का कोड लौटाता है) और decimal_mark
(मूल्य और धन डेटा के अंश के बीच का चार्ट), दूसरों के बीच में।
अरे मैं तो करीब करीब भूल ही गया था; मनी रत्न स्थापित करने के बाद, आप एक BigDecimal
. तक पहुंच सकते हैं to_money
. नामक विधि जो स्वचालित रूप से आपके लिए रूपांतरण करता है।
“मुद्रीकरण” रत्न
रूबीमनी परियोजना में प्रत्येक पुस्तकालय की भूमिका को समझना महत्वपूर्ण है। जब भी आपको किसी भिन्न रूबी ऑब्जेक्ट (एक String
.) को कनवर्ट करने की आवश्यकता होती है , उदाहरण के लिए) money
. में , फिर monetize
आप जो खोज रहे हैं वह है।
सबसे पहले, मणि निर्भरता स्थापित करना सुनिश्चित करें या इसे अपने Gemfile . में जोड़ें :
gem install monetize
जाहिर है, money
भी स्थापित करने की आवश्यकता है।
parse
जब आप किसी भिन्न प्रारूप में धन डेटा प्राप्त करते हैं तो विधि भी बहुत उपयोगी होती है; उदाहरण के लिए,
Money.parse("£100") == Money.new(100, "GBP") #=> true
हालाँकि जिन परिदृश्यों में आप इस पार्सिंग पद्धति का उपयोग करेंगे, वे प्रतिबंधित हैं, यह तब बहुत उपयोगी हो सकता है जब आप HTTP अनुरोध से इसके मुद्रा कोड के साथ स्वरूपित मान प्राप्त करते हैं। वेब पर, सब कुछ टेक्स्ट है, इसलिए स्ट्रिंग से money
में कनवर्ट करना बहुत उपयोगी हो सकता है।
हालांकि, सावधान रहें कि आपका सिस्टम मूल्यों में कैसे हेरफेर करता है और अगर उन्हें किसी तरह हैक किया जा सकता है। वित्तीय सिस्टम हमेशा कई सुरक्षा परतों से ढके रहते हैं ताकि यह सुनिश्चित किया जा सके कि आपको जो मूल्य मिल रहा है वह उस लेन-देन का वास्तविक मूल्य है।
“मुद्रीकरण-रेल” रत्न
यह पुस्तकालय है जो समान धन हेरफेर संचालन से संबंधित है, लेकिन एक रेल ऐप के भीतर।
रेल के साथ काम करने के लिए हमें दूसरी लाइब्रेरी की आवश्यकता क्यों है? ठीक है, आप निश्चित रूप से money
. का उपयोग कर सकते हैं सामान्य गणित संचालन के लिए रेल परियोजनाओं के भीतर मणि अकेले। हालांकि, यह ठीक से काम नहीं करेगा जब आपके रेल ढांचे को money
. के साथ संचार करने की आवश्यकता होगी की विशेषताएं।
निम्नलिखित उदाहरण पर विचार करें:
class Cart < ActiveRecord::Base
monetize :amount_cents
end
यह एक वास्तविक, कार्यात्मक रेल मॉडल वस्तु है। आप डेटाबेस के साथ इसका उपयोग कर सकते हैं (यहां तक कि उपनाम सहित जब आप एक अलग मॉडल विशेषता नाम चाहते हैं), Mongoid, REST वेब सेवाएं, आदि।
अब तक हम जिन सुविधाओं के संपर्क में रहे हैं, वे भी इस रत्न पर लागू होती हैं। आमतौर पर, इसे चलाने के लिए केवल अतिरिक्त सेटिंग्स की आवश्यकता होती है, जिसे config/initializers/money.rb में रखा जाना चाहिए। फ़ाइल:
MoneyRails.configure do |config|
# set the default currency
config.default_currency = :usd
end
यह आपके द्वारा प्रदान की जाने वाली डिफ़ॉल्ट मुद्रा को सेट कर देगा। हालांकि, विकास के दौरान, संभावना है कि आपको पूरे मॉडल में विनिमय रूपांतरण करने या एक से अधिक मुद्रा को संभालने की आवश्यकता हो सकती है।
अगर ऐसा है, तो money-rails
हमें एक मॉडल-स्तरीय मुद्रा परिभाषा कॉन्फ़िगर करने की अनुमति देता है:
class Cart < ActiveRecord::Base
# Use GPB as model level currency
register_currency :eur
monetize :amount_cents, as "amount"
monetize :discount_cents, with_currency: :eur
monetize :converted_value, with_currency: :usd
end
ध्यान दें कि एक बार सब कुछ सेट हो जाने के बाद, आपकी परियोजनाओं के साथ-साथ पैसे के प्रकारों का उपयोग करना वास्तव में आसान होता है।
रैपिंग अप
इस ब्लॉग पोस्ट में, हमने रूबी और रेल्स इकोसिस्टम के भीतर पैसे के मूल्यों से निपटने के लिए कुछ उपलब्ध विकल्पों का पता लगाया है। कुछ महत्वपूर्ण बिंदुओं का सारांश नीचे दिया गया है:
- यदि आप फ्लोट नंबरों की गणना के साथ काम कर रहे हैं, खासकर यदि वे पैसे डेटा का प्रतिनिधित्व करते हैं, तो
BigDecimal
के लिए जाएं याmoney
उदाहरण। - अपने विकास के साथ-साथ आगे की विसंगतियों से बचने के लिए केवल एक प्रणाली पर टिके रहने का प्रयास करें।
- द
money
पुस्तकालय पूरे रूबीमनी सिस्टम का मूल है, और यह बहुत मजबूत और सीधा है।money-rails
रेल अनुप्रयोगों के लिए समकक्ष संस्करण है, औरmonetize
जब भी आपको किसी भी मूल्य सेmoney
में पार्स करने की आवश्यकता हो, तो यह आवश्यक है वस्तुओं। float
का उपयोग करने से बचें . यहां तक कि अगर आपके ऐप को अभी कुछ भी गणना करने की आवश्यकता नहीं है, तो संभावना है कि एक अनजान देव भविष्य में ऐसा करेगा। हो सकता है कि आप इसे रोकने के लिए मौजूद न हों।
याद रखें, आधिकारिक डॉक्स हमेशा जरूरी होने चाहिए। BigDecimal महान व्याख्याओं और इसके उपयोग के उदाहरणों से भरा है, और वही RubyMoney रत्न परियोजनाओं के बारे में सच है।