बिटवाइज़ शिफ्ट और बैश में सबसे बड़ा पूर्णांक


16

यह एक अन्वेषण प्रश्न है, जिसका अर्थ है कि मुझे पूरी तरह से यकीन नहीं है कि यह प्रश्न क्या है, लेकिन मुझे लगता है कि यह बैश में सबसे बड़े पूर्णांक के बारे में है। किसी भी तरह, मैं इसे व्यापक रूप से परिभाषित करूंगा।

$ echo $((1<<8))
256

मैं थोड़ा स्थानांतरित करके एक पूर्णांक बना रहा हूं। मैं कितनी दूर जा सकता हूं?

$ echo $((1<<80000))
1

यह अभी तक नहीं, जाहिरा तौर पर। (1 अप्रत्याशित है, और मैं इसे वापस कर दूँगा।) लेकिन,

$ echo $((1<<1022))
4611686018427387904

अभी भी सकारात्मक है। हालांकि, यह नहीं:

$ echo $((1<<1023))
-9223372036854775808

और एक कदम और आगे बढ़ें,

$ echo $((1<<1024))
1

क्यों 1? और निम्नलिखित क्यों?

$ echo $((1<<1025))
2
$ echo $((1<<1026))
4

क्या कोई इस श्रृंखला का विश्लेषण करना चाहेगा?

अपडेट करें

मेरी मशीन:

$ uname -a
Linux tomas-Latitude-E4200 4.4.0-47-generic #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

-922337203685474780808 = 0xF333333333333334 यह एक मजाकिया दिखने वाला एज केस है। बेशक, 4611686018427387904 = 0x4000000000000000। मुझे लगता है कि आप बिट्स की संख्या पर किसी तरह के रैपराउंड को हिट कर रहे हैं। आप ऐसा क्यों कर रहे हैं, वैसे भी?
एक CVn

6
@ माइकलकॉर्जलिंग मनोरंजन के लिए;

2
@ माइकलकॉर्जलिंग नहीं, यह नहीं है। -922337203685474775808 0x8000000000000000 होगा। जाँच करते समय आपने अंतिम अंक छोड़ दिया: -922337203685477580 0xF333333333333334 होगा।
hvd

जवाबों:


27

बैश अंकगणित के लिए चर का उपयोग करता हैintmax_t । आपके सिस्टम पर ये लंबाई में 64 बिट्स हैं, इसलिए:

$ echo $((1<<62))
4611686018427387904

जो है

100000000000000000000000000000000000000000000000000000000000000

बाइनरी में (1 62 62 के बाद)। फिर से शिफ्ट करें:

$ echo $((1<<63))
-9223372036854775808

जो है

1000000000000000000000000000000000000000000000000000000000000000

बाइनरी में (63 0 एस), दो पूरक अंकगणित में।

सबसे बड़ा प्रतिनिधित्व योग्य पूर्णांक प्राप्त करने के लिए, आपको 1 को घटाना होगा:

$ echo $(((1<<63)-1))
9223372036854775807

जो है

111111111111111111111111111111111111111111111111111111111111111

बाइनरी में।

जैसा कि ilkachachu के जवाब में बताया गया है , शिफ्टिंग 64-बिट x86 सीपीयू (चाहे उपयोग RCLकर रहा हो SHL) पर 64 मोड्यूलो लेता है , जो आपके द्वारा देखे जा रहे व्यवहार की व्याख्या करता है:

$ echo $((1<<64))
1

के बराबर है $((1<<0))। इस प्रकार $((1<<1025))है $((1<<1)), $((1<<1026))है $((1<<2))...

आपको टाइप परिभाषाएँ और अधिकतम मान मिलेंगे stdint.h; आपके सिस्टम पर:

/* Largest integral types.  */
#if __WORDSIZE == 64
typedef long int                intmax_t;
typedef unsigned long int       uintmax_t;
#else
__extension__
typedef long long int           intmax_t;
__extension__
typedef unsigned long long int  uintmax_t;
#endif

/* Minimum for largest signed integral type.  */
# define INTMAX_MIN             (-__INT64_C(9223372036854775807)-1)
/* Maximum for largest signed integral type.  */
# define INTMAX_MAX             (__INT64_C(9223372036854775807))

1
नहीं, आपको उनकी आवश्यकता है, बाइनरी -की तुलना में उच्च पूर्वता है <<
congonglm

