2013-10-06 13 views
5

अन्य भाषाओं जो 64-बिट पूर्णांक प्रतिनिधित्व कर सकते हैं के लिए, यह बहुत आसानी से ऐसा करना संभव है ...जावास्क्रिप्ट: 20-बिट और 32-बिट पूर्णांक के लिए एक 52-बिट पूर्णांक कन्वर्ट

How to store a 64 bit integer in two 32 bit integers and convert back again

How to store a 64 bit integer in two 32 bit integers in Ruby

// convert 64-bit n to two 32-bit x and y 
x = (n & 0xFFFFFFFF00000000) >> 32 
y = n & 0xFFFFFFFF 

लेकिन जावास्क्रिप्ट 64-बिट पूर्णांकों का प्रतिनिधित्व नहीं कर सकते। बिना किसी समस्या के can only represent 52-bit integers

अब इसका मतलब है कि 64-बिट पूर्णांक को दो 32 बिट पूर्णांक में परिवर्तित करना संभव नहीं है, क्योंकि पहले स्थान पर it is not even possible to have a 64-bit integer है।

लेकिन फिर भी, हमारे पास 52 बिट शेष हैं। मेरा सवाल है: हम दो 32-बिट पूर्णांक (20 उच्च बिट्स और 32 कम बिट्स) में जावास्क्रिप्ट में इस 52-बिट पूर्णांक को कैसे विभाजित कर सकते हैं

क्या कोई 20-बिट और 32-बिट करने के लिए ऊपर की तरह थोड़ा मैनिपुलेशन कोड सुझा सकता है। जावास्क्रिप्ट में बिट विभाजित?

संबंधित: How are 32 bit JavaScript numbers resulting from a bit-wise operation converted back to 64 bit numbers

+0

मुझे यकीन नहीं है कि इसका उपयोग क्या होगा क्योंकि जावास्क्रिप्ट में पूर्णांक नहीं हैं। सभी संख्याएं फ्लोटिंग पॉइंट हैं। –

+0

जेएस में UInt32s है, लेकिन आपको https://github.com/silentmatt/javascript-biginteger – dandavis

+0

@MikeW वास्तव में मुझे 32-बिट्स से अधिक बिट फ़ील्ड के साथ काम करने की आवश्यकता है। इसलिए मुझे किसी दिए गए नंबर को इस तरह से विभाजित करने की आवश्यकता है। – treecoder

उत्तर

11

इससे पहले कि हम शुरू

सबसे पहले, अपने link बताते हुए में एक छोटी सी अशुद्धि जिसमें "कोई भी पूरी संख्या कम से कम 2 [...] होगा सुरक्षित रूप से एक जावास्क्रिप्ट संख्या में फिट।" हालांकि तकनीकी रूप से सही, यह एक तंग बाध्य नहीं है: इसे बिना किसी परेशानी के सत्यापित किया जा सकता है कि जावास्क्रिप्ट संख्या 2 सकारात्मक प्रतिक्रिया पूर्णांक को 2 तक स्टोर कर सकती है (लेकिन 2 +1 नहीं)।

कुछ कोड

आगे की हलचल के बिना, कार्यों का अनुरोध आपने किया है, नीचे 32 बिट और 20 शीर्ष बिट्स में 52-बिट नंबर बंटवारे:

function to_int52(hi, lo) { 
    /* range checking */ 
    if ((lo !== lo|0) && (lo !== (lo|0)+4294967296)) 
     throw new Error ("lo out of range: "+lo); 
    if (hi !== hi|0 && hi >= 1048576) 
     throw new Error ("hi out of range: "+hi); 

    if (lo < 0) 
    lo += 4294967296; 

    return hi * 4294967296 + lo; 
} 

