Unsigned Longs cast as Ints during multiplication

I am having a casting problem with long and unsigned longs getting cast as integer. I have wasted a great deal of time experimenting with the syntax, doing explicit casts, putting things into parentheses… Can someone please tell me the correct syntax to eliminate my casting error?

What I am trying to do is find powers of 2. The built in pow() function uses doubles and I get rounding errors. So I wrote my own iPow() function. But when I try to find 2 to the power of 16 which should be 65536, I get 0 [zero]. Likewise when I try to find 2 to the power of 15 I get -32768 [negative].

Here is my iPow() function as it currently stands. As I said, I have tried all sorts of things with the syntax but can’t seem to find the magic syntax to get the proper results.

unsigned long iPow(int power)
{
  // Integer version of pow() function
  // Used to get powers of 2
  // Because the built in pow() function uses doubles and has rounding errors
  
  unsigned long lOut = 1UL;
  const unsigned long two = 2UL;
  
  for (int iLoop = 1; iLoop <= power; iLoop++)
    {
      lOut *= two;
    }
  return lOut;
}

Here is the entire testbed sketch:

int iMult = 0;
int Pwr = 15;

void setup()
{
  Serial.begin(9600);
  Serial.println("Initialized");
  iMult = iPow(Pwr);
}

void loop()
{
  Serial.print ("The iPow of ");
  Serial.print (Pwr);
  Serial.print (" is ");
  //print_hex(iMult,24);
  Serial.print (iMult);
  Serial.println();
  delay(2000);
}


unsigned long iPow(int power)
{
  // Integer version of pow() function
  // Used to get powers of 2
  // Because the build in pow() function uses doubles and has rounding errors
  
  unsigned long lOut = 1UL;
  const unsigned long two = 2UL;
  
  for (int iLoop = 1; iLoop <= power; iLoop++)
    {
      lOut *= two;
    }
  return lOut;
}

void print_hex(int v, int num_places)
{
  int mask=0, n, num_nibbles, digit;

  for (n=1; n<=num_places; n++)
  {
    mask = (mask << 1) | 0x0001;
  }
  v = v & mask; // truncate v to specified number of places

  num_nibbles = num_places / 4;
  if ((num_places % 4) != 0)
  {
    ++num_nibbles;
  }

  do
  {
    digit = ((v >> (num_nibbles-1) * 4)) & 0x0f;
    Serial.print(digit, HEX);
  } 
  while(--num_nibbles);

} // end print_hex

I know I’m doing something really simple wrong and I just can’t see the forest for the trees!

I don't see the bug in what you have there, but isn't this an easier way to generate powers of two?

unsigned long iPow(int power) {
    return 1<<power;
}

-br

There's nothing wrong with your iPow (except you could probably do it faster with a bit shift operation, see Billroy). But...

int iMult = 0; // this is declared as int, so it will be truncated to the low order bytes (or are they the high order bytes? well you got the idea).

What if you include a function prototype for iPow()?

unsigned long iPow(int);

I'm thinking that without the prototype, the default return type for the function is int.

afremont:
What if you include a function prototype for iPow()?

unsigned long iPow(int);

I'm thinking that without the prototype, the default return type for the function is int.

Especially if you assign it to an int ;).

int iMult = 0;
  iMult = iPow(Pwr);

That is why your unsigned long result is being truncated to a signed integer. You store it in a signed integer.

billroy:
I don’t see the bug in what you have there, but isn’t this an easier way to generate powers of two?

unsigned long iPow(int power) {

return 1<<power;
}

The constant 1 normally has type int, and thus the shift is done as an int. If power is 16 or greater, the result is undefined. What you want is shift a unsigned long long value. Adding a UL suffix to 1 will force the compiler to treat it as unsigned long:

unsigned long iPow(int power) {
    return 1UL<<power;
}

Obviously, you need to store the result in an unsigned long as johnwasser mentions, and do any further calculations involving it as unsigned long to prevent truncation.

If you want to find powers of two, shift 1 bit to the left.

@DrWizard : Please do not cross-post. This wastes time and resources as people attempt to answer your question on multiple threads.

Also don't resurrect old threads and start a new one on the same topic at the same time, thanks.

Your other post deleted.