कैसे जांचा जाए कि कोई संख्या 2 की शक्ति है या नहीं


584

आज मुझे जाँच के लिए एक सरल एल्गोरिथ्म की आवश्यकता है यदि कोई संख्या 2 की शक्ति है।

एल्गोरिथ्म होना चाहिए:

  1. सरल
  2. किसी भी ulongमूल्य के लिए सही ।

मैं इस सरल एल्गोरिथ्म के साथ आया:

private bool IsPowerOfTwo(ulong number)
{
    if (number == 0)
        return false;

    for (ulong power = 1; power > 0; power = power << 1)
    {
        // This for loop used shifting for powers of 2, meaning
        // that the value will become 0 after the last shift
        // (from binary 1000...0000 to 0000...0000) then, the 'for'
        // loop will break out.

        if (power == number)
            return true;
        if (power > number)
            return false;
    }
    return false;
}

लेकिन फिर मैंने सोचा, अगर एक बिल्कुल गोल संख्या है तो जांच कैसे की जाए ? लेकिन जब मैंने 2 ^ 63 + 1 के लिए जाँच की, तो राउंडिंग के कारण बिल्कुल 63 ही लौटे। इसलिए मैंने जाँच की कि क्या 2 की शक्ति 63 मूल संख्या के बराबर है - और यह है, क्योंकि गणना एस में की जाती है और सटीक संख्या में नहीं:log2 xMath.Logdouble

private bool IsPowerOfTwo_2(ulong number)
{
    double log = Math.Log(number, 2);
    double pow = Math.Pow(2, Math.Round(log));
    return pow == number;
}

यह trueदिए गए गलत मान के लिए लौटा 9223372036854775809:।

क्या एक बेहतर एल्गोरिथ्म है?


1
मुझे लगता है कि (x & (x - 1))जब Xदो की शक्तियों का योग होता है , तो समाधान गलत सकारात्मक लौट सकता है 8 + 16
जो ब्राउन

32
सभी संख्याओं को दो की शक्तियों के योग के रूप में लिखा जा सकता है, यही कारण है कि हम बाइनरी में किसी भी संख्या का प्रतिनिधित्व कर सकते हैं। इसके अलावा, आपका उदाहरण एक गलत सकारात्मक नहीं है, क्योंकि 11000 और 10111 = 10000! = 0.
vlsd

1
@JoeBrown इसमें कोई झूठी सकारात्मकता नहीं है। वास्तव में अभिव्यक्ति दो की दो शक्तियों में से किसी भी राशि का बड़ा रिटर्न देती है।
सामी बेनचेरी

जवाबों:


1219

इस समस्या के लिए एक सरल चाल है:

bool IsPowerOfTwo(ulong x)
{
    return (x & (x - 1)) == 0;
}

ध्यान दें, यह समारोह रिपोर्ट करेंगे trueके लिए 0, जिनमें से एक शक्ति नहीं है 2। यदि आप इसे बाहर करना चाहते हैं, तो यहां बताया गया है:

bool IsPowerOfTwo(ulong x)
{
    return (x != 0) && ((x & (x - 1)) == 0);
}

व्याख्या

MSDN परिभाषा से बिटवाइंड बाइनरी और ऑपरेटर के लिए सबसे पहले और सबसे महत्वपूर्ण:

बाइनरी एंड ऑपरेटर्स अभिन्न प्रकार और बूल के लिए पूर्वनिर्धारित हैं। अभिन्न प्रकार के लिए, और उसके ऑपरेंड के तार्किक बिटवाइड और गणना करता है। बूल ऑपरेंड के लिए, और उसके ऑपरेंड के तार्किक और गणना करता है; इसका परिणाम यह है कि परिणाम सही है और यदि इसके दोनों ऑपरेंड सत्य हैं तो ही।

अब एक नजर डालते हैं कि यह सब कैसे होता है:

फ़ंक्शन बूलियन (सच्चा / गलत) देता है और इस तरह के अहस्ताक्षरित लंबे (एक्स, इस मामले में) के एक आने वाले पैरामीटर को स्वीकार करता है। हमें सरलता के लिए मान लें कि किसी ने मान 4 पास कर दिया है और फ़ंक्शन को इस तरह बुलाया है:

