डीसी के साथ सटीकता खोना


12

मैं dcहेक्साडेसिमल अंकों के साथ कुछ आधार 16 नंबरों को संभालने के लिए उपयोग करना चाहता हूं, लेकिन मैं सटीक समस्याओं में चल रहा हूं। उदाहरण के लिए, नीचे मैं गुणा F423F.FDकर रहा हूं 100, दोनों हेक्स। अपेक्षित जवाब है F423FFD, इसके बजाय यह दे रहा है F423FFA.E1, पास है लेकिन पूरी तरह से सटीक नहीं है, भले ही गोलाई के बाद।

$ dc
16 d i o F423F.FD 100 * p
F423FFA.E1

मैंने पढ़ा कि dcयह एक असीमित सटीक कैलकुलेटर था, और यह किसी भी तरह से बड़ी संख्या में नहीं है। क्या मैं कुछ गलत कर रहा हूँ?

आपके उत्तर के लिए धन्यवाद। के साथ मुद्दों को देखते हुए dc, मैंने गोली चलाई और अन्य ठिकानों में वास्तविक संख्याओं के लिए अपना स्वयं का पार्सर लिखा। अगर किसी को कोड में दिलचस्पी है, तो मैं इसे यहां पोस्ट कर सकता हूं।

जवाबों:


6

ध्यान दें कि मूल संख्या को प्रिंट करने से पता चलता है कि यह गोल है:

$ dc <<<'16 d i o F423F.FD p'
F423F.FA

अधिक सटीकता के लिए बहुत सारे अनुगामी शून्य जोड़कर आप इसे प्राप्त कर सकते हैं:

$ dc <<<'16 d i o F423F.FD000000 100 * p'
F423FFD.0000000

धन्यवाद। मुझे लगता है कि इसका dcउपयोग करने के लिए संख्याओं की मालिश करने के लिए अधिक कोड लेना समाप्त हो जाएगा, फिर बस सीधे एक पार्सर लिखने के लिए! (इनपुट में दशमलव नहीं हो सकता है, और अन्य ठिकानों में हो सकता है, इसलिए पैडिंग की मात्रा भिन्न हो सकती है।)
यिमिन रोंग

2
मैं इसे स्वीकृत उत्तर के रूप में चिह्नित करूंगा। dcउत्तर को बनाए रखने के लिए जिम्मेदार लोग : गैर-दशमलव अंश अंकों को ठीक से संभालने के लिए, डीसी और डीसी द्वारा उपयोग किए गए दशमलव-स्केल मॉडल की तुलना में पूरी तरह से अलग मॉडल की आवश्यकता होगी (जैसा कि बीसी के लिए पोसिक्स द्वारा निर्देशित है, और दोनों के लिए ऐतिहासिक परंपरा द्वारा)। , इसलिए तकनीकी रूप से इसे ठीक किया जा सकता है dc, लेकिन यह संभवतः टूट जाएगा bc, इसलिए इसे WONTFIX के रूप में वर्गीकृत किया जाएगा।
यमिन रॉन्ग

8

दशमलव के रूप में व्यक्त ( dcकन्वर्ट करने के लिए), यह 999999.98 (गोल नीचे) × 256, यानी 255999994.88 से मेल खाती है, जो कि हेक्साडेसिमल में F423FFA.E1 है।

तो अंतर dcगोल व्यवहार से आता है : 256 × (999999 + 253) 256) की गणना करने के बजाय, जो 255999997 देगा, यह 253 down 256 नीचे गोल करता है और परिणाम को गुणा करता है।

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

10 k
16 d i o
F423FFD 100 / p
F423F.FD0000000
100 * p
F423FFD.000000000

