Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
- - - - -

Ruby, Manual Trigonometric Algorithm

ruby

  • Please log in to reply
No replies to this topic

#1 RhetoricalRuvim

RhetoricalRuvim

    JavaScript Programmer

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1311 posts
  • Location:C:\Countries\US
  • Programming Language:C, Java, C++, PHP, Python, JavaScript

Posted 27 August 2011 - 10:34 PM

You know how, when you add two vectors that are of the same length, the answer vector always has an angle that is the average of the other two vectors' angles?

And you know how you can scale a vector down to have a magnitude of 1 by dividing both coordinates by its magnitude?

If you don't, think about it a little.

Overview
  • The Unit Circle
  • Finding An Angle
  • Example Program











The Unit Circle
The unit circle has a radius of 1 unit; hence why it's called the unit circle.

Posted Image

As you can see, the X value is the cosine of t and the Y value is the sine of t.











Finding An Angle
Let's say you have two vectors. The vectors both have the same magnitude. You add those two vectors together and get a third vector. Doesn't it make sense that the angle part of the third vector is equal to the average of the angle parts of the first two vectors?

Posted Image

  • a is the sum of p and R.
  • d is 1, since the unit circle has a radius of 1.
  • q is a vector pointing in the same direction as a, but has a magnitude of 1, unlike a, which has a magnitude of m.
  • It would make sense that q is equal to a divided by the magnitude of a.
  • If we can find q, we can find a point - on the unit circle - exactly in between two other points, on the unit circle.

We can use this idea to approximate the cosine and sine of any number.

For the algorithm, we'll need three variables: higher, lower, and now.

The higher can be thought of as point p, the lower can be thought of as point r, and the now can be thought of as point q.

We would have a loop that would find the now and that would check the angle of now. If that angle is greater than the target angle, it'll store the values in now to higher. If that angle is less than the target angle, it'll store the values in now to lower. Otherwise, it'll break from the loop.

Each of the three (higher, lower, now) variables should, however, have three values - the x (cosine), the y (sine), and the t (theta; angle).

So here's the plan for the algorithm:
loop start: 
for the cosine and sine (first two) fields:
now= lower + higher
now /= magnitude(now)

for the angle field (the third one):
now= (higher - lower) / 2 + lower = higher / 2 - lower / 2 + lower =
(lower * 2 + higher - lower) / 2 = (lower * 2 - lower + higher) / 2 =
(lower + higher) / 2

if (angle(now) == target angle) break 
if (angle(now) > target angle) higher= now
if (angle(now) < target angle) lower= now

continue loop 
end of loop: 

cosine= cosine(now)
sine= sine(now)











Example Program

The Code
# Request for user input. 
puts 'Enter the angle, in radians: ' 
angle= gets.chomp.to_f 

# Set the x, y, and a indexes. 
x= 0 
y= 1 
a= 2 

# Initialize the variables. 
higher= [0.0, 1.0, Math::PI / 2] 
now= [0.0, 0.0, 0.0] 
lower= [1.0, 0.0, 0.0] 

while true
	# Figure out the coordinates of the point, on the unit circle, between the higher and lower points. 
	now[x]= lower[x] + higher[x] 
	now[y]= lower[y] + higher[y] 
	magnitude= Math.sqrt( (now[x]**2) + (now[y]**2) ) 
	now[x] /= magnitude 
	now[y] /= magnitude 
	
	# Figure out the angle of that point. 
	now[a]= (lower[a] + higher[a]) / 2 
	
	# If angle equal to target angle, break. 
	if now[a] == angle 
		break 
	end 
	
	# If greater, higher= now. 
	if now[a] > angle 
		higher[x]= now[x] 
		higher[y]= now[y] 
		higher[a]= now[a] 
	end 
	
	# If less, lower= now. 
	if now[a] < angle 
		lower[x]= now[x] 
		lower[y]= now[y] 
		lower[a]= now[a] 
	end 
end

# Output the information. 
puts 'Cosine (' + now[a].to_s + ') = ' + now[x].to_s 
puts 'Sine   (' + now[a].to_s + ') = ' + now[y].to_s 

# Wait for return key press. 
gets

This code only works for values greater than 0 and less than pi/2, but it's possible to modify it to work for other values too.

The Output
Posted Image

(Fullsize Screenshot)











First Tutorial:
Hello World Introduction

Previous Tutorial:
If...Else, For, While
  • 0





Also tagged with one or more of these keywords: ruby

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download