bool b = IsPowerOfTwo(4)

अब हम x की प्रत्येक घटना को 4 से प्रतिस्थापित करते हैं:

return (4 != 0) && ((4 & (4-1)) == 0);

वैसे हम पहले से ही जानते हैं कि ४! = ० तक सही है, अब तक अच्छा है। लेकिन क्या बारे में:

((4 & (4-1)) == 0)

यह इस पाठ्यक्रम के लिए अनुवाद:

((4 & 3) == 0)

लेकिन वास्तव में क्या है 4&3?

4 का द्विआधारी प्रतिनिधित्व 100 है और 3 का द्विआधारी प्रतिनिधित्व 011 है (याद रखें और इन संख्याओं के द्विआधारी प्रतिनिधित्व को लेता है)। तो हमारे पास:

100 = 4
011 = 3

कल्पना कीजिए कि इन मूल्यों को प्राथमिक जोड़ की तरह ढेर किया जा रहा है। &ऑपरेटर का कहना है कि उसके बाद परिणाम 1 है अगर दोनों मूल्यों 1 के बराबर हैं, अन्यथा यह 0. तो है 1 & 1 = 1, 1 & 0 = 0, 0 & 0 = 0, और 0 & 1 = 0। तो हम गणित करते हैं:

100
011
----
000

परिणाम केवल 0. है, इसलिए हम वापस जाते हैं और देखते हैं कि अब हमारा रिटर्न स्टेटमेंट क्या है:

return (4 != 0) && ((4 & 3) == 0);

जिसका अब अनुवाद है:

return true && (0 == 0);
return true && true;

हम सभी जानते हैं कि true && trueयह सरल है true, और यह दर्शाता है कि हमारे उदाहरण के लिए, 4 2 की शक्ति है।


56
@ क्रिप्प: संख्या बाइनरी फॉर्म 1000 ... 000 की होगी। जब आप -1 करते हैं, तो यह फॉर्म 0111 ... 111 का होगा। इस प्रकार, दो नंबर का बाइनरी और परिणाम होगा 000000। यह नॉन-पॉवर-ऑफ-ट्वॉस के लिए नहीं होगा, क्योंकि 1010100 उदाहरण के लिए 1010011 बन जाएगा, जिसके परिणामस्वरूप (जारी ...)
विन्यासकर्ता

47
... बाइनरी के बाद 1010000 में परिणाम और। केवल झूठी सकारात्मक 0 होगा, यही कारण है कि मैं उपयोग करूंगा: वापसी (x! = 0) && ((x (x - 1)) == 0);
विन्यासकर्ता

6
क्रिप्प, विचार (2: 1, 10: 1) (4: 3, 100: 11) (8: 7, 1000: 111) (16:15, 10000: 1111) पैटर्न देखें?
थॉमस एल होलडे

13
@ शुग्गीकोउक: दो का पूरक है कि नकारात्मक संख्याओं का प्रतिनिधित्व कैसे किया जाता है। चूंकि यह एक अहस्ताक्षरित पूर्णांक है, इसलिए नकारात्मक संख्याओं का प्रतिनिधित्व प्रासंगिक नहीं है। यह तकनीक केवल nonnegative पूर्णांक के द्विआधारी प्रतिनिधित्व पर निर्भर करती है।
ग्रेग हेवगिल

4
@ SapapBox - क्या अधिक सामान्य है? शून्य या गैर-शून्य संख्या जो दो की शक्तियां नहीं हैं? यह एक ऐसा सवाल है जिसका जवाब आप कुछ और संदर्भ के बिना नहीं दे सकते। और यह वास्तव में, वास्तव में वैसे भी कोई फर्क नहीं पड़ता।
विन्यासकर्ता

97

कुछ साइटें जो इस और अन्य बिट्स को हैक करने का दस्तावेज और व्याख्या करती हैं:

