Problem with simple math code. sqrt() and sq() and the long variable type

I need to do a little bit of math in some code I'm writing.

I simply need to use pythagorem theorem to solve for the magnitude of a side with two other known sides.

x = sqrt( sq(y) + sq(z) );

The largest values I anticipate seeing for my variables of y and z are around 150.

So I wrote some code to test out which variable types I need to use to properly hold my values.

void setup() {

Serial.begin(9600);

}

void loop(){

long x = 0;

x = sqrt(sq(150) + sq(150));

Serial.println(x);

}

In the serial monitor I was getting strange results, not the correct answer.

I then tried to elimnate the square root function to see if I would get the right answer before taking the square root:

void setup() {

Serial.begin(9600);

}

void loop(){

long x = 0;

x = sq(150) + sq(150);

Serial.println(x);

}

This was still giving me strange results. I guess it is some kind of data overflow? I thought a long variable type was supposed to hold up to the value of 2,147,483,647 I'm not even close to that. I should be getting an answer of 45000. If I only do one sq(15) and not the other, I get the correct answer of 22500. Why won't it add them together properly?

Thanks guys!

It looks to the compiler that your expression is all ints and it only casts to long on assignment

try this:

   x = sq(150L) + sq(150L);

Works perfect.

I was not aware that the numbers you are working with must be declared as longs as well.

Thank you!

Unless YOU explicitly indicate otherwise, if the constant is in the range of an "int" then the compiler treats it as an "int". The result of any operation between two "int"s is an "int".

x = sqrt( sq( 150 /* an "int" / ) + sq( 150 / also an "int" */ ));

x = sqrt( ( 150*150 /* an "int" times an "int"; result is an "int" / ) + ( 150*150 / ditto */ ) );

x = sqrt( 22500 /* still an "int" / + 22500 / ditto */ );

x = sqrt( 12232 /* the addition overflowed an "int" so the result is not 45000 */ );

[quote author=Coding Badly link=topic=57057.msg410061#msg410061 date=1301511123] Unless YOU explicitly indicate otherwise, if the constant is in the range of an "int" then the compiler treats it as an "int". [/quote]

Which is annoying and counterintuitive. :P This still trips me up after many years of putting L's after constants...

[quote author=Coding Badly link=topic=57057.msg410061#msg410061 date=1301511123] if the constant is in the range of an "int" then the compiler treats it as an "int". The result of any operation between two "int"s is an "int". [/quote]

Ah-ha! Nice explanation by the way.

  int n=32767;
  int i;
  long l;
  float f;
  i=32767+32767;
  l=32767+32767;
  f=32767+32767;
  Serial.println(n); // "32767"
  Serial.println(i); // "-2"
  Serial.println(l); // "-2"
  Serial.println(f); // "-2.00"

He's right too... :)

if the constant is in the range of an "int" then the compiler treats it as an "int". The result of any operation between two "int"s is an "int".

how about unsigned int versus long?

It would be saver if the compiler used the largest datatype available, however then we have a speed penalty.. :( Or should every const be typecasted (can this be enforced?), so the compiler does not need to guess?

robtillaart:
how about unsigned int versus long?

“long” then “long long”. YOU have to make the literal1 unsigned.

1 Sorry about misusing terminology. In C(++) they are called “literals” not “constants”.

It would be saver if the compiler used the largest datatype available, however then we have a speed penalty… :frowning:

Yup. By design, C(++) compilers are supposed to prefer “int”.

Or should every const be typecasted (can this be enforced?), so the compiler does not need to guess?

My preference is to use named constants as much as possible…

static const long PythagoreanTestValue = 150;
long x = 0;
x = sqrt(sq(PythagoreanTestValue) + sq(PythagoreanTestValue));

Or explicit type-casts…

long x = 0;
x = sqrt(sq((long)150) + sq((long)150));

IBM publishes some very nice C(++) documentation. Even though this is for the AIX compiler, it still applies (I’m too tired to find the matching page for the Linux compiler)…
http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fconref.htm