2009-10-22 17 views
13

एक और गणित गणना समस्या फिर से मिला।PHP फ्लोट गणना 2 दशमलव बिंदु

$a = 34.56 

$b = 34.55 

$a कुछ गणना करते हैं यह आंकड़ा पाने के लिए

$b निकटतम 0.05 गोलाई यह आंकड़ा

प्राप्त करने के लिए क्या हो रहा है

$c = $b - $a 

माना जाता है कि मैं -0.01 होना चाहिए कर रहा है, लेकिन मैं $c को प्रतिबिंबित करता हूं -0.00 9 88888888888

मैं n umber_format($c, 2) उपयोग करने का प्रयास है, लेकिन उत्पादन 0.00 है,

मुझे यकीन है कि $a और $b ठीक 2 दशमलव, वापस में कोई छिपा संख्या है कैसे कर सकते हैं।

मेरी php ज्ञान number_format केवल प्रदर्शन स्वरूप करने में सक्षम में

, लेकिन मूल्य नहीं वास्तव में 2 दशमलव,

मुझे आशा है कि मैं यहाँ से मदद मिल सकती है। यह वास्तव में मुझे निराश किया।

+0

अधिक व्यापक, PHP-wide परिवर्तनों के लिए php.ini में 'सटीक' की जांच करें। हालांकि, सलाह दीजिये कि आप * महत्वपूर्ण अंकों * से निपट रहे हैं। –

उत्तर

34

प्रयास करें sprintf("%.2f", $c);

चल बिन्दु संख्या 2 के पावर पर आधारित आईईईई अंकन में प्रतिनिधित्व कर रहे हैं, तो समाप्त दशमलव संख्या एक को समाप्त द्विआधारी संख्या नहीं हो सकता है, यही कारण है कि आप पीछे अंक मिलता है।

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

$a = 3456; 

$b = 3455; 

$c = $b - $a; 

sprintf ("%.2f", $c/100.0); 

इस तरह, यदि आप प्रिंटिंग से पहले बहुत सारी गणना करते हैं तो आपके पास कोई गोल करने वाली त्रुटियां नहीं होंगी।

+0

आपके उत्तर के लिए धन्यवाद, आउटपुट को प्रारूपित करने का एकमात्र तरीका है, स्ट्रिंग का उपयोग करने के अलावा इसे केवल 2 दशमलव पर सेट करना संभव नहीं है। – Shiro

+0

यदि आप इसे केवल 2 दशमलव तक सेट करना चाहते हैं, तो आपको फिक्स्ड-पॉइंट नंबरों का उपयोग करना चाहिए, फ्लोटिंग-पॉइंट नहीं। परिवर्तनीय लंबाई कोडर का जवाब देखें। –

+0

मैं वास्तव में समझ नहीं पा रहा हूं कि इसका मतलब "निश्चित-बिंदु" संख्याओं से क्या है, क्या आप कृपया कुछ उदाहरण प्रदान कर सकते हैं? आपका बहुत बहुत धन्यवाद! – Shiro

12

उपयोग round():

$c = round($b - $a, 2); 

नोट: आप भी उचित रूप में गोलाई मोड चुन सकते हैं।

संपादित करें:

$c = number_format($b - $a, 2); 

बनाम

$c = sprintf("%.2f", $b - $a); 

: ठीक है मैं क्या sprintf() कर रही है कि number_format() नहीं है नहीं मिलता है?

+0

शायद कुछ भी नहीं, लेकिन sprintf() मेरे जैसे लोगों के लिए उपयोग करने के लिए बहुत अधिक मजेदार है जो सी के आदी हैं। यह भी एक लेख '$ foo = number_format ($ b - $ a, 2) बचाता है। "सेब!" और इसके बजाय '$ foo = sprintf ("%। 2f सेब!", $ b - $ a) लिखना - मेरी राय में, और अधिक सुरुचिपूर्ण। –

+0

