C/C++ power of two macro
Solution 1
Why not do it right and use a function? This even allows us to generate the result at compile time using the powerfull constexpr!
template <class T>
constexpr T pwrtwo(T exponent) {
return (T(1) << exponent);
}
Solution 2
One answer (incorrectly) suggests that the answer should be #define pwrtwo(x) (1 << ((x) - 1)
. However:
1 = 0000 0001 in binary mode
Now, when it's asked for 2 power 5, then
1 << (5-1) ; where x = 5
1 should be shifted 4 time then result will be
0001 0000 ==> 2 power 4
But that's wrong, and that's why the actual answer should be:
#define pwrtwo(x) (1 << (x))
Solution 3
2x is 1 << x
, so:
#define pwrtwo(x) (1 << (x))
Solution 4
This macro will do the job:
#ifndef PWRTWO
#define PWRTWO(EXP) (1 << (EXP))
#endif
However, it would be advisable not to use it unless you limit or cap the range of values that EXP
can be!
Try to input these values into this macro on a machine where the size of an int
is 4 bytes one at a time, try to compile and run, then tell me what happens at each value:
std::cout << PWRTWO(30) << std::endl; // Okay
std::cout << PWRTWO(31) << std::endl; // - value
// In the following cout statement within the macro, do not confuse the
// (x >= 32) as what is actually being passed into the macro as an argument.
// This is just a short hand notation to represent all values >= 32 where the actual
// numerical value would be entered into this macro statement as there is
// no defined variable x here in this context nor any comparison expression being passed to it.
// Compiler Warning C4293 '<<' shift count negative or two big, undefined behavoir
std::cout << PWRTWO(X >= 32) << std::endl; // In most cases on my machine it prints out 0.
//However, since this is undefined behavior, there is no telling what it could or may do on another machine.
EDIT
// Try this for loop to see the actual values being printed out as long as
// the integer value on your machine is 32bit or 4 bytes in size.
std::cout << "Excepted values for 32bit integers" << std::endl;
std::cout << "----------------------------------\n";
for ( int i = 0; i < 31; i++ ) {
std::cout << PWRTWO( i ) << std::endl;
}
std::cout << std::endl;
// Then print out the next one
std::cout << "First value to produce a negative result with int being 32bit." << std::endl;
std::cout << "------------------------------------------\n";
std::cout << PWRTWO( 31 ) << std::endl << std::endl;
// Then print out these as well : compiler warnings
std::cout << "Value Range that generates a compiler error." << std::endl;
std::cout << "-------------------------------------------\n";
for ( int i = 32; i <= 100; i++ ) {
std::cout << PWRTWO( i ) << std::endl;
}
Ace shinigami
By day I am a C high school student; by night an incompetent recreational programmer... wow it's kind of depressing when I phrase it like that.
Updated on June 19, 2022Comments
-
Ace shinigami almost 2 years
I am not as good with my powers of two as I should be so I thought maybe I could
#define
something.Unfortunately I am very inexperienced when it comes to preprocessor directives and I couldn't figure out how to do things like for loops. I looked at:
- http://www.cplusplus.com/doc/tutorial/preprocessor
- https://msdn.microsoft.com/en-us/library/teas0593.aspx
But neither of them have examples of for loops. All I want is to be able to write something like
pwrtwo(5)
instead of using a calculator to figure out that 25 is 32. -
PeterT about 8 yearsit's
1<<x
isn't it? -
user207421 about 8 yearsOKOK it was a long day. Thanks for the corrections and edit.
-
mindriot about 8 yearsYou could even template it so you can use it cleanly for other integer types as well.
-
Humam Helfawi about 8 yearsReturn T rather than int?
-
mindriot about 8 yearsHere's something I'm not sure about: would it be better to write
T(1)
, or does the expression get the type of the right-hand side anyway? I.e., does this behave correctly ifT
is a larger type thanint
(the type of1
)? -
Jan Hohenheim about 8 years@mindriot The cast happens implicitly, but I added it to the answer because explicit casts are always preferable
-
mindriot about 8 yearsJust tested it. You definitely need the explicit cast: ideone.com/z5GGvS - even on 64-bit systems you need it because the
1
is interpreted as a signed integer by default. -
Jan Hohenheim about 8 years@mindriot interesting, seems I didn't test it well enough. Nice job in calling me out!
-
Ace shinigami about 8 yearsdoes this compromise speed? I am fairly sure this method does not start working before compile time.
-
Jan Hohenheim about 8 years@Julian what do you mean by "does not start working before compile time."? My function generates it's result directly into the code of the compiled code. It's application is exactly the same as any #define you would make, it just works faster AND more generally in the background because it's a constexpr and a template
-
Jonathan Leffler about 8 yearsNote that the last sample (
std::cout << PWRTWO(X >= 32) << std::endl;
) will print either 1 or 2 on every machine (assuming X is defined anywhere), becauseX >= 32
evaluates to 0 (false) or 1 (true). A negative argument will cause undefined behaviour, as will an argument larger thansizeof(int) * CHAR_BIT
. -
Francis Cugler about 8 years@JonathanLeffler You misinterpreted my intention of the use of the expression (x >= 32). It is meant to stand for the actual values being entered into the macro such as 32, 33, 34, 35 etc., not the actual expression itself, and on my windows 7 machine it does display 0 in every case >= 32. I apologize about this confusion I will edit and add a comment into the original answer to reflect this
-
Francis Cugler about 8 yearsWhy the down vote? The OP asked for a #define or macro! And this is a power of two macro!
-
Spastika almost 2 yearsOf course! I needed something like this for C, so the
constexpr
C++ approach of stackoverflow.com/a/35909762/8800561 doesn't work for me, but this bit-shift approach is perfect. Thanks!