C/C++ power of two macro

10,450

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 EXPcan 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;
}
Share:
10,450
Ace shinigami
Author by

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, 2022

Comments

  • Ace shinigami
    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:

    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
    PeterT about 8 years
    it's 1<<x isn't it?
  • user207421
    user207421 about 8 years
    OKOK it was a long day. Thanks for the corrections and edit.
  • mindriot
    mindriot about 8 years
    You could even template it so you can use it cleanly for other integer types as well.
  • Humam Helfawi
    Humam Helfawi about 8 years
    Return T rather than int?
  • mindriot
    mindriot about 8 years
    Here'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 if T is a larger type than int (the type of 1)?
  • Jan Hohenheim
    Jan Hohenheim about 8 years
    @mindriot The cast happens implicitly, but I added it to the answer because explicit casts are always preferable
  • mindriot
    mindriot about 8 years
    Just 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
    Jan Hohenheim about 8 years
    @mindriot interesting, seems I didn't test it well enough. Nice job in calling me out!
  • Ace shinigami
    Ace shinigami about 8 years
    does this compromise speed? I am fairly sure this method does not start working before compile time.
  • Jan Hohenheim
    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
    Jonathan Leffler about 8 years
    Note 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), because X >= 32 evaluates to 0 (false) or 1 (true). A negative argument will cause undefined behaviour, as will an argument larger than sizeof(int) * CHAR_BIT.
  • Francis Cugler
    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
    Francis Cugler about 8 years
    Why the down vote? The OP asked for a #define or macro! And this is a power of two macro!
  • Spastika
    Spastika almost 2 years
    Of 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!