और उनमें से grandaddy, पुस्तक "हैकर के डिलाईट" हेनरी वॉरेन, जूनियर द्वारा :

जैसा कि सीन एंडरसन का पृष्ठ बताता है, अभिव्यक्ति ((x & (x - 1)) == 0)गलत तरीके से इंगित करती है कि 0 की शक्ति है। वह उपयोग करने का सुझाव देता है:

(!(x & (x - 1)) && x)

उस समस्या को ठीक करने के लिए।


4
0 2 की शक्ति है ... 2 ^ -inf = 0.;););)
माइकल ब्रे

4
चूँकि यह एक C # टैग किया गया धागा है, यह इंगित करने योग्य है कि अंतिम अभिव्यक्ति (सीन एंडरसन की) C # में अवैध है, क्योंकि !इसे केवल बूलियन प्रकारों पर लागू किया जा सकता है, और &&दोनों ऑपरेंड को बूलियन होने की भी आवश्यकता है - (सिवाय इसके कि उपयोगकर्ता परिभाषित ऑपरेटर) अन्य चीजों को संभव बनाएं, लेकिन यह प्रासंगिक नहीं है ulong।)
जेपी स्टिग नीलसन

40

return (i & -i) == i


2
कोई संकेत क्यों यह काम करेगा या नहीं करेगा? मैंने केवल जावा में इसकी शुद्धता की जाँच की, जहाँ केवल हस्ताक्षरित इन्ट / लोंग हैं। यदि यह सही है, तो यह बेहतर उत्तर होगा। तेज + छोटा
एंड्रियास पीटरसन

7
यह दो-पूरक संकेतन के गुणों में से एक का लाभ उठाता है: एक संख्या के नकारात्मक मूल्य की गणना करने के लिए आप एक बिटवाइज़ नकारात्मक करते हैं और परिणाम में 1 जोड़ते हैं। कम से कम महत्वपूर्ण बिट iसेट किया गया है जो भी सेट किया जाएगा -i। नीचे दिए गए बिट्स 0 (दोनों मानों में) होंगे जबकि इसके ऊपर वाले बिट्स एक दूसरे के संबंध में उलटे होंगे। i & -iइसलिए वसीयत का मूल्य कम से कम महत्वपूर्ण सेट बिट i(जो दो की शक्ति है) होगा। यदि iसमान मूल्य है तो वह एकमात्र बिट सेट था। यह विफल हो जाता है जब i0 उसी कारण से होता i & (i - 1) == 0है जो करता है।
माइकल कार्मन

6
यदि iएक अहस्ताक्षरित प्रकार है, तो टोमोस पूरक का इससे कोई लेना-देना नहीं है। आप केवल मॉड्यूलर अंकगणितीय और बिटवाइज़ और के गुणों का लाभ उठा रहे हैं।
R .. GitHub STOP हेल्पिंग IC

2
यह काम नहीं करता है अगर i==0(रिटर्न (0&0==0)जो है true)। यह होना चाहिएreturn i && ( (i&-i)==i )
bobobobo

22
bool IsPowerOfTwo(ulong x)
{
    return x > 0 && (x & (x - 1)) == 0;
}

3
यह समाधान बेहतर है क्योंकि यह नकारात्मक संख्या से भी निपट सकता है यदि नकारात्मक में पारित करने में सक्षम थे (यदि लंबे समय तक उल्टे के बजाय)
स्टीवन

एक दशमलव इस मामले में दो की शक्ति के रूप में क्यों गुजरता है?
क्रिस फ्रिसिना

21

मैंने इसके बारे में हाल ही में http://www.exploringbinary.com/ten-ways-to-check-if-an-integer-is-a-power-of-two-in-c/ पर एक लेख लिखा था । इसमें बिट काउंटिंग, सही ढंग से लॉगरिदम का उपयोग कैसे किया जाता है, क्लासिक "x &&! (X & x - 1))" चेक, और अन्य शामिल हैं।


17

यहाँ एक सरल सी ++ समाधान है:

bool IsPowerOfTwo( unsigned int i )
{
    return std::bitset<32>(i).count() == 1;
}

