Arduino/C Programming Question

26 views
Skip to first unread message

ChrisH

unread,
Dec 14, 2012, 9:42:02 AM12/14/12
to milwaukee...@googlegroups.com
I'm working with the pow() function in the Arduino IDE, inside of a for loop.
pow() returns a floating point number, which I'm aware of.
When I hit "pow(2,2)" inside my loop, I get a result of "4.00", which is what I would expect.
However, when I try casting this to an int (such as: Serial.print( (int)pow(2,2)) ), I get an unexpected result: "3".
Why is my cast completely fubar'ing this?  Shouldn't 4.00f become 4 as an int?
Any help muchly appreciated..  This is where I lack, in programming.  Perl has spoiled me! :D

ChrisH

unread,
Dec 14, 2012, 9:44:57 AM12/14/12
to milwaukee...@googlegroups.com
(Whoops -- pow() returns a double, but that's still pretty close to a float, on an Uno, is my understanding...)

Jim Rawson

unread,
Dec 14, 2012, 10:10:13 AM12/14/12
to milwaukee...@googlegroups.com
pow() returns a double? I believe only with 2,2    4,2 =16     6,4 =7776

ChrisH

unread,
Dec 14, 2012, 10:28:30 AM12/14/12
to milwaukee...@googlegroups.com
According to http://arduino.cc/en/Reference/Pow ...

Parameters

base: the number (float)

exponent: the power to which the base is raised (float)

Returns

The result of the exponentiation (double)


I just don't understand why when I cast a double/float value of "4.00" to an int, it suddenly becomes "3".. That's what I need help understanding. :)

Adam Cohen

unread,
Dec 14, 2012, 10:36:28 AM12/14/12
to milwaukee...@googlegroups.com

ChrisH

unread,
Dec 14, 2012, 10:36:31 AM12/14/12
to milwaukee...@googlegroups.com
Here's my code...
  for (int i=0; i<sizeof(IDpins); i++){
    pinMode( IDpins[i], INPUT );      // Configure the pin to be read from.
    digitalWrite( IDpins[i], HIGH );  // Enable weak internal pull-up.
    int pinState=digitalRead( IDpins[i] );
    if ( pinState == LOW ){
      Serial.print("Base 2, Exponent ");
      Serial.print(i);
      Serial.print(" = (int)");
      Serial.print( (int)pow(2, i) );
      Serial.print(" [uncasted]");
      Serial.println( pow(2,i) );
      // Has been pulled down by external jumper.
      BoardID += pow(2, i);
    }

And here's what it's returning:
Base 2, Exponent 0 = (int)1 [uncasted]1.00
Pin 0 State: 0 = Board ID: 1
Base 2, Exponent 1 = (int)2 [uncasted]2.00
Pin 1 State: 0 = Board ID: 3
Base 2, Exponent 2 = (int)3 [uncasted]4.00
Pin 2 State: 0 = Board ID: 6
Base 2, Exponent 3 = (int)7 [uncasted]8.00
Pin 3 State: 0 = Board ID: 13
This is board ID:13

Scott Fradkin

unread,
Dec 14, 2012, 10:40:59 AM12/14/12
to milwaukee...@googlegroups.com
It's probably due to the math being done in 2's complement arithmetic.  Some numbers don't really represent well in binary.  I'm not sure how the power function manipulates the bits behind the scenes, but the representation of 2^2 must be some decimal just less than 4. So, while the answer is 4, in binary the bits a bit less.   When you cast to an int, it's most likely just truncating off bits which then makes the number a 3 since it was 3.99999999999whatever after the power function.

Someone probably knows this much more in depth than I do.

Scott
--
 
 
 

Joseph Bozarth

unread,
Dec 14, 2012, 10:51:29 AM12/14/12
to milwaukee...@googlegroups.com
If it is representing as slightly less that is how it would handle it. You can test this by rounding it and seeing if you get 4. so BoardID += round(pow(2,i));


--
 
 
 



--
Joseph Bozarth

Matt Czapar

unread,
Dec 14, 2012, 10:54:23 AM12/14/12
to milwaukee...@googlegroups.com
Also, if 2 is always going to be your base, shifting a 1 could be easier and quicker than using the pow function.  It's already in int format and there aren't any rounding issues.

1<<2 == 2^2

--
 
 
 

ChrisH

unread,
Dec 14, 2012, 10:57:02 AM12/14/12
to milwaukee...@googlegroups.com
Joseph,
The BoardID+=round(pow(2,i)); did the trick.. 
Holy wow, I'm kind of amazed by this..  
Why pow(2,2) was returning anything other than 4..  It's blowing my mind!
Thanks for the help!
-Chris

ChrisH

unread,
Dec 14, 2012, 11:01:41 AM12/14/12
to milwaukee...@googlegroups.com, matt....@gmail.com
I like this idea, but have no idea how to implement it inside my loop? :)

