बैश शेल के लिए तर्क क्या है जो आपको अंकगणित के अतिप्रवाह आदि की चेतावनी नहीं देता है?


9

bashशेल की अंकगणितीय मूल्यांकन क्षमताओं के लिए सीमाएं निर्धारित हैं । शेल अंकगणित लेकिन राज्यों के इस पहलू के बारे में मैनुअल पर्याप्त है :

अति-प्रवाह के लिए कोई जांच नहीं के साथ निश्चित-चौड़ाई के पूर्णांकों में मूल्यांकन किया जाता है, हालांकि 0 से विभाजन फंस जाता है और एक त्रुटि के रूप में चिह्नित किया जाता है। संचालक और उनकी पूर्वता, सहानुभूति और मूल्य C भाषा में समान हैं।

कौन-सी निश्चित-चौड़ाई पूर्णांक यह संदर्भित करता है कि वास्तव में किस डेटा प्रकार का उपयोग किया जाता है (और यह क्यों है, इसकी बारीकियों के बारे में), लेकिन सीमा मूल्य /usr/include/limits.hइस तरह से व्यक्त किया जाता है:

#  if __WORDSIZE == 64
#   define ULONG_MAX     18446744073709551615UL
#  ifdef __USE_ISOC99
#  define LLONG_MAX       9223372036854775807LL
#  define ULLONG_MAX    18446744073709551615ULL

और एक बार जब आप जानते हैं कि, आप इस तरह की स्थिति की पुष्टि कर सकते हैं:

# getconf -a | grep 'long'
LONG_BIT                           64
ULONG_MAX                          18446744073709551615

यह 64 बिट्स पूर्णांक है और यह अंकगणित मूल्यांकन के संदर्भ में सीधे शेल में अनुवाद करता है:

# echo $(((2**63)-1)); echo $((2**63)); echo $(((2**63)+1)); echo $((2**64))
9223372036854775807        //the practical usable limit for your everyday use
-9223372036854775808       //you're that much "away" from 2^64
-9223372036854775807     
0
# echo $((9223372036854775808+9223372036854775807))
-1

तो 2 के बीच 63 और 2 64 -1, आप कितनी दूर ULONG_MAX से दिखावा नकारात्मक पूर्णांक प्राप्त आप कर रहे हैं 1 । जब मूल्यांकन उस सीमा तक पहुँच जाता है और जो कुछ भी आदेश होता है, उससे आगे निकल जाता है, तो आपको कोई चेतावनी नहीं मिलती है और मूल्यांकन का वह भाग 0 पर रीसेट हो जाता है, जो उदाहरण के लिए सही-सहसंयोजी प्रतिपादक जैसे कुछ असामान्य व्यवहार उत्पन्न कर सकता है :

echo $((6**6**6))                      0   // 6^46656 overflows to 0
echo $((6**6**6**6))                   1   // 6^(6^46656) = 6^0 = 1
echo $((6**6**6**6**6))                6   // 6^(6(6^46656)) = 6^(6^0) = 6^1
echo $((6**6**6**6**6**6))         46656   // 6^(6^(6^(6^46656))) = 6^6
echo $((6**6**6**6**6**6**6))          0   // = 6^6^6^1 = 0
...

उपयोग करने से sh -c 'command'कुछ भी नहीं बदलता है, इसलिए मुझे यह मानकर चलना होगा कि यह सामान्य और अनुरूप आउटपुट है। अब जब मुझे लगता है कि मेरे पास अंकगणितीय सीमा और सीमा की एक बुनियादी लेकिन ठोस समझ है और अभिव्यक्ति के मूल्यांकन के लिए शेल में इसका क्या मतलब है, तो मैंने सोचा कि मैं लिनक्स डेटा के अन्य सॉफ्टवेयरों के डेटा को किस प्रकार देख सकता हूं। मैंने bashइस कमांड के इनपुट को पूरक करने के लिए कुछ स्रोतों का उपयोग किया :