8
जीसीसी पर यह एक एकल जीसी बिल्डिन के लिए संकलित है जिसे कहा जाता है __builtin_popcount। दुर्भाग्य से, प्रोसेसर के एक परिवार के पास ऐसा करने के लिए अभी तक एक भी विधानसभा निर्देश नहीं है (x86), इसलिए इसके बजाय यह बिट काउंटिंग के लिए सबसे तेज़ तरीका है। किसी भी अन्य वास्तुकला पर यह एक एकल विधानसभा निर्देश है।
deft_code

3
@deft_code नए x86 माइक्रोआर्किटेक्चर का समर्थनpopcnt
fuclv

13

स्वीकृत उत्तर के लिए निम्नलिखित परिशिष्ट कुछ लोगों के लिए उपयोगी हो सकता है:

दो की एक शक्ति, जब बाइनरी में व्यक्त की जाती है, हमेशा 1 की तरह दिखाई देगी, जिसके बाद n शून्य होगा जहां n 0. से अधिक या उसके बराबर है:

Decimal  Binary
1        1     (1 followed by 0 zero)
2        10    (1 followed by 1 zero)
4        100   (1 followed by 2 zeroes)
8        1000  (1 followed by 3 zeroes)
.        .
.        .
.        .

और इसी तरह।

जब हम 1इस प्रकार की संख्याओं से घटाते हैं , तो वे 0 हो जाते हैं और उसके बाद n फिर से ऊपर के समान होता है। उदाहरण के लिए:

Decimal    Binary
1 - 1 = 0  0    (0 followed by 0 one)
2 - 1 = 1  01   (0 followed by 1 one)
4 - 1 = 3  011  (0 followed by 2 ones)
8 - 1 = 7  0111 (0 followed by 3 ones)
.          .
.          .
.          .

और इसी तरह।

क्रूक्स में आ रहा है

क्या होता है जब हम एक बिटवाइज़ और एक नंबर की x, जो 2 की शक्ति होती है, और x - 1?

इनमें से एक xशून्य के साथ संरेखित हो जाता है x - 1और सभी के शून्य के साथ संरेखित हो जाता xहै x - 1, जिसके परिणामस्वरूप बिटवाइज़ और 0. में परिणाम होता है और इसी तरह से हमारे पास एकल पंक्ति का उत्तर है जिसका उल्लेख सही है।


इसके बाद के संस्करण की स्वीकार किए जाते हैं की सुंदरता के लिए आगे जोड़ने -

इसलिए, अब हमारे पास एक संपत्ति है:

जब हम 1 को किसी भी संख्या से घटाते हैं, तो बाइनरी प्रतिनिधित्व में सबसे सही 1 बन जाएगा 0 और इससे पहले कि सभी शून्य अब 1 हो जाएंगे

इस संपत्ति का एक भयानक उपयोग यह पता लगाने में है - किसी संख्या के बाइनरी प्रतिनिधित्व में कितने 1s मौजूद हैं? एक पूर्णांक के लिए यह करने के लिए छोटा और मीठा कोड xहै:

byte count = 0;
for ( ; x != 0; x &= (x - 1)) count++;
Console.Write("Total ones in the binary representation of x = {0}", count);

संख्याओं का एक और पहलू जो ऊपर वर्णित अवधारणा से सिद्ध किया जा सकता है, "क्या प्रत्येक सकारात्मक संख्या को 2 की शक्तियों के योग के रूप में दर्शाया जा सकता है?"

हां, प्रत्येक सकारात्मक संख्या को 2 की शक्तियों के योग के रूप में दर्शाया जा सकता है। किसी भी संख्या के लिए, उसके द्विआधारी प्रतिनिधित्व को लें। Ex: संख्या लें 117

The binary representation of 117 is 1110101

Because  1110101 = 1000000 + 100000 + 10000 + 0000 + 100 + 00 + 1
we have  117     = 64      + 32     + 16    + 0    + 4   + 0  + 1

@ मरीचि: क्या मैंने कहीं दावा किया कि 0 एक सकारात्मक संख्या है? या 2 की शक्ति?
डिस्प्लेनेम

