# Thread: Trig Functions without math.h

1. ## Trig Functions without math.h

I pose a problem, ladies and gentlemen. I need to do work with vectors on a Vex microcontroller, but the problem is, it doesn't support double or float variables, so using the math.h trig functions is out. Specifically, I need tangent and arctangent (tan and atan). Any way of writing custom functions for these using integers?

Basically, I'm trying to derive the angle and magnitude of the position of a control joystick with the x and y axes. Each axis has an unsigned character range (0-255), and 127 is center. I need to combine the positions of both axes and get the angle of the joystick (such as on a standard coordinate plane) and the distance of the joystick from the center (Pythagorean theorem, not worried about that part). 2. There sure is. As a matter of fact, I wrote a function to calculate cosine a while back, let me see if I can tweak it for tangent, shouldnt be difficult.
I do include the math.h header, but it is only for the constant M_PI, which you could easily define yourself.

Edit: The tangent Maclaurin series is pretty complicated, you could divide sin by cosine. 3. Originally Posted by daltore I pose a problem, ladies and gentlemen. I need to do work with vectors on a Vex microcontroller, but the problem is, it doesn't support double or float variables, so using the math.h trig functions is out. Specifically, I need tangent and arctangent (tan and atan). Any way of writing custom functions for these using integers?

Basically, I'm trying to derive the angle and magnitude of the position of a control joystick with the x and y axes. Each axis has an unsigned character range (0-255), and 127 is center. I need to combine the positions of both axes and get the angle of the joystick (such as on a standard coordinate plane) and the distance of the joystick from the center (Pythagorean theorem, not worried about that part).
If you have the ROM for it, maybe a lookup table combined with interpolation? You could try to compute it using a series expansion with fixed point arithmetic, but I don't think it would be terribly accurate. 4. Originally Posted by carrotcake1029 There sure is. As a matter of fact, I wrote a function to calculate cosine a while back, let me see if I can tweak it for tangent, shouldnt be difficult.
I do include the math.h header, but it is only for the constant M_PI, which you could easily define yourself.

Edit: The tangent Maclaurin series is pretty complicated, you could divide sin by cosine.
This still involves a lot of floating point variables, not to mention the long long function for factorials. Vex is a low-power microcontroller with ONLY character and integer variables.

If you have enough ROM you could try a lookup table...
I don't have enough ROM. I think the limit is something like 4 KB, and that's really pushing it. I'd have to make an instance for 256^2 (2^16) cases. That's a lot of ROM.

Thanks for the suggestion though, I'll look into the Maclaurin series in the future for applications with more memory and processor speed. 5. Originally Posted by daltore I don't have enough ROM. I think the limit is something like 4 KB, and that's really pushing it. I'd have to make an instance for 256^2 (2^16) cases. That's a lot of ROM.
Well, it depends how small you want to make the table and how much interpolation error you can tolerate. Also, for something like arctan which is extremely flat over much of its range, you could approximate quite brutally and still have low absolute error. 6. You could multiply all your integers by 10,000, and after any division, you get 4 decimal places, still in the integer, to round or discard as you please. 7. Interpolation is probably your best bet. You might be surprised at how few points you're able to get away with.
Using a taylor series is going to use a lot of cycles and if I remember correctly, the taylor series for arctan diverges for tan(x) > 1.
---
Just a heads-up to save you some time in case you hadn't realized it yet:
When you use atan(x/y), you lose some information (since -x/y==x/-y). So you're probably going to want to use atan2(x,y), which will let you recover the full 360 degrees of angles. With the regular atan, you are only going to get 180 degrees back. 8. Originally Posted by NeonBlack Just a heads-up to save you some time in case you hadn't realized it yet:
When you use atan(x/y), you lose some information (since -x/y==x/-y). So you're probably going to want to use atan2(x,y), which will let you recover the full 360 degrees of angles. With the regular atan, you are only going to get 180 degrees back.
Yeah, I'm taking Pre-Cal right now, that kind of info yells at me. But that may not actually be a bad thing because of what I'm using this for anyway. I need these vectors because I'm trying to write point-and-shoot driving code for a crab drive base (all 4 wheels of the base swivel in sync). The distance of the joystick from center is proportional to speed, and the angle of the joystick determines where the wheels are pointing. There's a potentiometer that measures where the wheels are, and because of the way it's all set up, the wheels can't swivel 360*, so I need to reverse the direction of their rotation at 180 anyway. Because of the reaction time you need for the crab drive and because there's no way to turn other than strafing, I really don't think a lookup table is the way to go. I think next I'll try law of sines or law of cosines to find the angle or something. Thank you for all the suggestions, though. 9. I would definitely recommend the CORDIC method. It is the algorithm used for producing the results in hardware, as it can be done using entirely integer math. Here are some links:
http://www.voidware.com/cordic.htm
http://en.wikipedia.org/wiki/CORDIC
http://www.andraka.com/cordic.htm 10. 11. Originally Posted by iMalc I would definitely recommend the CORDIC method. It is the algorithm used for producing the results in hardware, as it can be done using entirely integer math.
Yeah, I found a CORDIC library for IFI controllers (of which Vex is a part), and I'm currently testing it.