गोल चट्टानों, शायद यही कारण है कि मैं अभी भी जानता हूं, अभी भी सीख रहा हूं। – Newb

2

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

उदाहरण के लिए, यदि आप डॉलर (या अपनी पसंदीदा मुद्रा) को रीसेट करने वाली फ्लोट्स में गणना कर रहे हैं, तो आप वास्तव में पूर्णांक सेंट में अपनी गणना करना चाहेंगे।

+0

क्या आप कृपया एक उदाहरण दे सकते हैं कि पूर्णांक सेंट कैसे काम करते हैं? वास्तव में आप क्या मतलब नहीं मिलता है। आपकी टिप्पणी के लिए बहुत बहुत धन्यवाद। – Shiro

+0

"इंटीजर सेंट" का अर्थ है कि, उदाहरण के लिए, $ 24.95 की राशि को फ्लोटिंग-पॉइंट 24.9 5 के रूप में नहीं रखा जाना चाहिए, बल्कि पूर्णांक 2495 के रूप में संग्रहीत किया जाना चाहिए। $ 10.00 की राशि पूर्णांक 1000 के रूप में संग्रहीत की जाएगी। और आगे। –

2

आप बीसीएमथ लाइब्रेरी का उपयोग करके इन सभी मुद्दों को बहुत अच्छी तरह से हटा सकते हैं।

बस प्रलेखन को पढ़ना याद रखें और सावधान रहें कि क्या आप स्ट्रिंग्स या न्यूमेरिक डेटाटाइप के रूप में तर्क पारित कर रहे हैं।

4

मूल निवासी गणना:

$a = 34.56; 
$b = 34.55; 
$c = $b - $a; // -0.010000000000005  

वर्क्स के रूप में की उम्मीद (वास्तविक संख्या की गणना के लिए हमेशा ईसा पूर्व कार्यों का उपयोग, इस मुद्दे सब सी आधारित प्लेटफॉर्म के लिए है!):

$a = '34.56'; 
$b = '34.55'; 
$c = bcsub($b, $a, 4); // -0.0100  
+0

इस पर आगे बढ़ने के लिए। फ्लोट/डबल डेटा प्रकारों के बजाय डेटा का प्रतिनिधित्व करने के लिए स्ट्रिंग का उपयोग करें। फिर चर की गणना करने के लिए बीसीएमएथ फ़ंक्शंस का उपयोग करें। Sprintf का उपयोग करने के लिए ('% 1 $ s', bcadd ($ var1, $ var2)); डाटाबेस डेटा स्टोरेज पर भी यही लागू होता है। http://php.net/manual/en/book.bc.php – fyrye

3

मैं फ्लोट्स के साथ गणना करते समय हाल ही में इस मुद्दे में भी भाग गया। उदाहरण के लिए, मेरे पास 2 फ्लोट्स थीं जब घटित और स्वरूपित किया गया था, मान -0.00 था।

$floatOne = 267.58; 
$floatTwo = 267.58; 
$result = number_format($floatOne - floatTwo, 2); 
print $result; //printed a string -0.00 

मैं क्या किया था:

$result = abs($floatOne - $floatTwo);// Made the number positive 
print money_format('%i', $result); // printed the desired precision 0.00 

मेरी समाधान में मुझे पता है कि floatOne floatTwo से कम होना कभी नहीं होगा। money_format फ़ंक्शन केवल तभी परिभाषित किया जाता है जब सिस्टम में स्ट्रफ़ोन क्षमताएं हों, विंडोज नहीं।

1

यदि अभी भी कोई भी इसी पृष्ठ के साथ इस पृष्ठ तक पहुंचता है जहां फ़्लोटिंग संख्या घटाव त्रुटि या अजीब मानों का कारण बनता है। मैं इस समस्या को थोड़ा और विवरण के साथ समझाऊंगा। अपराधी फ्लोटिंग पॉइंट नंबर है। और विभिन्न ऑपरेटिंग सिस्टम और प्रोग्रामिंग भाषाओं के विभिन्न संस्करण अलग-अलग व्यवहार कर सकते हैं।