हां, एक उदाहरण के रूप में 0 डालकर और उस बाइनरी प्रतिनिधित्व के अंदर उस पर गणित बना। यह एक कन्फ्यूजन पैदा करता है।
मिकी

1
यदि दो संख्याओं को जोड़ने से आपको विश्वास हो जाता है कि उन्हें सकारात्मक होना है, तो मैं इसके बारे में कुछ नहीं कर सकता। इसके अलावा, 0 के प्रतिनिधित्व में यह दर्शाने के लिए दिखाया गया है कि 2 की शक्ति को इस संख्या में छोड़ दिया गया है। जो कोई भी बुनियादी गणित जानता है वह जानता है कि 0 जोड़ने का अर्थ है कुछ भी जोड़ना नहीं।
डिस्प्लेनैम

10

प्रश्न पोस्ट करने के बाद मैंने निम्नलिखित समाधान के बारे में सोचा:

हमें यह जांचने की आवश्यकता है कि क्या बाइनरी अंकों में से एक ठीक एक है। इसलिए हम बस संख्या को एक बार में सही एक अंक में बदल देते हैं, और trueयदि यह बराबर होता है तो वापस लौटें । 1. यदि किसी बिंदु पर हम विषम संख्या ( (number & 1) == 1) से आते हैं, तो हमें पता है कि परिणाम क्या है false। यह (बड़े) सच्चे मूल्यों के लिए मूल विधि की तुलना में थोड़ा अधिक (झूठे या छोटे मूल्यों के लिए) बहुत तेजी से साबित हुआ।

private static bool IsPowerOfTwo(ulong number)
{
    while (number != 0)
    {
        if (number == 1)
            return true;

        if ((number & 1) == 1)
            // number is an odd number and not 1 - so it's not a power of two.
            return false;

        number = number >> 1;
    }
    return false;
}

बेशक, ग्रेग का समाधान बहुत बेहतर है।


10
    bool IsPowerOfTwo(int n)
    {
        if (n > 1)
        {
            while (n%2 == 0)
            {
                n >>= 1;
            }
        }
        return n == 1;
    }

और यहां यह पता लगाने के लिए एक सामान्य एल्गोरिथ्म है कि क्या एक संख्या किसी अन्य संख्या की शक्ति है।

    bool IsPowerOf(int n,int b)
    {
        if (n > 1)
        {
            while (n % b == 0)
            {
                n /= b;
            }
        }
        return n == 1;
    }

6
bool isPow2 = ((x & ~(x-1))==x)? !!x : 0;

1
क्या यह है c#? मुझे लगता है कि यह एक बूल के c++रूप xमें लौटा है।
Mariano Desanze

1
मैंने इसे C ++ के रूप में लिखा था। इसे बनाने के लिए C # तुच्छ है: बूल .Pow2 = ((x & ~ (x-1)) == x)? x! = 0: गलत;
abelenky 19

4

पता करें कि क्या दी गई संख्या 2 की शक्ति है।

#include <math.h>

int main(void)
{
    int n,logval,powval;
    printf("Enter a number to find whether it is s power of 2\n");
    scanf("%d",&n);
    logval=log(n)/log(2);
    powval=pow(2,logval);

    if(powval==n)
        printf("The number is a power of 2");
    else
        printf("The number is not a power of 2");

    getch();
    return 0;
}

या, C #: रिटर्न x == मैथ.पो (2, मैथ.लॉग (x, 2)) में;
विन्यासकर्ता

4
टूटा हुआ। प्रमुख फ्लोटिंग पॉइंट राउंडिंग मुद्दों से पीड़ित। का प्रयोग करें frexpबुरा बजाय logसामान आप चल बिन्दु उपयोग करना चाहते हैं।
R .. GitHub STOP की मदद से ICE

4
bool isPowerOfTwo(int x_)
{
  register int bitpos, bitpos2;
  asm ("bsrl %1,%0": "+r" (bitpos):"rm" (x_));
  asm ("bsfl %1,%0": "+r" (bitpos2):"rm" (x_));
  return bitpos > 0 && bitpos == bitpos2;
}