You could multiply all your integers by 10,000, and after any division, you get 4 decimal places, still in the integer, to round or discard as you please.
The problem is not working with the numbers, there are fairly easy ways to deal with those numbers, the main problem is that all of the functions are written in object code as floats. 12. Just an update, I have found a function which closely approximates the arctangent function that can be modified for integers for a precision of about 2 degrees or .01 radians. It uses ratios of x and y subtracted against each other in various arrangements that I can't quite understand at 3:17 AM, but here's the code:

Code:
```int arctan2(int y, int x)
{
int angle, abs_y = y;
if(abs_y<0) abs_y=0-y;

if(x>=0) angle = (45 - (45 * (x - abs_y) / (x + abs_y)));
else if(x<0) angle = (135 - (45 * (x + abs_y) / (abs_y - x)));

if (y < 0) return(360-angle);     // negate if in quad III or IV
else if(y >= 0) return(angle);
}```
Enjoy, it works great. For more precision in the 2nd and 4th quadrants, which apparently have lower precision inherently with this setup, you can use these two lines, respectively:

theta1=0.1963 * ((x + abs_y) / (abs_y - x))^3 - 0.9817 * ((x + abs_y) / (abs_y - x)) + pi/4 (2a)
theta2=0.1963 * ((x - abs_y) / (x + abs_y))^3 - 0.9817 * ((x - abs_y) / (x + abs_y)) + 3*pi/4 (4a)

Please note that the carret (^) is used as an exponent here, not the XOR, and cannot be used as such in the actual program. Also note that these are in radians, not degrees, because the original function was built for radians and I was to lazy to modify the two lines I didn't use. For more details, see the original website:

http://dspguru.com/comp.dsp/tricks/alg/fxdatan2.htm 13. The bits in red can be removed:
Code:
```int arctan2(int y, int x)
{
int angle, abs_y = y;
if(abs_y<0) abs_y=0-y;

if(x>=0) angle = (45 - (45 * (x - abs_y) / (x + abs_y)));
else if(x<0) angle = (135 - (45 * (x + abs_y) / (abs_y - x)));

if (y < 0) return(360-angle);     // negate if in quad III or IV
else if(y >= 0) return(angle);
}``` 14. Originally Posted by daltore Just an update, I have found a function which closely approximates the arctangent function that can be modified for integers for a precision of about 2 degrees or .01 radians. It uses ratios of x and y subtracted against each other in various arrangements that I can't quite understand at 3:17 AM, but here's the code:
That's an extremely coarse rational-linear approximation (as you can tell by noting that the variable 'x' and 'y' don't get raised to any power anywhere). If it works well enough for you, I'd use it -- it's about as simple, small, and fast as you'll get. Popular pages Recent additions atan, tan, tangent, trig, vex 