function from_int52(i) { 
    var lo = i | 0; 
    if (lo < 0) 
    lo += 4294967296; 

    var hi = i - lo; 
    hi /= 4294967296; 
    if ((hi < 0) || (hi >= 1048576) 
     throw new Error ("not an int52: "+i); 
    return { lo: lo, hi: hi }; 
} 

कहाँ विभाजित करने के लिए

मैं हालांकि इन का उपयोग करने का सुझाव नहीं देंगे। जावास्क्रिप्ट bitwise ops हस्ताक्षरित हैं (@ डांडवीस: जेएस में UInt32s नहीं है), और साइन बिट सिरदर्द का कारण बनता है जब हम वास्तव में सकारात्मक मान चाहते हैं। प्लस वी 8 में (हस्ताक्षरित) पूर्णांक के लिए ऑप्टिमाइज़ेशन हैं जिन्हें 31 बिट्स में संग्रहीत किया जा सकता है। इन दो तथ्यों को जोड़कर, आपको 30 से अधिक बिट्स पर विभाजित करना चाहिए, अधिकतम सकारात्मक आकार जो V8 छोटे पूर्णांक ("smi") में फिट होगा।

function int52_30_get(i) { 
    var lo = i & 0x3fffffff; 
    var hi = (i - lo)/0x40000000; 
    return { lo: lo, hi: hi }; 
} 

आप शायद हालांकि वस्तुओं का निर्माण नहीं करना चाहती:

यहाँ 30 कम बिट और 22 उच्च बिट्स संख्या विभाजित करने के लिए कोड है। ये inlined जाना चाहिए (यदि आप वास्तव में सब पर कार्यों के साथ परेशान कर रहा हो):

function int52_30_get_lo(i) { 
    return i & 0x3fffffff; 
} 

function int52_30_get_hi(i) { 
    return (i - (i & 0x3fffffff))/0x40000000; 
} 

और निम्न और उच्च भागों से नंबर बनाने का:

function int52_30_new_safe(hi, lo) { 
    return (hi & 0x3fffff) * 0x40000000 + (lo & 0x3fffffff); 
} 

तुम सच में यकीन है कि हाय कर रहे हैं

function int52_30_new(hi, lo) { 
    return hi * 0x40000000 + lo; 
} 

सेट व्यक्तिगत रूप से उच्च और निम्न भागों:

और लो आप मास्किंग को छोड़ सकते हैं श्रेणी में हैं

आप यह सुनिश्चित करें कि हाय और लो श्रेणी में हैं कर रहे हैं: (। इन कार्यों के कारण वे i को संशोधित नहीं कर रहे हैं)

/* set high part of i to hi */ 
i = hi * 0x40000000 + (i & 0x3fffffff); 

/* set low part of i to lo */ 
i += lo - (i & 0x3fffffff); 

अतिरिक्त मस्ती के लिए, एक समारोह मनमाने ढंग से बाहर निकलने के लिए bitfields:

function int52_30_get_bits(i, lsb, nbits) { 
    while (lsb >= 32) { 
     i /= 4294967296; 
     lsb -= 32; 
    } 
    return (i/(1<<lsb)) & ((1<<nbits)-1); 
} 

(nbits होना चाहिए < = 31. विफलता मोड जब nbits 32 दिलचस्प है, औरकी आरएचएस संकार्य का केवल 5 कम बिट्स की वजह से है< महत्वपूर्ण है, x86 आईएसए के साथ जावास्क्रिप्ट स्पेक शेयरों में एक दोष है।)

52 से अधिक बिट्स?

यह से -2 -1 के पूर्णांक के रूप में 53-बिट द्विआधारी संख्या स्टोर करने के लिए संकेत बिट का उपयोग करने के लिए पूरी तरह से संभव है। मैंने यह नहीं किया है लेकिन यह काफी आसान होना चाहिए। उसके बाद यह थोड़ा बालों वाली हो जाती है, और आप अंततः इस तथ्य में भाग लेंगे कि 2 पर जाने से पहले आप गोल करने के लिए पर्याप्त तैरने वाले नहीं हैं (कई नाएन हैं)।एक नाव में पैकिंग 63 बाइनरी अंकों सैद्धांतिक रूप से संभव होना चाहिए, लेकिन पाठक :) के लिए एक व्यायाम के रूप में छोड़ दिया जाता है

अन्य दृष्टिकोण

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

स्ट्रिंग मैनिपुलेशन का सुझाव देने वाले सभी लोग सिर्फ पागल हैं।

+0

इस बहुत विस्तृत उत्तर के लिए धन्यवाद। आप सही हैं कि जेएस वास्तव में 52 + 1 बिट पूर्णांक स्टोर कर सकता है। मुझे मेरा समाधान मिला, इसके लिए धन्यवाद। – treecoder

+0

53 वां बिट छुपा हुआ है, साइन बिट नहीं –

4

वैसे आप यह संख्यानुसार इस तरह कर सकते हैं:

function numeric(n) { 
    return { 
     hi: Math.floor(n/4294967296), 
     lo: (n & 0xFFFFFFFF) >>> 0 
    } 
} 

या स्ट्रिंग संस्करण हो सकता है:

function strings(n) { 
    s = n.toString(16); 

    if (s.length > 8) { 

     return { 
      hi: parseInt(s.toString(16).slice(0, s.length - 8), 16), 
      lo: parseInt(s.toString(16).slice(s.length - 8), 16) 
     } 
    } else { 
     return { hi: 0, lo: n } 
    } 

} 

या हो सकता है ...

function stringPad(n) { 
    s = "00000000000"+n.toString(16); 
    return { 
     hi: parseInt(s.toString(16).slice(0, s.length - 8), 16), 
     lo: parseInt(s.toString(16).slice(s.length - 8), 16) 
    } 
} 

अब, जो तेजी से है। यह पता लगाने के लिए कि मैंने यहां एक टेस्ट बेड सेट किया है: http://jsfiddle.net/SpaceDog/ZTJ2p/ (आप अपने पसंदीदा जेएस प्रोफाइलर का भी उपयोग कर सकते हैं)।

परिणाम (100000 कॉल के लिए):

Function: numeric completed in 146 ms 
Function: strings completed in 379 ms 
Function: stringPad completed in 459 ms 

मैं सोचा तार तेजी से थे, और अगर यह parseInt फोन था आश्चर्य होता है, लेकिन कोई:

Function: stringPadNoParse completed in 386 ms 

अब, इस isn यह बहुत सटीक नहीं है क्योंकि यह कई अन्य चीजों पर निर्भर करता है (फिर से, एक प्रोफाइलर बेहतर हो सकता है) लेकिन ऐसा लगता है कि संख्यात्मक संस्करण तेज है और मैंने इसे परीक्षण करने के लिए कुछ बार चलाया है।

लेकिन शायद कोई आ जाएगा और इसे करने का एक और तरीका प्रदान करेगा।

+0

कोड के लिए धन्यवाद। 'संख्यात्मक()' फ़ंक्शन पूरी तरह से काम करता है। – treecoder

+0

एमबी var hi = n >> 32; ??? – nim

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