4
int isPowerOfTwo(unsigned int x)
{
    return ((x != 0) && ((x & (~x + 1)) == x));
}

यह वास्तव में तेज है। सभी 2 ^ 32 पूर्णांक की जांच करने में लगभग 6 मिनट और 43 सेकंड लगते हैं।


4
return ((x != 0) && !(x & (x - 1)));

यदि xदो की शक्ति है, तो इसका 1 बिट स्थिति में है n। इसका अर्थ x – 1है कि स्थिति में 0 है n। यह देखने के लिए कि, बाइनरी घटाव कैसे काम करता है, याद करें। जब 1 से घटाना x, उधार स्थिति के लिए सभी तरह से प्रचार करता है n; बिट n0 हो जाता है और सभी निचले बिट्स बन जाते हैं 1. अब, चूंकि x1 बिट्स आम नहीं है x – 1, x & (x – 1)0 है, और !(x & (x – 1))यह सच है।


3

एक संख्या 2 की शक्ति है यदि इसमें केवल 1 सेट बिट है। हम इस संपत्ति और जेनेरिक फ़ंक्शन countSetBitsका उपयोग यह पता लगाने के लिए कर सकते हैं कि कोई संख्या 2 की शक्ति है या नहीं।

यह एक C ++ प्रोग्राम है:

int countSetBits(int n)
{
        int c = 0;
        while(n)
        {
                c += 1;
                n  = n & (n-1);
        }
        return c;
}

bool isPowerOfTwo(int n)
{        
        return (countSetBits(n)==1);
}
int main()
{
    int i, val[] = {0,1,2,3,4,5,15,16,22,32,38,64,70};
    for(i=0; i<sizeof(val)/sizeof(val[0]); i++)
        printf("Num:%d\tSet Bits:%d\t is power of two: %d\n",val[i], countSetBits(val[i]), isPowerOfTwo(val[i]));
    return 0;
}

हमें 0 की पावर होने के लिए स्पष्ट रूप से जांच करने की आवश्यकता नहीं है, क्योंकि यह 0 के लिए भी गलत है।

आउटपुट

Num:0   Set Bits:0   is power of two: 0
Num:1   Set Bits:1   is power of two: 1
Num:2   Set Bits:1   is power of two: 1
Num:3   Set Bits:2   is power of two: 0
Num:4   Set Bits:1   is power of two: 1
Num:5   Set Bits:2   is power of two: 0
Num:15  Set Bits:4   is power of two: 0
Num:16  Set Bits:1   is power of two: 1
Num:22  Set Bits:3   is power of two: 0
Num:32  Set Bits:1   is power of two: 1
Num:38  Set Bits:3   is power of two: 0
Num:64  Set Bits:1   is power of two: 1
Num:70  Set Bits:3   is power of two: 0

एक 'int' के रूप में c लौटते हैं जब फ़ंक्शन में 'ulong' का रिटर्न प्रकार होता है? एक के whileबजाय का उपयोग कर if? मैं व्यक्तिगत रूप से एक कारण नहीं देख सकता, लेकिन यह काम करने लगता है। संपादित करें: - नहीं ... यह 1 से अधिक के लिए कुछ भी लौटाएगा 0!
जेम्स खूर्नी

@JamesKhoury मैं एक c ++ प्रोग्राम लिख रहा था इसलिए मैंने गलती से एक int लौटा दिया। हालांकि यह एक छोटा टाइपो था और एक डाउनवोट के लायक नहीं था। लेकिन मैं आपकी टिप्पणी के बाकी के तर्क को समझने में विफल रहता हूं "अगर इसके बजाय" का उपयोग करते हुए "और" यह 0 से अधिक के लिए 1 लौटाएगा। मैंने आउटपुट को जांचने के लिए मुख्य स्टब को जोड़ा। AFAIK इसकी अपेक्षित उत्पादन। अगर मैं ग़लत हूं तो मेरी गलती सुझाएं।
jerrymouse

3

