Switch to full style
Understanding the language, error messages, etc.
Post a reply

Decimal to fraction

Tue Mar 24, 2015 1:06 am

Hello everyone,

I am making a game that involves angles, and I need to convert the output of the sine of an angle to fraction format. For example, when I do the sine of 30 degrees (0.523598... radians), the output is 0.5 radians and I need it to output 1/2. Does anyone know if there is a function for the conversion?

Re: Decimal to fraction

Tue Mar 24, 2015 6:19 am

This can't be done with perfect accuracy. Trigonometric functions are irrational, i.e. most have an infinite number of digits. Fractions, by definition, are not.

What you need to do is pick some arbitrary value for the denominator that's enough for whatever the application is e.g. 1024. The numerator is then just 1024*X rounded to the nearest integer, where X is your trig value. So in the case you gave the value of 0.5 would wind up as (0.5*1024)/1024 = 512/1024.

I suspect what you really want is some way of then converting that fraction into the smallest numbers that can be used to represent that same fraction which in this case is 1/2. To do that you need to divide both numerator and denominator by what's called the "greatest common divisor", which in this case is 512 (i.e. dividing 512/1024 results in 1/2). There are many algorithms you can used to find the GCD, Google is your friend here and the Wikipedia page on them also has plenty of examples:

http://en.wikipedia.org/wiki/Greatest_common_divisor

Obviously the choice of denominator is critical, 1024 will work terrific for powers of 2 but won't work as well as other values for (say) multiples of 3.

Re: Decimal to fraction

Tue Mar 24, 2015 8:49 pm

Thanks Myndale. I managed to figure it out. Here's the code:

Code:
void moveAngle(int angle){
   double radian = ((atan(1)*4)/180 * angle);
   double toa = tan(radian);
   
   int denominator = 1000;
   int numerator = toa*denominator;
   int gcd;
   
   for(long i=denominator;i>0;i--){
      if(numerator%i==0 && denominator%i==0){
         gcd = i;
         numerator /= gcd;
         denominator /=gcd;
         break;
      }
   }
   int rise = numerator;
   
   int run = denominator;

   gb.display.print(rise);
   gb.display.print(F(" / "));
   gb.display.print(run);
}

Re: Decimal to fraction

Wed Mar 25, 2015 12:35 am

Ugh, now the problem is trying to get the player to move along that slope at a specified speed. You can't just subtract the rise from the player's y and add the run to their x- some of the rise and run values are pretty high, and the player just flies off the screen. Any ideas?


Here's the code:
Code:
void moveAngle(int &x, int &y, int angle){
   double radian = ((atan(1)*4)/180 * angle);
   double toa = tan(radian);
   
   double run = 10;
   double rise = toa*run;
   double runDecimal = run-int(run);
   double riseDecimal = rise-int(rise);
   int gcd;
   
   for(int i=run;i>0;i--){
      if(fmod(rise,i)==riseDecimal && fmod(run,i)==runDecimal){
         gcd = i;
         rise /= gcd;
         run /= gcd;
         break;
      }
   }
}

Re: Decimal to fraction

Wed Mar 25, 2015 3:29 am

Not quite sure I understand what you're trying to do here, if you simply want to move the player at a fixed speed in a given direction then you use cos() and sin() scaled by the speed:

Code:
void moveAngle(float &x, float &y, int angle) {
   const float speed = 10;
   float radian = (angle*PI/180);
   x += speed * cos(radian);
   y += speed * sin(radian);
}


Note that I've also made x and y floats, to avoid jitter you should probably keep them as floats and cast them to integers when it's time to draw the object on screen.

Re: Decimal to fraction

Wed Mar 25, 2015 11:36 am

You need fixed point math + sine/cosine lookup tables to really hit some speed.

http://sourceforge.net/projects/avrfix/
https://jfdube.wordpress.com/2011/12/06/trigonometric-look-up-tables-revisited/
Post a reply