ChrisH

unread,
Dec 14, 2012, 11:04:52 AM12/14/12
to milwaukee...@googlegroups.com, matt....@gmail.com
I think I got it:
if (pinState == LOW){
  BoardID += 1<<i
}

Thanks for everyone's help!

ChrisH

unread,
Dec 14, 2012, 11:08:14 AM12/14/12
to milwaukee...@googlegroups.com, matt....@gmail.com
Here's the whole chunk, now:
  // Determine the ID of this board.
  for (int i=0; i<sizeof(IDpins); i++){
    pinMode( IDpins[i], INPUT );      // Configure the pin to be read from.
    digitalWrite( IDpins[i], HIGH );  // Enable weak internal pull-up.
    int pinState=digitalRead( IDpins[i] );
    if ( pinState == LOW ) BoardID+=1<<i;  // Add the shifted amount to the board ID. COOL!
  }

Joseph Bozarth

unread,
Dec 14, 2012, 11:22:54 AM12/14/12
to milwaukee...@googlegroups.com
I like that solution. I am not sure why that did not occur to me before. It is nice and clean and it will always be correct with no chance of a rounding error. .Net must be getting to me. I need to go do some Clojure or something tonight.



--
 
 
 

ChrisH

unread,
Dec 14, 2012, 12:15:10 PM12/14/12
to milwaukee...@googlegroups.com
Thanks!
I even cleaned it up a little bit more by not storing the digitalRead() output.

Ed Cramer

unread,
Dec 14, 2012, 7:59:18 PM12/14/12
to milwaukee...@googlegroups.com, matt....@gmail.com
Whoa there - shifting bits results in the multiplication or division of a value by numbers that are powers of two, it doesn't perform exponential/power caclulations.

2 << 3 = 16 ---------- 2 * 2^3 or 2 * 8
4 << 3 = 32 ---------- 4 * 2^3 or 4 * 8


pow(2,3) = 8 --------- 2^3
pow(4,3) = 64 -------- 4^3

-Ed


On Friday, December 14, 2012 9:54:23 AM UTC-6, Matt Czapar wrote:

ChrisH

unread,
Dec 15, 2012, 9:40:55 AM12/15/12
to milwaukee...@googlegroups.com
Ed,
Understood! I originally chose pow() to do my calculations, when bit shifting was really what I was after. :)

Joseph Bozarth

unread,
Dec 15, 2012, 11:24:08 AM12/15/12
to milwaukee...@googlegroups.com

Also, make sure you are not looping too many times. That is a 32-bit signed int (I may be wrong but I am fairly sure it will use a signed bit) meaning that you have 32 bits to work with to represent a number and that the 32nd bit is a flag bit indicating negative. So an example in 8-bits would be:

00010010 = 18
10010010 = -18 (not 146)

Meaning that you only have half the range for positive and half for negative. How all this effects you is that if you try to rotate to the 32nd bit you are not going to get what you expect and if you rotate past that you are going to loop back to 1 (assuming it is rotating and not shifting. If it is shifting then you will just get only zero after you pass the 32nd bit.)

On Dec 15, 2012 8:40 AM, "ChrisH" <hemm...@gmail.com> wrote:
Ed,
Understood! I originally chose pow() to do my calculations, when bit shifting was really what I was after. :)

--



Joseph Bozarth

unread,
Dec 15, 2012, 11:51:10 AM12/15/12
to milwaukee...@googlegroups.com

It could also be doing the 2s compliment in which case you would get a very large negative number and then all zeros.

Ray Scheufler

unread,
Dec 15, 2012, 7:18:44 PM12/15/12
to milwaukee...@googlegroups.com

Most microcontrollers have a rotate and a shift operation. The << and >> operators are shift. An int in c/c++ does not have a standard size. Since the arduino is based on an avr it has an internal data size if 8 bits. Most likely the compiler is setup for 16 bit integers.

An avr is designed around 2's compliment numbers because they make much more sense than sign and magnitude.

Ray Scheufler

--
 
 
 

Joseph Bozarth

unread,
Dec 15, 2012, 8:21:07 PM12/15/12
to milwaukee...@googlegroups.com

Yeah, I realized that about ten minutes later. That will teach me not to post answers within 5 minutes of waking up. But yes. 2s compliment.

--
 
 
 

ChrisH

unread,
Dec 16, 2012, 1:53:21 PM12/16/12
to milwaukee...@googlegroups.com
Great point, Joseph!
I'm only looping through 4 times, so an 'int' should have more than enough space to hold that.  Heck, even a 'byte' would be fine. :)
-Chris
Reply all
Reply to author
Forward
0 new messages