{ shopt -s globstar; for i in /path/to/source_bash-4.2/include/**/*.h /usr/include/**/*.h; do grep -HE '\b(([UL])|(UL)|())LONG|\bFLOAT|\bDOUBLE|\bINT' $i; done; } | grep -iE 'bash.*max'

bash-4.2/include/typemax.h:#    define LLONG_MAX   TYPE_MAXIMUM(long long int)
bash-4.2/include/typemax.h:#    define ULLONG_MAX  TYPE_MAXIMUM(unsigned long long int)
bash-4.2/include/typemax.h:#    define INT_MAX     TYPE_MAXIMUM(int)

वहाँ के साथ और अधिक उत्पादन है ifबयानों और मैं की तरह एक आदेश के लिए खोज सकते awkभी आदि मैं नियमित अभिव्यक्ति मैं इस्तेमाल किया मनमाना परिशुद्धता उपकरण जैसे मैं के बारे में कुछ भी पकड़ नहीं कर रहा है bcऔर dc


प्रशन

  1. आपको चेतावनी न देने का औचित्य क्या है (जैसे awk2 ^ 1024 का मूल्यांकन करते समय) जब आपके अंकगणितीय मूल्यांकन ओवरफ्लो होते हैं? 2 63 और 2 64 -1 के बीच नकारात्मक पूर्णांक अंतिम उपयोगकर्ता के सामने क्यों आते हैं, जब वह किसी चीज का मूल्यांकन कर रहा होता है?
  2. मैंने कहीं पढ़ा है कि UNIX का कुछ स्वाद ULONG_MAX को अंतःक्रियात्मक रूप से बदल सकता है? क्या किसी ने इस बारे में सुना है?
  3. यदि कोई अनियंत्रित पूर्णांक के मान को अधिकतम रूप से बदलता है limits.h, तो recompiles bash, हम क्या उम्मीद कर सकते हैं?

ध्यान दें

1. मैं और अधिक स्पष्ट रूप से वर्णन करना चाहता था कि मैंने क्या देखा, क्योंकि यह बहुत ही सरल अनुभवजन्य सामान है। मैंने देखा है कि:

  • (ए) कोई भी मूल्यांकन जो <२ ^ ६३-१ देता है वह सही है
  • (b) कोई भी मूल्यांकन जो => २ ^ ६३ से २ ^ ६४ देता है एक नकारात्मक पूर्णांक देता है:
    • उस पूर्णांक की सीमा x से y है। x = -922337203685474780808 और y = 0।

इसे देखते हुए, एक मूल्यांकन जो (बी) 2 ^ 63-1 के रूप में व्यक्त किया जा सकता है और x..y के भीतर कुछ है। उदाहरण के लिए अगर हमें सचमुच मूल्यांकन करने के लिए कहा जाता है (2 ^ 63-1) +100 002 (लेकिन (a) की तुलना में कोई संख्या छोटी हो सकती है) तो हमें -9223372036854675807 मिलता है। मैं केवल स्पष्ट अनुमान लगा रहा हूं, लेकिन इसका मतलब यह है कि दो निम्नलिखित भाव हैं:

  • (2 ^ 63-1) + 100 002 और;
  • (2 ^ 63-1) + (LLONG_MAX - {शेल हमें क्या देता है ((2 ^ 63-1) + 100 002), जो कि -9223372036854675807} है;
    • (2 ^ 63-1) + (9223372036854775807 - 9223372036854675807 - 100%)
    • = 922337203685474780807 + 100 000

वास्तव में बहुत करीब हैं। दूसरी अभिव्यक्ति "2" के अलावा (2 ^ 63-1) + 100 002 है, जिसका हम मूल्यांकन कर रहे हैं। इसका मतलब है कि आपके द्वारा नकारात्मक पूर्णांक आपको दिखाते हैं कि आप 2 ^ 64 से कितने दूर हैं। मेरा मतलब है कि उन नकारात्मक पूर्णांकों और सीमाओं के ज्ञान के साथ, अच्छी तरह से आप मूल्यांकन को x..y रेंज में बैश शेल में समाप्त नहीं कर सकते हैं, लेकिन आप कहीं और कर सकते हैं - डेटा उस अर्थ में 2 ^ 64 तक उपयोग करने योग्य है (मैं जोड़ सकता हूं) यह कागज पर है या इसे bc में उपयोग करें)। इसके अलावा कि व्यवहार 6 ^ 6 ^ 6 के समान है, क्योंकि सीमा क्यू में नीचे वर्णित है ...