1
@cuonglm हुह, मुझे zsh पर परीक्षण के लिए सही काम करता है ... फिर से धन्यवाद!
स्टीफन किट

@cuonglm और स्टीफन। खैर, यह एक अच्छा संपादन है। echo $((1<<63-1))मुझे देता है 4611686018427387904

@tomas yup, bash C ऑपरेटर पूर्ववर्तीता का उपयोग करता है, zsh की अपनी डिफ़ॉल्ट रूप से जहां $((1<<63-1))बराबरी है $(((1<<63)-1))
स्टीफन किट

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

4

2.05b के CHANGESलिए फ़ाइल से bash:

जे। शेल अब लंबे समय के बजाय सबसे बड़े पूर्णांक आकार में मशीन के समर्थन (intmax_t) का अंकगणित करता है।

X86_64 मशीनों intmax_tपर हस्ताक्षर किए गए 64-बिट पूर्णांक से मेल खाती है। तो आप के बीच -2^63और सार्थक मूल्यों को प्राप्त करते हैं 2^63-1। उस सीमा के बाहर आपको सिर्फ रैप-अराउंड मिलता है।


नाइटिक: बीच में -2^63और 2^63-1समावेशी।
नाममात्र पशु

4

1024 से शिफ्टिंग एक देता है, क्योंकि शिफ्ट राशि को प्रभावी ढंग से बिट्स की संख्या (64), इसलिए 1024 === 64 === 0, और लिया जाता है 1025 === 65 === 1

1शिफ्ट के अलावा किसी और चीज को शिफ्ट करना यह स्पष्ट नहीं है कि यह थोड़ा घूमने वाला है, क्योंकि शिफ्ट वैल्यू (कम से कम) 64 होने से पहले उच्च बिट्स कम अंत तक नहीं लपेटते हैं:

$ printf "%x\n" $(( 5 << 63 )) $(( 5 << 64 ))
8000000000000000
5

यह हो सकता है कि यह व्यवहार प्रणाली पर निर्भर करता है। बैश कोड स्टीफन से जुड़ा हुआ शो दाहिने हाथ मूल्य के लिए किसी भी जाँच के बिना सिर्फ एक सादे पाली,। अगर मुझे सही तरीके से याद है, तो x86 प्रोसेसर केवल शिफ्ट वैल्यू (64-बिट मोड) के निचले छह बिट्स का उपयोग करते हैं, इसलिए व्यवहार सीधे मशीन भाषा से हो सकता है। इसके अलावा, मुझे लगता है कि बिट चौड़ाई से अधिक बदलाव से सी या तो स्पष्ट रूप से परिभाषित नहीं होता है ( gccउस के लिए चेतावनी)।


2

थोड़ा सा स्थानांतरण करके पूर्णांक का निर्माण करना। मैं कितनी दूर जा सकता हूं?

जब तक पूर्णांक प्रतिनिधित्व चारों ओर लपेटता है (अधिकांश गोले में डिफ़ॉल्ट)।
64 बिट पूर्णांक आमतौर पर चारों ओर लपेटता है 2**63 - 1
कि 0x7fffffffffffffffया 9223372036854775807में है।

वह संख्या '+1' ऋणात्मक हो जाती है।

वह 1<<63इस प्रकार है:

$ echo "$((1<<62)) $((1<<63)) and $((1<<64))"
4611686018427387904 -9223372036854775808 and 1

उसके बाद प्रक्रिया फिर से दोहराती है।

$((1<<80000)) $((1<<1022)) $((1<<1023)) $((1<<1024)) $((1<<1025)) $((1<<1026))

परिणाम mod 64स्थानांतरण मूल्य [ए] पर निर्भर करता है ।

[a] से: Intel® ६४ और IA-३२ आर्किटेक्चर सॉफ्टवेयर डेवलपर का मैनुअल: वॉल्यूम २ इस गणना को ५ बिट्स (या ६ बिट्स अगर ६४-बिट मोड और REX.W में प्रयोग किया जाता है) के लिए मास्क किया गया है। गिनती सीमा 0 से 31 तक सीमित है (या यदि 64-बिट मोड और REX.W का उपयोग किया जाता है तो 63)।

इसके अलावा: याद रखें कि $((1<<0))है1