यहाँ एक और तरीका है जिसे मैंने तैयार किया है, इस मामले में |इसके बजाय का उपयोग कर रहा है &:

bool is_power_of_2(ulong x) {
    if(x ==  (1 << (sizeof(ulong)*8 -1) ) return true;
    return (x > 0) && (x<<1 == (x|(x-1)) +1));
}

क्या आपको (x > 0)यहाँ की आवश्यकता है?
विन्यासकर्ता

@configurator, हाँ, अन्यथा is_power_of_2 (0) सच लौटेगा
चेतन

3

2 की किसी भी शक्ति के लिए, निम्नलिखित भी रखती है।

n & (- एन) == n

नोट: n = 0 के लिए विफल रहता है, इसलिए इसे जांचने की आवश्यकता है
कि यह क्यों काम करता है:
-n n का 2s पूरक है। -n n की तुलना में फ़्लिप किए गए n के सबसे दाहिने सेट बिट के बाईं ओर हर बिट होगा। 2 की शक्तियों के लिए केवल एक सेट बिट है।


2

उदाहरण

0000 0001    Yes
0001 0001    No

कलन विधि

  1. बिट मास्क का उपयोग करके, NUMचर को बाइनरी में विभाजित करें

  2. IF R > 0 AND L > 0: Return FALSE

  3. अन्यथा, NUMवह बन जाता है जो गैर-शून्य है

  4. IF NUM = 1: Return TRUE

  5. अन्यथा, चरण 1 पर जाएं

जटिलता

समय ~ O(log(d))जहां dबाइनरी अंकों की संख्या है


1

बिट्स अंकगणित के बिना @ user134548 के उत्तर में सुधार:

public static bool IsPowerOfTwo(ulong n)
{
    if (n % 2 != 0) return false;  // is odd (can't be power of 2)

    double exp = Math.Log(n, 2);
    if (exp != Math.Floor(exp)) return false;  // if exp is not integer, n can't be power
    return Math.Pow(2, exp) == n;
}

इसके लिए ठीक काम करता है:

IsPowerOfTwo(9223372036854775809)

फ्लोटिंग पॉइंट ऑपरेशंस एक साधारण बिटवाइज़ एक्सप्रेशन की तुलना में धीमे होते हैं
phuclv

1

यदि आपके पास .NET Core 3, System.Runtime.Intrinsics.X86.Popcnt.Popountount है तो मार्क बजरी ने यह सुझाव दिया है

public bool IsPowerOfTwo(uint i)
{
    return Popcnt.PopCount(i) == 1
}

एकल निर्देश, (x != 0) && ((x & (x - 1)) == 0)कम पोर्टेबल से तेज ।


क्या आपको यकीन है कि यह इससे तेज है (x != 0) && ((x & (x - 1)) == 0)? मुझे संदेह है कि, esp। पुराने सिस्टम पर जहां पॉपकॉइन उपलब्ध नहीं है
phuclv

यह तेज नहीं है। मैंने अभी एक आधुनिक इंटेल सीपीयू पर यह परीक्षण किया है और डिस्कसेप में उपयोग किए गए POPCNT को सत्यापित किया है (सी कोड में, .NET नहीं)। POPCNT बिट्स को सामान्य रूप से गिनने के लिए तेज़ है, लेकिन सिंगल-बिट-ऑन केस के लिए बिट टिडलिंग ट्रिक 10% से अधिक तेज़ है।
युगफल

उफ़, मैं इसे वापस लेता हूं। मैं एक लूप में परीक्षण कर रहा था मुझे लगता है कि शाखा की भविष्यवाणी "धोखा" थी। POPCNT वास्तव में एक एकल निर्देश है जो एक एकल घड़ी चक्र में चलता है और यदि आपके पास उपलब्ध है तो तेज है।
युगपुरुष

0