5
मेरा अनुमान है कि औचित्य "शेल गणित के लिए सही उपकरण नहीं है" को उबालता है। यह इसके लिए डिज़ाइन नहीं किया गया है और जैसा कि आप दिखाते हैं, इसे शान से निपटने का प्रयास नहीं करता है। नर्क, अधिकांश गोले भी झांकियों के साथ सौदा नहीं करते हैं!
terdon

@terdon यद्यपि शेल इस मामले में संख्याओं के साथ व्यवहार करता है, ठीक उसी तरह जैसा कि मैंने कभी सुना है हर उच्च स्तरीय भाषा। पूर्णांक प्रकार एक निश्चित आकार हैं और अतिप्रवाह कर सकते हैं।
गोल्डीलॉक्स

@terdon दरअसल, जैसा कि मैंने 6 ^ 6 ^ 6 टाइमिंग के बाद से इस पर शोध किया, क्यू कि मुझे एहसास हुआ। मुझे इस बात का भी अंदाजा था कि मुझे ज्यादा सामग्री क्यों नहीं मिल रही है क्योंकि सी, या सी 99 के साथ भी ऐसा ही करना था। जैसा कि मैं न तो एक डेवलपर हूं और न ही एक आईटी व्यक्ति हूं, मुझे उन सभी ज्ञान के साथ आना होगा जो इन धारणाओं को पृष्ठभूमि में रखते हैं। निश्चित रूप से किसी ऐसे व्यक्ति की आवश्यकता होती है जिसे डेटा प्रकार के बारे में मनमाने ढंग से सटीकता की आवश्यकता होती है, लेकिन जाहिर है कि मैं वह व्यक्ति नहीं हूं :) (लेकिन मैंने awk के व्यवहार पर ध्यान दिया @ 2 ^ 53 + 1 यानी फ्लोट डबल; बस सटीक और आंतरिक बनाम मुद्रण आदि मेरे से परे है। !)।

1
यदि आप शेल में बड़ी संख्या के साथ काम करना चाहते हैं bc, उदाहरण के लिए $num=$(echo 6^6^6 | bc):। दुर्भाग्य से, bcलाइन ब्रेक में डालता है, इसलिए आपको num=$(echo $num | sed 's/\\\s//g')बाद में करना होगा; यदि आप इसे एक पाइप में करते हैं, तो वास्तविक newline वर्ण हैं, जो कि sed के साथ अजीब हैं, हालांकि num=$(echo 6^6^3 | bc | perl -pne 's/\\\s//g')काम करता है। या तो आपके पास अब एक पूर्णांक है, जिसका उपयोग किया जा सकता है, जैसे num2=$(echo "$num * 2" | bc)
गोल्डीलॉक्स

1
... यहां किसी ने बताया कि आप bcसेटिंग द्वारा इस लाइन ब्रेक सुविधा को अक्षम कर सकते हैं BC_LINE_LENGTH=0
गोल्डीलॉक्स

जवाबों:


11

तो 2 ^ 63 और 2 ^ 64-1 के बीच, आपको नकारात्मक पूर्णांक मिलते हैं जो आपको दिखाते हैं कि आप ULONG_MAX से कितनी दूर हैं।

नहीं। आपको लगता है कि कैसे समझ सकता हूँ? अपने स्वयं के उदाहरण से, अधिकतम है:

