Ten Ways to Check if an Integer Is a Power Of Two in C

Ten Ways to Check if an Integer Is a Power Of Two in C

To write a program to check if an integer is a power of two, you could follow two basic strategies: check the number based on its decimal value, or check it based on its binary representation. The former approach is more human-friendly but generally less efficient; the latter approach is more machine-friendly but generally more efficient. We will explore both approaches, comparing ten different but equivalent C functions.

Decimal-Based Approaches to Checking for Powers of Two

Decimal integers in C source code are converted to binary form, but technically you don’t need to know that; you can still treat them as decimal in the algorithms you write. The first six functions presented are based on that view.

1. Divide by Two

This function implements the “pencil and paper” method of checking whether an integer is a power of two. It repeatedly divides x, the 32-bit unsigned integer being tested, by 2. It divides until either the quotient becomes 1, in which case x is a power of two, or the quotient becomes odd before reaching 1, in which case x is not a power of two.

int isPowerOfTwo (unsigned int x)
{
 while (((x % 2) == 0) && x > 1) /* While x is even and > 1 */
   x /= 2;
 return (x == 1);
}

2. Check All

This function hard codes the first 32 nonnegative powers of two into one `OR’ expression. If x is a power of two less than 2,147,483,648, or 231, the expression will short-circuit according to C-semantics. If x is not a power of two or is 231 , all 32 values will be inspected.

int isPowerOfTwo (unsigned int x)
{
 return (
   x == 1 || x == 2 || x == 4 || x == 8 || x == 16 || x == 32 ||
   x == 64 || x == 128 || x == 256 || x == 512 || x == 1024 ||
   x == 2048 || x == 4096 || x == 8192 || x == 16384 ||
   x == 32768 || x == 65536 || x == 131072 || x == 262144 ||
   x == 524288 || x == 1048576 || x == 2097152 ||
   x == 4194304 || x == 8388608 || x == 16777216 ||
   x == 33554432 || x == 67108864 || x == 134217728 ||
   x == 268435456 || x == 536870912 || x == 1073741824 ||
   x == 2147483648);
}

3. Check Next Power

This function computes each power of two incrementally, quitting when x is less than or equal to the current power of two.

int isPowerOfTwo (unsigned int x)
{
 unsigned int powerOfTwo = 1;

 while (powerOfTwo < x && powerOfTwo < 2147483648)
   powerOfTwo *= 2;
 return (x == powerOfTwo);
}

The hard coded constant for 231 prevents overflowing the 32-bit unsigned integer.

4. Linear Search

This function is the same as the Check Next Power algorithm except that the powers of two are precomputed and stored in a table.

int isPowerOfTwo (unsigned int x)
{  
 unsigned int powersOfTwo[32] = 
   {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,
    65536,131072,262144,524288,1048576,2097152,4194304,8388608,
    16777216,33554432,67108864,134217728,268435456,536870912,
    1073741824,2147483648};

 int exponent = 0;

 while (powersOfTwo[exponent] < x && exponent < 31)
   exponent++;
 return (x == powersOfTwo[exponent]);
}

5. Binary Search

This function does a binary search of powers of two stored in a table.

int isPowerOfTwo (unsigned int x)
{  
 unsigned int powersOfTwo[32] = 
   {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,
    65536,131072,262144,524288,1048576,2097152,4194304,8388608,
    16777216,33554432,67108864,134217728,268435456,536870912,
    1073741824,2147483648};

 unsigned char isAPowerOfTwo;

 int interval = 16;
 int exponent = interval; /* Start out at midpoint */ 
 
 switch (x) {
   case 0:
	isAPowerOfTwo = 0;
        break;
   case 1: /* Special case makes binary search easier */
	isAPowerOfTwo = 1;
	break;
   default:
     while (x != powersOfTwo[exponent] && interval > 1) {
       if (x < powersOfTwo[exponent])
        exponent -= interval/2;
       else
        exponent += interval/2;
       interval /= 2;
     }
     isAPowerOfTwo = x == powersOfTwo[exponent];
 }
 
 return (isAPowerOfTwo);
}

6. Log Search

This function uses logarithms to determine if x is a power of two, put perhaps not in the way you’d expect. The log in base 2 of x, or log2(x), is the exponent n to which 2 is raised to get x. Mathematically, if n is an integer, then x is a power of two; if n is not an integer, then x is not. But in a computer, when floating-point calculations are used, things don’t always work out this neatly (see section“Beware of Logarithms” for more about this.)

In this case, the solution is to choose the two integral exponents that bound the logarithm and compare x to their corresponding powers of two; x can only be a power of two if it matches one of the two.

Since Visual C++ does not have a built-in function for log2(x), a change of base is used to compute it.

int isPowerOfTwo (unsigned int x)
{  
 int exponent = 0;
 unsigned char isAPowerOfTwo;

 unsigned int powersOfTwo[32] = 
   {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,
    65536,131072,262144,524288,1048576,2097152,4194304,8388608,
    16777216,33554432,67108864,134217728,268435456,536870912,
    1073741824,2147483648};

 if (x == 0 || x > 2147483648) 
   isAPowerOfTwo = 0;
 else
   {
    exponent = (int)(log((double)x)/log(2.0)); /* Log base 2 */
    isAPowerOfTwo = (x == powersOfTwo[exponent] ||
                     x == powersOfTwo[exponent+1]);
   }
 return (isAPowerOfTwo);
}

When the exponent is 31, the OR expression will short-circuit before trying to access the table out-of-bounds.

Binary-Based Approaches to Checking for Powers of Two

An arguably more direct way to check if an integer is a power of two is to access its binary representation. An unsigned integer is a power of two if and only if it has exactly one 1 bit. The four functions below are based on that observation.

7. Count Ones

This function is probably the first that comes to mind — counting 1 bits. Of course you don’t need to count all 1 bits; you can stop counting if more than one 1 bit is found.

int isPowerOfTwo (unsigned int x)
{
 unsigned int numberOfOneBits = 0;

 while(x && numberOfOneBits <=1)
   {
    if ((x & 1) == 1) /* Is the least significant bit a 1? */
      numberOfOneBits++;
    x >>= 1;          /* Shift number one bit to the right */
   }

 return (numberOfOneBits == 1); /* 'True' if only one 1 bit */
}

8. Shift Right

This function is the equivalent of the Divide by Two algorithm. Dividing a binary integer by 2 is the same as shifting it right one bit, and checking whether a binary integer is odd is the same as checking if its least significant bit is 1.

int isPowerOfTwo (unsigned int x)
{
 while (((x & 1) == 0) && x > 1) /* While x is even and > 1 */
   x >>= 1;
 return (x == 1);
}

The only way the statement “x == 1” becomes true is when there is only one 1 bit in x to start with.

9. Decrement and Compare

This function is a common one-liner you’ll find on the Web, and is how the check is implemented in malloc.c in the GNU C Library (glibc).

int isPowerOfTwo (unsigned int x)
{
  return ((x != 0) && !(x & (x - 1)));
}

There are two halves to the expression: x != 0 and !(x & (x – 1)). The first half makes 0 a special case, since the second half only works correctly for positive numbers. The second half — the interesting part of the expression — is true when x is a power of two and false when x is not. Let’s see why.

Let n be the position of the leftmost 1 bit if x. If x is a power of two, its lone 1 bit is in position n. This means x – 1 has a 0 in position n. To see why, recall howbinary subtraction works. When subtracting 1 from x, the borrow propagates all the way to position n; bit n becomes 0 and all lower bits become 1. Now, since x has no 1 bits in common with x – 1, x & (x – 1) is 0, and !(x & (x – 1)) is true.

Here are some examples (I’ll use 8-bit unsigned integers to keep things manageable):

Decrement and Compare, when x is a power of two
xx – 1x & (x – 1)
0000000100000000 00000000
0000010000000011 00000000
0001000000001111 00000000

If x is not a power of two, x – 1 has a 1 in position n. This is because the borrow will not propagate to position n. Subtraction borrows from the lowest 1 bit, which by virtue of x not being a power of two, is before position n. The lowest 1 bit is like a firewall that prevents the borrow from reaching position n. Since x and x – 1 have at least one 1 bit in common — at position n — x & (x – 1) is nonzero, and !(x & (x – 1)) is false.

Here are some examples:

Decrement and Compare, when x is a NOT power of two
xx – 1x & (x – 1)
0000001100000010 00000010
0000011000000101 00000100
0000101100001010 00001010
0001110000011011 00011000

10. Complement and Compare

This function is another one-liner that can be found on the Web. At it’s core, it is similar to the Decrement and Compare method.

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

The first half of the expression ensures that x is a positive integer. The second half of the expression, (x & (~x + 1)) == x, is true only when x is a power of two. It compares x with its two’s complement. The two’s complement of x is computed with ~x + 1, which inverts the bits of x and adds 1 (~x + 1 is equivalent to -x, but negation is technically illegal for an unsigned integer).

Let n be the position of the leftmost 1 bit if x. If x is a power of two, its lone 1 bit is in position n. This means ~x has a 0 in position n and 1s everywhere else. When 1 is added to ~x, all positions below n become 0 and the 0 at position n becomes 1. In other words, the carry propagates all the way to position n. So what happens is this: negating x inverts all its bits, but adding 1 inverts them back, from position n on down. So, (x & (~x + 1)) == x is true.

Here are some examples:

Complement and Compare, when x is a power of two
x~x~x + 1x & (~x + 1)
000000011111111011111111 00000001
000001001111101111111100 00000100
000100001110111111110000 00010000

If x is not a power of two, ~x has at least one 0 below position n. When 1 is added, the carry will not propagate to position n. In other words, not all bits from position n and below will be inverted back. This means (x & (~x + 1)) == x is false.

Here are some examples:

Complement and Compare, when x is a NOT power of two
x~x~x + 1x & (~x + 1)
000000111111110011111101 00000001
000001101111100111111010 00000010
000010111111010011110101 00000001
000111001110001111100100 00000100

Endianness

In case you were wondering, these algorithms are endian-independent. Integers are accessed numerically and logically with arithmetic, bitwise, and logical operators, not as byte strings.

Comparing the Algorithms

As for readability, the decimal-based algorithms are more human-friendly. Divide by Two and Check Next Power are methods you might use if you had to check by hand; Check AllLinear SearchBinary Search, and Log Search are methods you might use if you had a table of powers of two to consult. The binary-based algorithms are designed for machines, but if you understand how they work, you’ll appreciate their elegance.

As for performance, the table below shows how the algorithms stack up. I wrote a test case to call each function with all 232 unsigned integer values. I used the Microsoft Visual C++ 2008 Express Edition compiler and ran the program on an Intel Core Duo machine. I repeated the test case three times and computed the average running time for each function.

The algorithms are listed from fastest to slowest. As you might expect, the binary-based functions are generally the fastest.

Running Time to Check All 232 Integers
AlgorithmElapsed Time
No.Name
10Complement and Compare6 minutes, 43 seconds
9Decrement and Compare6 minutes, 51 seconds
8Shift Right7 minutes, 2 seconds
2Check All8 minutes, 42 seconds
7Count Ones10 minutes, 14 seconds
1Divide by Two10 minutes, 44 seconds
3Check Next Power14 minutes, 8 seconds
5Binary Search18 minutes, 17 seconds
6Log Search21 minutes, 58 seconds
4Linear Search26 minutes, 20 seconds

How NOT to Check

Beware of Signed Integers

If you want to check signed integers, you either have to modify the routines above or filter out negative numbers before calling them. As an example, considerDecrement and Compare. If you switched its parameter from unsigned integer to signed integer, it would handle all negative numbers correctly except one: -2,147,483,648. The problem is that in two’s complement, the largest negative integer of any given word size looks like a power of two. In this case, that’s -231, or -2,147,483,648, and it looks like this: 10000000000000000000000000000000. The fix is to change the check “x != 0” to “x > 0”.

Beware of Logarithms

The following code is wrong:

int isPowerOfTwo(unsigned int x)
{
  /* Incorrect way to check */
 double exponent;
 unsigned char isAPowerOfTwo;

 if (x == 0)
   isAPowerOfTwo = 0;
 else
   {
    exponent = log((double)x)/log(2.0); /* Log base 2 */
    isAPowerOfTwo = int(exponent) == exponent;
   }
 return (isAPowerOfTwo);
}

As I hinted in the Log Search algorithm section, the logarithm calculation can return nonintegers when an integer is expected. This is true of the above function, and specifically, for two powers of two: 536,870,912 (2^29) and 2,147,483,648 (2^31). It computes log2(229) as 29.000000000000004, and log2(231) as 31.000000000000004. These are extremely close to, but are not, integers.

You might think you could build in a tolerance so that “close” values are treated as integers. But where do you draw the line? log2(229 + 1) = 29.000000003, and log2(231 + 1) = 31.0000000007. Should those be treated as integers? No!

The solution is to choose the two integral exponents that bound the logarithm and compare x to their corresponding powers of two. That is what we did in section“Log Search”.

Determining Which Power of Two an Integer Is

If you also want to know which power of two an integer is, that is, what its exponent is, the functions above must be modified. The Linear Search and Log Search functions require the least change; they just have to return the computed exponent. The other functions would need to be changed to varying degrees, some to the point where the code would change dramatically.

Summary

I presented ten C functions that showed different ways of checking whether an integer is a power of two. No doubt you could implement them differently, like using macros instead of functions. Beyond that, you could modify them to work for different word sizes. You could also translate them easily to other languages, like PHP, Java, and of course, C++.

The two approaches I discussed should give you more insight into the nature of the powers of two, both as decimal and binary numbers.

Afterword (July 2011)

I wrote this article two and a half years ago, but it recently got a lot of attention on Reddit and Hacker News. Based on that discussion — and the resulting reader comments below — I’d like to make a few additional points.

This article was intended mainly for students, written as if they were given this problem as an assignment. The decimal-based approaches appear first because they are more likely to be understood, and more likely to be what a beginner would come up with on their own. The binary-based approaches are more sophisticated, so appear after the more obvious solutions. There’s no doubt that methods 9 (Decrement and Compare) and 10 (Complement and Compare) are the ones to use in practice — they are short, simple (once you know how they work!), fast, and like all the binary-based methods, independent of integer size.

As some readers pointed out, most of the decimal-based methods have some dependence on the binary representation: the maximum power of two in an unsigned integer (231) must be known. In any case, the point is that the methods use basic mathematical operations — on constants specified in decimal — instead of bit manipulation.

As for the benchmarks, if you use a different compiler — or different compiler options — you’ll get different results. For example, I used debug mode in my tests; when I reran them in release mode (on Visual Studio 2010 Express Edition), they ran much faster. While methods 9 and 10 were still the fastest, some of the other methods switched positions. One difference worth noting is that method 1 (Divide by Two) and method 8 (Shift Right) executed in almost identical times; this makes sense, since they were compiled into virtually identical code by release mode optimizations.

As you’ll see from the Reddit and Hacker News discussions, and from the comments below, there are many more ways to check for powers of two — and many variations (some improved) on the methods I presented. Some of those methods are faster than methods 9 and 10, but they use OS-dependent function calls or inline assembler. I don’t consider them C-based methods.

【转自http://www.exploringbinary.com/ten-ways-to-check-if-an-integer-is-a-power-of-two-in-c/

与编程之美中“求1的数目”那章的一些方法好相似

<think>好的,用户需要一个Java方法来验证密码是否符合规则:至少10个字符,包含至少两位数字以及字母和数字的组合。首先,我需要考虑如何分解这些要求。 首先,密码长度至少10个字符,这可以通过检查字符串长度是否>=10来实现。然后,必须包含至少两位数字。可能需要遍历每个字符,统计数字的数量,或者使用正则表达式来匹配。另外,只能包含字母和数字,不能有其他字符,这点也可以用正则表达式来验证。 用户可能希望一个综合的方法,结合正则表达式和字符检查。正则表达式可以处理整体格式,比如^[a-zA-Z0-9]{10,}$来确保只包含字母数字且长度足够。但单独的正则可能无法直接检查至少两位数字,所以可能需要另外统计数字的数量。 所以,可能的步骤是: 1. 检查长度是否>=10。 2. 检查是否只包含字母和数字。 3. 检查至少有两个数字。 需要将这些步骤整合到一个方法中,返回布尔值。可能需要使用正则表达式来验证字符类型,然后用循环统计数字的数量。 另外,用户可能没有提到是否区分大小写,但问题中只提到字母,所以应该包括大小写字母。同时,必须至少有两个数字,但其他字符可以是字母。 可能的实现方式是: - 使用正则表达式^[a-zA-Z0-9]{10,}$来验证长度和字符类型。 - 遍历每个字符,统计数字出现的次数,如果>=2则符合条件。 需要处理可能的异常,比如输入为null的情况,应该返回false。 现在,将这些逻辑写成Java方法。例如: public static boolean validatePassword(String password) { if (password == null || password.length() < 10) { return false; } if (!password.matches("[a-zA-Z0-9]+")) { return false; } int digitCount = 0; for (char c : password.toCharArray()) { if (Character.isDigit(c)) { digitCount++; } } return digitCount >= 2; } 或者,可以将正则表达式分成两部分:首先检查长度和字符范围,然后检查数字数量。或者使用一个更复杂的正则,但可能难以直接表达至少两个数字的条件,因此分开处理可能更简单。 用户可能希望代码高效且易读,所以分开步骤比较好。此外,正则表达式中的matches方法必须匹配整个字符串,所以应该使用^[a-zA-Z0-9]{10,}$来确保整个字符串符合要求。 另外,用户可能没有考虑到Unicode字符,但问题中明确要求字母和数字,所以假设只处理ASCII字符。 现在测试几个案例: - "abcd1234ef" 长度10,两位数字,符合条件 → true。 - "abcdefghij" 长度10,无数字 → false。 - "a1b2c3d4e5" 长度10,五位数字 → true。 - "1234567890" 长度10,十位数字 → true。 - "abcde$1234" 包含特殊字符$ → false。 - null 或长度9 → false。 这样应该覆盖所有情况。然后,生成相关问题,考虑密码验证的其他方面,如特殊字符要求、大小写要求、性能优化等。</think>### Java密码验证方法实现 需要验证密码字符串满足以下条件: 1. 长度至少10个字符 2. 包含至少2位数字 3. 仅允许字母和数字组合 实现代码: ```java public static boolean validatePassword(String password) { // 基础校验 if (password == null || password.length() < 10) return false; // 字符类型校验(正则表达式) if (!password.matches("^[a-zA-Z0-9]*$")) return false; // 数字数量校验 int digitCount = 0; for (char c : password.toCharArray()) { if (Character.isDigit(c)) digitCount++; } return digitCount >= 2; } ``` ### 方法解析 1. **长度校验**:通过`length()`直接判断字符串长度,时间复杂度$O(1)$ 2. **正则表达式**:`^[a-zA-Z0-9]*$`确保只包含字母和数字[^1] 3. **数字计数**:使用字符遍历统计数字数量,时间复杂度$O(n)$ ### 测试用例 | 输入值 | 预期结果 | 说明 | |----------------|----------|---------------------| | "Abcd1234ef" | true | 符合所有条件 | | "abcdefghij" | false | 缺少数字 | | "Password123" | true | 包含3个数字 | | "123!@#qwe" | false | 包含特殊字符 | | null | false | 空值处理 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值