pow() function not behaving as expected

I know this is going to be a really simple, stupid mistake I've made, but for the life of me, I cannot figure it out.

I am trying to make a simple bargraph using a shift register to control the LEDs (yes, I know there's probably a simpler, easier way to do this, but I'm trying to learn the Arduino, electronics and programming, all at the same time, so please be patient with me, OK :slight_smile: ) using the following code

int dataPin = 8;
int clockPin = 9;
int latchPin = 10;

int inputPin = 0;

int readVal = 0;
int outputVal = 0;

void setup()
{
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(latchPin, OUTPUT);

Serial.begin(9600);
}

void loop()
{
readVal = analogRead(inputPin);
readVal = int(readVal / 114); //converts analogRead's 0-1023 range to a 0-8 range
outputVal = pow(2, readVal) - 1; //should convert readVal's 0-8 range to 0, 1, 3, 7, 15 etc.
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, outputVal);
digitalWrite(latchPin, HIGH);
}

But when I start to turn the pot, LED 1 lights, then it goes out while the other LEDs light up (so the output to the shift register goes 0, 1, 2, 6, 14 etc. and not 0, 1, 3, 7, 15 etc.). I have used a simple Serial.print to confirm that readVal is being calculated correctly and have tried switching from int arithmetic to float to see if that makes any difference, but it doesn't. If I write my own function to calculate the powers, it works fine and writing a simple loop

for(x = 0; x < 10; x++) { Serial.println(pow(2, x));}

also works fine.

So, where am I going wrong?

Many thanks,

David Shaw

Check the Reference page - this came up just yesterday or the day before, something about pow() being a float and not an int so some funny rounding can happen.
Did you try the map() function also to see if that would compress into the range you wanted?

I did wonder if it was a rounding problem, which is why I tried changing the variables being used to float, to fit the function expectiong float parameters (the one thing I didn't try was changing outputVal to a double, to fit the function).

map() never even occurred to me though - it would be easier and neater to use it, wouldn't it?

(EDIT - except that it doesn't work :frowning: Still, thanks anyway :slight_smile: )

Many thanks for the suggestion :slight_smile:

David Shaw

It was a simple, stupid mistake.

The function returns a double precision value. I was trying to put it into an int. Changing outputVal to a double fixed it.

It does make me wonder, though. The value returned should fit into an int without problem, which suggests a possible problem in converting from double to int. Ah well, I'm happy now, so I'm not going to worry too much about it :slight_smile:

David Shaw

try this

void loop()
{
  readVal = analogRead(inputPin);
  readVal = int(readVal / 114);      // converts analogRead's 0-1023 range to a 0-8 range
  outputVal = (1 << readVal) - 1;    //  convert readVal's 0-8 range to 0, 1, 3, 7, 15 etc.
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, outputVal);
  digitalWrite(latchPin, HIGH);
}

Works very nicely, thanks - and it saves me nearly 600 bytes :slight_smile:

David Shaw

you can compress the first 3 lines of loop to

void loop()
{
  outputVal = (1 << (analogRead(inputPin)/114)) - 1;