> max=$((2**63 - 1)); echo $max
9223372036854775807

यदि "अतिप्रवाह" का अर्थ है "आप नकारात्मक पूर्णांक प्राप्त करते हैं जो आपको दिखा रहा है कि आप ULONG_MAX से कितने दूर हैं", तो यदि हम इसमें एक जोड़ते हैं, तो क्या हमें -1 नहीं मिलना चाहिए? लेकिन बदले:

> echo $(($max + 1))
-9223372036854775808

शायद आपका मतलब है कि यह एक संख्या है जिसे आप $maxनकारात्मक अंतर प्राप्त करने के लिए जोड़ सकते हैं , क्योंकि:

> echo $(($max + 1 + $max))
-1

लेकिन यह वास्तव में सही नहीं है:

> echo $(($max + 2 + $max))
0

ऐसा इसलिए है क्योंकि सिस्टम हस्ताक्षरित पूर्णांकों को लागू करने के लिए दो के पूरक का उपयोग करता है । 1 एक अतिप्रवाह से उत्पन्न मूल्य एक अंतर, एक नकारात्मक अंतर, आदि प्रदान करने का प्रयास नहीं है। यह वस्तुतः किसी मूल्य को सीमित संख्या में बिट्स के रूप में विभाजित करने का परिणाम है, फिर इसे दो के पूरक हस्ताक्षरित पूर्णांक के रूप में व्याख्या किया गया है। । उदाहरण के लिए, कारण $(($max + 1 + $max))-1 के रूप में सामने आता है, क्योंकि दो के पूरक में उच्चतम मूल्य उच्चतम बिट को छोड़कर सभी बिट सेट है (जो नकारात्मक इंगित करता है); मूल रूप से इन्हें एक साथ जोड़ने का मतलब है कि आप सभी बिट्स को बाईं ओर ले जाएं ताकि आप (यदि आकार 16-बिट्स थे, और 64 नहीं)

11111111 11111110

उच्च (साइन) बिट अब सेट किया गया है क्योंकि यह इसके अतिरिक्त है। यदि आप इसमें एक (00000000 00000001) जोड़ते हैं, तो आपके पास सभी बिट सेट हैं , जो दो के पूरक में -1 है।

मुझे लगता है कि आंशिक रूप से आपके पहले प्रश्न के उत्तरार्ध का उत्तर है - "नकारात्मक पूर्णांक क्यों हैं ... अंतिम उपयोगकर्ता के संपर्क में हैं?"। पहला, क्योंकि यह 64-बिट दो के पूरक संख्याओं के नियमों के अनुसार सही मूल्य है। यह अधिकांश (अन्य) सामान्य प्रयोजन के उच्च स्तरीय प्रोग्रामिंग भाषाओं का पारंपरिक अभ्यास है (मैं ऐसा नहीं सोच सकता जो ऐसा नहीं करता है), इसलिए bashसम्मेलन का पालन कर रहा है। जो पहले प्रश्न के पहले भाग का उत्तर भी है - "तर्क क्या है?": यह प्रोग्रामिंग भाषाओं के विनिर्देश में आदर्श है।

दूसरा सवाल WRT, मैंने उन सिस्टम के बारे में नहीं सुना है जो ULONG_MAX को अंतःक्रियात्मक रूप से बदलते हैं।

यदि कोई अनियंत्रित पूर्णांक के मान को सीमा में अधिकतम रूप से बदलता है, तो recompiles बैश, हम क्या उम्मीद कर सकते हैं?

