c++ 64 बिट पूर्णांक गुणन का उच्च भाग प्राप्त करना




assembly 64bit (2)

लंबे गुणा ठीक प्रदर्शन होना चाहिए।

स्प्लिट a*b में (hia+loa)*(hib+lob) । यह 4 32 बिट के साथ कुछ बदलावों को बदलता है। उन्हें 64 बिट में करो, और मैन्युअल रूप से किया जाता है, और आपको उच्च भाग मिलेगा

ध्यान दें कि उच्च हिस्से का एक सन्निकटन कम गुणा के साथ किया जा सकता है - सटीक 2 ^ 33 या तो 1 गुणा के साथ, और 1 के साथ 3 बहुभुज।

मुझे नहीं लगता कि पोर्टेबल विकल्प है

इस सवाल का पहले से ही उत्तर दिया गया है:

सी ++ में कहना है कि:

uint64_t i;
uint64_t j;

तब i * j एक uint64_t उत्पन्न करेगा जिसकी कीमत i और j बीच गुणन के निचले हिस्से के रूप में है, अर्थात्, (i * j) mod 2^64 अब, क्या होगा अगर मैं गुणा का उच्च भाग चाहता हूं? मुझे पता है कि एक विधानसभा अनुदेश मौजूद है जैसे कि 32 बिट पूर्णांक का उपयोग करते हुए, लेकिन मैं विधानसभा के साथ बिल्कुल भी परिचित नहीं हूं, इसलिए मैं मदद की उम्मीद कर रहा था।

ऐसा कुछ करने का सबसे कारगर तरीका क्या है:

uint64_t k = mulhi(i, j);

Answer #1

अगर आप जीसीसी और संस्करण का उपयोग कर रहे हैं तो आप 128 बिट संख्याओं को 128 गुणा और ऊपरी 64 बिट निकालने की तुलना में 128 बिट नंबरों का समर्थन कर सकते हैं (परिणामस्वरूप __uint128_t का प्रयोग करके) परिणाम प्राप्त करने का सबसे कारगर तरीका हो सकता है।

यदि आपका कंपाइलर 128 बिट नंबरों का समर्थन नहीं करता है, तो Yakk का उत्तर सही है। हालांकि, सामान्य उपभोग के लिए यह बहुत संक्षिप्त हो सकता है। विशेष रूप से, एक वास्तविक कार्यान्वयन के लिए 64 बिट इंटिगर्स को बहकाव करना चाहिए।

वह सरल और पोर्टेबल समाधान का प्रस्ताव करता है कि प्रत्येक ए और बी को 2 32-बिट नंबरों में तोड़ दिया जाए और फिर उन 32 बिट संख्याओं को 64 बिट गुणा प्रचालन का उपयोग करके गुणा करें। अगर हम लिखते हैं:

uint64_t a_lo = (uint32_t)a;
uint64_t a_hi = a >> 32;
uint64_t b_lo = (uint32_t)b;
uint64_t b_hi = b >> 32;

तो यह स्पष्ट है कि:

a = (a_hi << 32) + a_lo;
b = (b_hi << 32) + b_lo;

तथा:

a * b = ((a_hi << 32) + a_lo) * ((b_hi << 32) + b_lo)
      = ((a_hi * b_hi) << 64) +
        ((a_hi * b_lo) << 32) +
        ((b_hi * a_lo) << 32) +
          a_lo * b_lo

बशर्ते कि गणना 128 बिट (या अधिक) अंकगणितीय का उपयोग कर की जाती है।

लेकिन इस समस्या की आवश्यकता है कि हम 64 बिट अंकगणितीय का उपयोग करते हुए सभी कैलकुलेशन करते हैं, इसलिए हमें अतिप्रवाह के बारे में चिंतित होना होगा।

चूंकि a_hi, a_lo, b_hi और b_lo सभी 32 बिट नंबरों से हस्ताक्षरित हैं, उनका उत्पाद बिना सोचे समझे 64 बिट संख्या में बिना अतिप्रवाह के। हालांकि, ऊपर की गणना के मध्यवर्ती परिणाम नहीं होंगे।

निम्नलिखित कोड मुलि (ए, बी) को क्रियान्वित करेगा, जब गणित को मॉड्यूलो 2 ^ 64:

uint64_t    a_lo = (uint32_t)a;
uint64_t    a_hi = a >> 32;
uint64_t    b_lo = (uint32_t)b;
uint64_t    b_hi = b >> 32;

uint64_t    a_x_b_hi =  a_hi * b_hi;
uint64_t    a_x_b_mid = a_hi * b_lo;
uint64_t    b_x_a_mid = b_hi * a_lo;
uint64_t    a_x_b_lo =  a_lo * b_lo;

uint64_t    carry_bit = ((uint64_t)(uint32_t)a_x_b_mid +
                         (uint64_t)(uint32_t)b_x_a_mid +
                         (a_x_b_lo >> 32) ) >> 32;

uint64_t    multhi = a_x_b_hi +
                     (a_x_b_mid >> 32) + (b_x_a_mid >> 32) +
                     carry_bit;

return multhi;

जैसा कि यक बताता है, अगर आपको ऊपरी 64 बिट में 1 से बंद नहीं किया जाता है, तो आप लेयर बिट की गणना को छोड़ सकते हैं।





multiplication