सी में, मैंने i && !(i & (i - 1)ट्रिक का परीक्षण किया और इसके साथ तुलना की __builtin_popcount(i), लिनक्स पर जीसीसी का उपयोग करते हुए, -mpopcnt फ्लैग के साथ सीपीयू के POPCNT निर्देश का उपयोग करना सुनिश्चित किया। मेरा परीक्षण कार्यक्रम 0 और 2 ^ 31 के बीच पूर्णांक के # गिने गए थे जो दो की शक्ति थे।

सबसे पहले मैंने सोचा कि i && !(i & (i - 1)यह 10% तेज था, भले ही मैंने सत्यापित किया कि POPCNT का उपयोग डिस्सैम्ड में किया गया था जहां मैंने उपयोग किया था __builtin_popcount

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

परिणाम:

इंटेल (R) कोर (TM) i7-4771 CPU अधिकतम 3.90GHz

Timing (i & !(i & (i - 1))) trick
30

real    0m13.804s
user    0m13.799s
sys     0m0.000s

Timing POPCNT
30

real    0m11.916s
user    0m11.916s
sys     0m0.000s

AMD Ryzen थ्रेडिपर 2950X 16-कोर प्रोसेसर अधिकतम 3.50GHz

Timing (i && !(i & (i - 1))) trick
30

real    0m13.675s
user    0m13.673s
sys 0m0.000s

Timing POPCNT
30

real    0m13.156s
user    0m13.153s
sys 0m0.000s

ध्यान दें कि यहाँ इंटेल CPU बिट ट्विगलिंग के साथ AMD की तुलना में थोड़ा धीमा लगता है, लेकिन इसमें बहुत तेज़ POPCNT है; AMD POPCNT उतना बढ़ावा नहीं देता है।

popcnt_test.c:

#include "stdio.h"

// Count # of integers that are powers of 2 up to 2^31;
int main() {
  int n;
  for (int z = 0; z < 20; z++){
      n = 0;
      for (unsigned long i = 0; i < 1<<30; i++) {
       #ifdef USE_POPCNT
        n += (__builtin_popcount(i)==1); // Was: if (__builtin_popcount(i) == 1) n++;
       #else
        n += (i && !(i & (i - 1)));  // Was: if (i && !(i & (i - 1))) n++;
       #endif
      }
  }

  printf("%d\n", n);
  return 0;
}

परीक्षण चलाएं:

gcc popcnt_test.c -O3 -o test.exe
gcc popcnt_test.c -O3 -DUSE_POPCNT -mpopcnt -o test-popcnt.exe

echo "Timing (i && !(i & (i - 1))) trick"
time ./test.exe

echo
echo "Timing POPCNT"
time ./test-opt.exe

-1
private static bool IsPowerOfTwo(ulong x)
{
    var l = Math.Log(x, 2);
    return (l == Math.Floor(l));
}

9223372036854775809 नंबर के लिए प्रयास करें। क्या यह काम करता है? मुझे लगता है कि नहीं होगा, क्योंकि गोलाई की गलतियाँ।
विन्यासकर्ता

1
@configurator 92233720368547478080_9_ मेरे लिए 2 की शक्ति की तरह नहीं दिखता है।)
किर्स्टेनस्टाइन

1
@ किर्चस्टीन: उस संख्या ने उसे एक गलत सकारात्मक संकेत दिया।
एरच मिराबल

7
Kirschstein: यह मेरे लिए एक की तरह नहीं दिखता है। हालांकि यह एक कार्य की तरह दिखता है ...
विन्यासकर्ता

-2

जावा में यह प्रोग्राम "सही" है यदि संख्या 2 की शक्ति है और यदि 2 की शक्ति नहीं है तो "गलत" लौटाता है

// To check if the given number is power of 2

import java.util.Scanner;

public class PowerOfTwo {
    int n;
    void solve() {
        while(true) {
//          To eleminate the odd numbers
            if((n%2)!= 0){
                System.out.println("false");
                break;
            }
//  Tracing the number back till 2
            n = n/2;
//  2/2 gives one so condition should be 1
            if(n == 1) {
                System.out.println("true");
                break;
            }
        }
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);
        PowerOfTwo obj = new PowerOfTwo();
        obj.n = in.nextInt();
        obj.solve();
    }

}

OUTPUT : 
34
false

16
true

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