यह कोई फर्क नहीं पड़ता कि अंकगणित कैसे निकलता है, क्योंकि यह एक मनमाना मूल्य नहीं है जो सिस्टम को कॉन्फ़िगर करने के लिए उपयोग किया जाता है - यह एक सुविधा मूल्य है जो हार्डवेयर को प्रतिबिंबित करने वाली एक अपरिवर्तनीय स्थिरांक को संग्रहीत करता है। सादृश्य से, आप सी को 55 मील प्रति घंटे पर फिर से परिभाषित कर सकते हैं , लेकिन प्रकाश की गति अभी भी 186,000 मील प्रति सेकंड होगी। c , ब्रह्मांड को कॉन्फ़िगर करने के लिए उपयोग की जाने वाली संख्या नहीं है - यह ब्रह्मांड की प्रकृति के बारे में कटौती है।

ULONG_MAX बिलकुल समान है। यह एन-बिट संख्याओं की प्रकृति के आधार पर कटौती / गणना की जाती है। इसे बदलना limits.hएक बहुत बुरा विचार होगा यदि उस स्थिरांक का उपयोग कहीं न कहीं यह मान कर किया जाए कि यह प्रणाली की वास्तविकता का प्रतिनिधित्व करने वाला है

और आप अपने हार्डवेयर द्वारा लगाई गई वास्तविकता को नहीं बदल सकते।


1. मुझे नहीं लगता कि यह (पूर्णांक प्रतिनिधित्व का साधन) वास्तव में इसकी गारंटी है bash, क्योंकि यह अंतर्निहित सी लाइब्रेरी पर निर्भर करता है और मानक सी इसकी गारंटी नहीं देता है। हालांकि, यह वही है जो अधिकांश सामान्य आधुनिक कंप्यूटरों पर उपयोग किया जाता है।


मैं बहुत आभारी हूँ! कमरे में हाथी के साथ आने और सोच रहा था। पहले भाग में हाँ यह अधिकतर शब्दों के बारे में है। मैंने अपने क्यू को अपडेट किया है कि मैं क्या मतलब था। मैं शोध करूँगा कि दो के पूरक ने कुछ ऐसा क्यों बताया जो मैंने देखा और आपका उत्तर यह समझने में अमूल्य है! जहां तक ​​UNIX Q का सवाल है, मुझे यहां AIX के साथ ARG_MAX के बारे में कुछ गलत जानकारी देनी चाहिए । चीयर्स!

1
वास्तव में आप मूल्य का निर्धारण करने के लिए दो के पूरक का उपयोग कर सकते हैं यदि आप सुनिश्चित हैं कि आप रेंज> 2 * में हैं $max, जैसा कि आप वर्णन करते हैं। मेरे बिंदु 1 हैं) यह उद्देश्य नहीं है, 2) सुनिश्चित करें कि आप समझते हैं कि क्या आप ऐसा करना चाहते हैं, 3) यह बहुत सीमित प्रयोज्यता के कारण बहुत उपयोगी नहीं है, 4) फुटनोट के अनुसार यह वास्तव में गारंटी नहीं है कि सिस्टम करता है दो के पूरक का उपयोग करें। संक्षेप में, प्रोग्राम कोड में शोषण करने की कोशिश करना एक बहुत ही खराब अभ्यास माना जाएगा। "बड़ी संख्या" पुस्तकालय / मॉड्यूल हैं (POSIX के तहत गोले के लिए bc) , - यदि आपको ज़रूरत है तो उनका उपयोग करें।
गोल्डीलॉक्स

यह केवल हाल ही में मैंने कुछ देखा है जो तेजी से ले जाने वाले आईसी के साथ 4-बिट बाइनरी योजक के साथ ALU को लागू करने के लिए दो के पूरक का लाभ उठाता है; यहां तक ​​कि किसी के पूरक के साथ तुलना भी की गई (यह देखना कि यह बंद कैसे था)। आपका स्पष्टीकरण मुझे नाम देने में सक्षम था और जो मैंने यहां देखा था , उन वीडियो में जो चर्चा की गई थी , उसे बढ़ाते हुए, मौका बढ़ाते हुए मैं वास्तव में लाइन के सभी निहितार्थों को समझ सकता हूं, क्योंकि यह सब उसके बाद फिर से डूब जाता है। चीयर्स!
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.