$ for i in 80000 1022 1023 1024 1025 1026; do echo "$((i%64)) $((1<<i))"; done
 0 1
62 4611686018427387904
63 -9223372036854775808
 0 1
 1 2
 2 4

तो, यह सब इस बात पर निर्भर करता है कि 64 की संख्या के कितने करीब है।

सीमा का परीक्षण:

परीक्षण का सबसे मजबूत तरीका जो अधिकतम सकारात्मक (और नकारात्मक) पूर्णांक है, प्रत्येक एक बिट को बारी-बारी से परीक्षण करना है। वैसे भी अधिकांश कंप्यूटरों के लिए इसका कम से कम 64 कदम है, यह बहुत धीमा नहीं होगा।

दे घुमा के

पहले हमें फॉर्म के सबसे बड़े पूर्णांक 2^n(शून्य के बाद 1 बिट सेट) की आवश्यकता है। हम यह कर सकते हैं कि अगली पाली तक बाईं ओर शिफ्टिंग करने से संख्या नकारात्मक हो जाती है, जिसे "रैप अराउंड" भी कहा जाता है:

a=1;   while ((a>0));  do ((b=a,a<<=1))  ; done

bपरिणाम कहां है: लूप को विफल करने वाली अंतिम पाली से पहले का मान।

फिर हमें यह पता लगाने के लिए हर कोशिश करने की ज़रूरत है कि कौन से चिन्ह को प्रभावित करते हैं e:

c=$b;d=$b;
while ((c>>=1)); do
      ((e=d+c))
      (( e>0 )) && ((d=e))
done;
intmax=$d

intmaxके अंतिम मान से अधिकतम पूर्णांक ( ) परिणाम है d

नकारात्मक पक्ष पर (कम से कम 0) हम सभी परीक्षणों को दोहराते हैं लेकिन परीक्षण जब थोड़ा सा बनाया जा सकता है तो चारों ओर लपेटे बिना।

सभी चरणों की छपाई के साथ एक संपूर्ण परीक्षा यह है (बैश के लिए):

#!/bin/bash
sayit(){ printf '%020d 0x%016x\n' "$1"{,}; }
a=1;       while ((a>0)) ; do((b=a,a<<=1))              ; sayit "$a"; done
c=$b;d=$b; while((c>>=1)); do((e=d+c));((e>0))&&((d=e)) ; sayit "$d"; done;
intmax=$d
a=-1;      while ((a<0)) ; do((b=a,a<<=1))              ; sayit "$b"; done;
c=$b;d=$b; while ((c<-1)); do((c>>=1,e=d+c));((e<0))&&((d=e)); sayit "$d"; done
intmin=$d       

printf '%20d max positive value 0x%016x\n' "$intmax" "$intmax"
printf '%20d min negative value 0x%016x\n' "$intmin" "$intmin"

लगभग किसी भी शेल में अनुवादित:

#!/bin/sh
printing=false
sayit(){ "$printing" && printf '%020d 0x%016x\n' "$1" "$1"; }
a=1;       while [ "$a" -gt 0  ];do b=$a;a=$((a<<1)); sayit "$a"; done
c=$b;d=$b; while c=$((c>>1)); [ "$c" -gt 0 ];do e=$((d+c)); [ "$e" -gt 0 ] && d=$e ; sayit "$d"; done;
intmax=$d
a=-1;      while [ "$a" -lt 0  ];do b=$a;a=$((a<<1)); sayit "$b"; done;
c=$b;d=$b; while [ "$c" -lt -1 ];do c=$((c>>1));e=$((d+c));[ "$e" -lt 0 ] && d=$e ; sayit "$d"; done
intmin=$d       

printf '%20d max positive value 0x%016x\n' "$intmax" "$intmax"
printf '%20d min negative value 0x%016x\n' "$intmin" "$intmin"

कई गोले के लिए ऊपर चल रहा है,
सभी (bash 2.04 और mksh को छोड़कर) ने 2**63 -1इस कंप्यूटर में ( ) तक के मानों को स्वीकार कर लिया है।

यह दिलचस्प है कि एट शेल की रिपोर्ट करना दिलचस्प है :

$ attsh --version
version         sh (AT&T Research) 93u+ 2012-08-01

के मूल्यों पर एक त्रुटि मुद्रित $((2^63)), हालांकि ksh नहीं।

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