(8 अंक की सटीकता पर्याप्त होगी क्योंकि आपको दशमलव में 1 decimal 256 का प्रतिनिधित्व करने की आवश्यकता है।


1
यह एक "मनमाना सटीक" कैलकुलेटर के लिए पूरी तरह से अप्रत्याशित परिणाम प्रतीत होगा?
यमिन रॉन्ग

3
यह अभी भी सटीक है जब kसेट किया जाता है: 10 k 16 d i o F423F.FD pF423F.FA, तो मुझे उन्हें उपयोग करने से पहले सभी नंबरों को स्केल करना होगा dc। मूल रूप से उन्हें पहले से पार्स करने के लिए राशि।
यमिन रॉन्ग

2
@ हाँ, दुर्भाग्यवश, dcकेवल एक अंक की संख्या का उपयोग करके अपने इनपुट को मापता है, जो मुझे एक बग की तरह लगता है (चूंकि इनपुट मूलांक का उपयोग करके अंकों की संख्या की गणना की जाती है, लेकिन दशमलव मान पर लागू होता है)।
स्टीफन किट

1
@dhag वह है जो POSIX निर्दिष्ट करता है (के लिए bc, जो dcपर आधारित है): "आंतरिक संगणनाओं को दशमलव में इनपुट संख्या और आउटपुट आधारों की परवाह किए बिना, दशमलव अंकों की निर्दिष्ट संख्या तक ले जाया जाएगा।"
स्टीफन किट

1
यह वास्तव में एक समस्या है कि कैसे एक निरंतर पार्स किया जा रहा है। कोशिश करें 20 k 16 d i o 0.3 1 / p (जो प्रिंट ।19999999999999999)। यह समझें कि ऑपरेशन सिर्फ विभाजित कर रहा 0.2है 1(जो सिद्धांत में मूल्य नहीं बदलना चाहिए)। जबकि 20 k 16 d i o 0.3000 1 / p(सही ढंग से) प्रिंट .30000000000000000। (कंट।)
आइजैक

1

समस्या

समस्या वह तरीका है जिसमें डीसी (और बीसी) संख्यात्मक स्थिरांक को समझते हैं।
उदाहरण के लिए, मान (हेक्स में) 0.3(1 से विभाजित) पास के मूल्य में बदल जाता है0.2

$ dc <<<"20k 16 d i o 0.3 1 / p"
.199999999999999999999999999

वास्तव में, सादा स्थिरांक 0.3भी बदल जाता है:

$ dc <<<"20 k 16 d i o     0.3     p"
.1

ऐसा लगता है कि यह एक अजीब तरीके से है, लेकिन यह (अधिक बाद में) नहीं है।
अधिक शून्य जोड़ने से उत्तर दृष्टिकोण सही मूल्य हो जाता है:

$ dc <<<"20 k 16 d i o     0.30     p"
.2E

$ dc <<<"20 k 16 d i o     0.300     p"
.2FD

$ dc <<<"20 k 16 d i o     0.3000     p"
.3000

अंतिम मान सटीक है और अधिक शून्य शून्य जोड़े जाने पर कोई फर्क नहीं पड़ता।

$ dc <<<"20 k 16 d i o     0.30000000     p"
.3000000

समस्या ई.पू. में भी मौजूद है:

$ bc <<< "scale=20; obase=16; ibase=16;    0.3 / 1"
.19999999999999999

$ bc <<< "scale=20; obase=16; ibase=16;    0.30 / 1"
.2E147AE147AE147AE

$ bc <<< "scale=20; obase=16; ibase=16;    0.300 / 1"
.2FDF3B645A1CAC083

$ bc <<< "scale=20; obase=16; ibase=16;    0.3000 / 1"
.30000000000000000

प्रति बिट एक अंक?

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

$ bc <<<'scale=30;obase=10;ibase=2; 0.101/1; 0.0001110001/1'; echo ".1234567890"
.625000000000000000000000000000
.110351562500000000000000000000
.1234567890

इसके अलावा, 2 ^ (- 10) जैसे फ्लोटिंग पॉइंट नंबर के लिए, जिसमें बाइनरी में केवल एक (सेट) बिट है:

$ bc <<<"scale=20; a=2^-10; obase=2;a; obase=10; a"
.0000000001000000000000000000000000000000000000000000000000000000000
.00097656250000000000

.0000000001दशमलव अंकों .0009765625(10) के रूप में बाइनरी अंकों (10) की समान संख्या है । अन्य आधारों में ऐसा नहीं हो सकता है लेकिन आधार 10 डीसी और बीसी दोनों में संख्याओं का आंतरिक प्रतिनिधित्व है और इसलिए एकमात्र आधार है जिसके बारे में हमें वास्तव में ध्यान रखने की आवश्यकता है।

गणित प्रमाण इस उत्तर के अंत में है।

बीसी स्केल

डॉट के बाद अंकों की संख्या बिल्ट-इन फ़ंक्शन scale()फॉर्म bc के साथ गिनी जा सकती है :

$ bc <<<'obase=16;ibase=16; a=0.FD; scale(a); a; a*100'
2
.FA
FA.E1

जैसा कि दिखाया गया है, निरंतर का प्रतिनिधित्व करने के लिए 2 अंक अपर्याप्त है 0.FD

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

हेक्स फ्लोट में बाइनरी अंक।

जैसा कि ज्ञात है, प्रत्येक हेक्स अंक 4 बिट का उपयोग करता है। इसलिए, दशमलव बिंदु के बाद प्रत्येक हेक्स अंक को 4 बाइनरी अंकों की आवश्यकता होती है, जो ऊपर (विषम?) तथ्य के कारण भी 4 दशमलव अंकों की आवश्यकता होती है।

इसलिए, एक संख्या की तरह 0.FD8 दशमलव अंकों को सही ढंग से दर्शाने की आवश्यकता होगी:

$ bc <<<'obase=10;ibase=16;a=0.FD000000; scale(a);a;a*100'
8
.98828125
253.00000000

शून्य जोड़ें

गणित सीधा है (हेक्स संख्या के लिए):

  • hडॉट के बाद हेक्स अंकों की संख्या ( ) गिनें ।
  • h4 से गुणा करें ।
  • h×4 - h = h × (4-1) = h × 3 = 3×hशून्य जोड़ें ।

शेल कोड में (श के लिए):

a=F423F.FD
h=${a##*.}
h=${#h}
a=$a$(printf '%0*d' $((3*h)) 0)
echo "$a"

echo "obase=16;ibase=16;$a*100" | bc

echo "20 k 16 d i o $a 100 * p" | dc

जो प्रिंट करेगा (सही ढंग से डीसी और बीसी दोनों में):

$  sh ./script
F423F.FD000000
F423FFD.0000000
F423FFD.0000000

आंतरिक रूप से, bc (या dc) आवश्यक अंकों की संख्या को ऊपर की गणना की गई संख्या से मेल कर सकता है ( 3*h) हेक्स फ़्लोट्स को आंतरिक दशमलव प्रतिनिधित्व में बदलने के लिए। या अन्य आधारों के लिए कुछ अन्य कार्य (अंकों की संख्या मानकर आधार 10 (bc और dc का आंतरिक) ऐसे अन्य आधार में) के संबंध में परिमित है। जैसे 2 i (2,4,8,16, ...) और 5,10।

POSIX

पॉज़िक्स विनिर्देश बताता है कि (bc के लिए, जो dc पर आधारित है):

आंतरिक संगणनाएँ तब की जाएंगी जैसे कि दशमलव में, इनपुट अंकों और आउटपुट आधारों की परवाह किए बिना, दशमलव अंकों की निर्दिष्ट संख्या तक।

लेकिन "... दशमलव अंकों की निर्दिष्ट संख्या।" समझा जा सकता है "" संख्यात्मक स्थिर का प्रतिनिधित्व करने के लिए दशमलव अंकों की आवश्यक संख्या "(जैसा कि ऊपर वर्णित है)" दशमलव आंतरिक संगणना "को प्रभावित किए बिना।

इसलिये:

bc <<<'scale=50;obase=16;ibase=16; a=0.FD; a+1'
1.FA

bc वास्तव में ऊपर सेट के रूप में 50 ("दशमलव अंकों की निर्दिष्ट संख्या") का उपयोग नहीं कर रहा है।

केवल तभी विभाजित किया जाता है जब इसे परिवर्तित किया जाता है (फिर भी गलत तरीके से यह 2 के पैमाने का उपयोग करता है 0.FDइसे 50 अंकों में विस्तारित करने से पहले निरंतर पढ़ने के लिए )

$ bc <<<'scale=50;obase=16;ibase=16; a=0.FD/1; a'
.FAE147AE147AE147AE147AE147AE147AE147AE147A

हालांकि, यह सटीक है:

$ bc <<<'scale=50;obase=16;ibase=16; a=0.FD000000/1; a'
.FD0000000000000000000000000000000000000000

फिर से, संख्यात्मक स्ट्रिंग्स (स्थिरांक) को पढ़ना सही संख्या में बिट्स का उपयोग करना चाहिए।


गणित का प्रमाण

दो चरणों में:

एक बाइनरी अंश को / 2 n के रूप में लिखा जा सकता है

एक द्विआधारी अंश दो की नकारात्मक शक्तियों का एक परिमित योग है।

उदाहरण के लिए:

= 0.00110101101 = 
= 0. 0     0      1     1      0      1     0      1      1     0       1

= 0 + 0 × 2 -1 + 0 × 2 -2 + 1 × 2 -3 + 1 × 2 -4 + 0 × 2 -5 + 1 × 2 -6 + 0 × 2 -7 + 1 × 2 -8 + 1 × 2 -9 + 0 × 2 -10 + 1 × 2 -11

= 2 -3 + 2 -4 + 2 -6 + 2 -8 + 2 -9 + 2 -11 = (शून्य हटाकर)

एन बिट्स के एक द्विआधारी अंश में, अंतिम बिट का मान 2 -एन , या 1/2 एन है । इस उदाहरण में: 2 -11 या 1/2 11

= 1/2 3 + 1/2 4 + 1/2 6 + 1/2 8 + 1/2 9 + 1/2 11 = (व्युत्क्रम के साथ)

सामान्य तौर पर, भाजक दो के सकारात्मक अंश घातांक के साथ 2 n हो सकता है । सभी शब्दों को तब एक मान / a 2 n में जोड़ा जा सकता है । इस उदाहरण के लिए:

= 2 8 /2 11 + 2 7 /2 11 + 2 5 /2 11 + 2 3 /2 11 + 2 2 /2 11 + 1/2 11 = (2 के साथ व्यक्त 11 )

= (2 8 + 2 7 + 2 5 + 2 3 + 2 2 + 1) / 2 11 = (निकालने आम कारक)

= (256 + 128 + 32 + 8 + 4 + 1) / 2 11 = (मूल्य में परिवर्तित)

= 429/2 11

प्रत्येक बाइनरी अंश को b / 10 n के रूप में व्यक्त किया जा सकता है

5 n / 5 n से गुणा a / 2 n , (a × 5 n ) / (2 n × 5 n ) = (a × 5 n ) / 10 n = b / 10 n , जहाँ b = a × 5 n । इसके n अंक हैं।

उदाहरण के लिए, हमारे पास:

(429 · 5 11 ) / 10 11 = 20947265625/10 11 = 0.20947265625

यह दिखाया गया है कि प्रत्येक बाइनरी अंश एक दशमलव अंश है जिसमें समान अंकों की संख्या होती है।

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