समस्या का वर्णन करने के लिए, मैं समझाऊंगा कि नीचे एक सरल उदाहरण क्यों है।

यह सीधे PHP से संबंधित नहीं है और यह एक बग नहीं है। हालांकि, प्रत्येक प्रोग्रामर को इस मुद्दे से अवगत होना चाहिए।

इस समस्या ने दो दशकों पहले भी कई जान ली।

25 फरवरी 1 99 1 को एमआईएम-104 देशभक्त मिसाइल बैटरी में फ्लोटिंग नंबर गणना में इस समस्या ने इसे अमेरिकी सेना के 14 वें क्वार्टरमास्टर डिटेचमेंट से 28 सैनिकों की मौत में योगदान देने वाले धहरान, सऊदी अरब में आने वाली स्कड मिसाइल को रोक दिया।

लेकिन ऐसा क्यों होता है?

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

बस एक साधारण उदाहरण:

$a = '36'; 
$b = '-35.99'; 
echo ($a + $b); 

आप इसे 0.01, सही मुद्रित करने के लिए उम्मीद करेंगे? लेकिन यह 0.0099 99 99 99 99 998

अन्य नंबरों की तरह, एक फ्लोटिंग पॉइंट नंबर डबल या फ्लोट को 0 और 1 की स्ट्रिंग के रूप में स्मृति में संग्रहीत किया जाता है।पूर्णांक से कितना फ़्लोटिंग पॉइंट अलग होता है यह है कि हम 0 और 1 की व्याख्या कैसे करते हैं जब हम उन्हें देखना चाहते हैं। कई मानक हैं कि वे कैसे संग्रहीत हैं।

फ्लोटिंग-बिन्दु संख्या आम तौर पर संकेत बिट, प्रतिपादक क्षेत्र, और significand या अपूर्णांश के रूप में एक कंप्यूटर गृहीत में पैक कर रहे हैं सही ....

दशमलव संख्या में अच्छी तरह से बाइनरी में प्रतिनिधित्व नहीं है बाएं से पर्याप्त जगह की कमी के कारण। तो, आप 1/3 बिल्कुल स्पष्ट नहीं कर सकते क्योंकि यह 0.3333333 है ..., है ना? हम एक कारण के लिए 0.01 का प्रतिनिधित्व नहीं कर सकते हैं क्योंकि बाइनरी फ्लोट नंबर एक ही कारण है। 1/100 0.00000010100011110101110000 है ..... एक दोहरा 10100011110101110000.

0.01 बाइनरी में 01000111101011100001010, जब यह वापस दशमलव के अनुवाद किया है के सरलीकृत और सिस्टम छोटा कर दिया के रूप में रखा गया है, तो के साथ, यह .००,९९,९९९ की तरह पढ़ कर दिया जाएगा। ... सिस्टम के आधार पर (64 बिट कंप्यूटर आपको 32-बिट्स से बेहतर परिशुद्धता देगा)। ऑपरेटिंग सिस्टम इस मामले में फैसला करता है कि इसे प्रिंट करना है या नहीं, इसे अधिक मानव-पठनीय तरीके से कैसे बनाया जाए। इसलिए, यह मशीन-निर्भर है कि वे इसका प्रतिनिधित्व कैसे करना चाहते हैं। लेकिन इसे विभिन्न तरीकों से भाषा स्तर में संरक्षित किया जा सकता है।

यदि आप परिणाम स्वरूपित करते हैं, तो echo number_format (0.009999999999998, 2); यह 0.01 प्रिंट करेगा।

ऐसा इसलिए है क्योंकि इस मामले में आप निर्देश देते हैं कि इसे कैसे पढ़ा जाना चाहिए और आपको कितनी सटीकता की आवश्यकता है।

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