Trouble computing hypotenuse

int xPin = A4;
int yPin = A5;
int xval = 0;
int yval = 0;
int a = 0;
int b = 0;
long c = 0;
long hypo = 0;

void setup()
{
  pinMode (xPin, INPUT);
  pinMode (yPin, INPUT);
  Serial.begin(9600); // also set up Serial port for debugging
}

void loop() {

  xval = analogRead(xPin);
  yval = analogRead(yPin);
  xval = (xval-512);
  yval = (yval-512);
  a = xval;
  b = yval;
  if (xval < 0) {
    a = a*-1;
  }
  if (yval < 0) {
    b = b*-1;
  }
  c=(a*a)+(b*b);
  hypo=(sqrt(c));
  Serial.print(" a=");
  Serial.print(a);
  Serial.print(" b=");
  Serial.print(b);
  Serial.print(" Hypotenuse=");
  Serial.println(hypo);
  delay(1000); 
}

Displaying the results, it is reading X and Y of analog joystick correctly but when I went to computer how far it travelled from center point (around 512, 512), hypotenuse ends up looking funny and in times, negative. Expected result is that hypotenuse is not overly large, about 725 at the highest.

I am using Pythagorean theory to get hypotenuse (x and y as the 2 sides of a right angle triangle) and with a^2+b^2=c^2 so I too x and y and squared it to c. Then square root to get the hypotenuse. But either I missed a step in the math or the math is too large for the 328p to handle. I thought using long would be enough but I think I need something else?

what is the range of numbers you can have in an int?
in an unsigned int?
in a long?
in an unsigned long?
.

Signed long is 2,147,483,647 and unsigned long is over 4 million. a^2+b^2 where a and b is at most about 512 is at most is 524288 so long should have been more than enough without rolling over into neagtive range.

int is signed 16 bit or 32768 at most which is more than enough for reading analog pins and subtracting 512 to set center point of X and Y grid. X are copied to a and Y to b, multiplied by -1 to make it positive if it is a negative number.

a^2+b^2 goes into c which is signed long and then sqrt(c) goes into hypo. Somehow hypo is getting screwed up.

I'm just wondering here but wouldn't it be possible to simplify your code by removing the if statements? I understand you would to eliminate the negative sign but wouldn't the same thing be accomplished in just the single line of code " C = (bb) + (aa)". I'm guessing that probably won't fix the problem you asked about but it will start eliminating possible causes and streamline things.
I believe you may be able to take that thought one step further and do all the math in one calculation with a line of code like this "C =sqrt( (bb) + (aa) );" if I remember correctly it should handle the inner parenthesis first and work it's way out to the square root. If that doesn't help I would put in a debugging print statement around your where you are subtracting 512 from your xval and ensure you are getting the expected numbers there also. You could possibly eliminate a few more lines of code by doing something like "a = (xval -512);", and hopefully making it a bit easier to locate the bug. Maybe something like this would work out, good luck and hopefully i could help out a bit with your project.

int xPin = A4;
int yPin = A5;
int xval = 0;
int yval = 0;
int a = 0;
int b = 0;
long hypo = 0;

void setup(){
  pinMode (xPin, INPUT);
  pinMode (yPin, INPUT);
  Serial.begin(9600); // also set up Serial port for debugging
}

void loop(){
  // reading joy stick input
  xval = analogRead(xPin);
  yval = analogRead(yPin);

  // calculating parameters
  a = (xval-512);
  b = (yval-512);

  // Calculaing Hypotenuse
  hypo = sqrt ( (a*a)+(b*b) );

  // Printing Parameters
  Serial.print(" a=");
  Serial.print(a);
  Serial.print(" b=");
  Serial.print(b);
  Serial.print(" Hypotenuse=");
  Serial.println(hypo);
  delay(1000); 
}

Try making everything long.
OR
Cast to long:
c=((long)aa)+((long)bb);

A rule of thumb - any 2 integers multiplied together will require the sum of their bit widths to hold the result.

On the average Arduino an 'int' is 16-bits. 16-bits time 16-bits gives 32-bit result.

the sum of 2 32 bit number will require one bit more than the width of the largest number. Given that you don't have 33-bit data the result needs to be store in the next largest avail bit-width which is a 'long long' or int64_t, but it isn't because the temp result is treated as an 'int' and much of it goes to the bit bucket appearing as an negative value.

Then you're calling 'sqrt' which takes a 'double' or 64-bit floating point value as input. Fine the the compiler would do the conversion for you if it supported doubles but it doesn't.

'sqrt' then return a 'double' as well but, well it's not supported.

Then on top of that you try to stuff the double returned form 'sqrt' into an 16-bit 'int'.

I may be wrong on some of the above but you get the idea I hope.

ry this -

Serial.println((1023 * 1023));
Serial.println((1023 * 1023) + (1023 * 1023));

But that won't work because 'print' doesn't support anything greater than 32 bits.

wilykat:
int is signed 16 bit or 32768 at most ...

Signed long is 2,147,483,647 and unsigned long is over 4 mbillion

There must be an integer square root function in C floating around somewhere. I wrote one once, in assembly language.