Arithmetic/Rational/C

From Rosetta Code
Revision as of 15:16, 8 January 2010 by rosettacode>Glennj (moved from Rational Arithmetic)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Arithmetic/Rational/C is part of Rational Arithmetic. You may find other members of Rational Arithmetic at Category:Rational Arithmetic.

C doesn't support classes, so a series of functions is provided that implments the arithmetic of a rational class. <lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include <string.h>
  3. include <math.h> // for fabs in converting float to rational

// a structure to contain the numerator and denominator values typedef struct sRational {

   int numerator, denominator;

} *Rational, sRational;

int gcd( int a, int b) {

   int g;
   if (a<b)  {
       g = a; a = b; b = g;
   }
   g = a % b;
   while (g) {
       a = b; b = g;
       g = a % b;
   }
   return abs(b);

}

int lcm( int a, int b) {

   return (a/gcd(a,b)*b);

}

Rational NewRational( int n, int d) {

   Rational r = (Rational)malloc(sizeof(sRational));
   int ndgcd;
   if (n!= 0)
       ndgcd = gcd(n,d);
   else {
       ndgcd = 1; d = 1;
   }
   if (r) {
       if (n>0) {
           r->numerator = n/ndgcd;
           r->denominator = d/ndgcd;
       }
       else {
           r->numerator = -n/ndgcd;
           r->denominator = -d/ndgcd;
       }
   }
   if ( d == 0) {
       printf("divide by zer0 error\n");
       exit(1);
   }
   return r;

}

  1. define Ratl_Delete(r) \
   {  if(r) free(r); \
   r = NULL; }

Rational Ratl_Add( Rational l, Rational r, Rational rzlt) {

   int  denom;
   denom= lcm(l->denominator, r->denominator);
   rzlt->numerator = denom/l->denominator *l->numerator 
                  + denom/r->denominator *r->numerator ;
   rzlt->denominator = denom;
   if (rzlt->numerator == 0) {
       rzlt->denominator = 1;
   }
   else {
       int d = gcd(rzlt->numerator, rzlt->denominator);
       rzlt->numerator /= d;
       rzlt->denominator /= d;
   }
   return rzlt;

}

Rational Ratl_Negate( Rational l, Rational rzlt) {

   rzlt->numerator = - l->numerator;
   rzlt->denominator = l->denominator;
   return rzlt;

}

Rational Ratl_Subtract(Rational l, Rational r, Rational rzlt) {

   return Ratl_Add(l,Ratl_Negate(r, rzlt), rzlt);

}

Rational Ratl_Multiply(Rational l, Rational r, Rational rzlt) {

   int g1 = gcd(l->numerator, r->denominator);
   int g2 = gcd(r->numerator, l->denominator);
   rzlt->numerator = l->numerator / g1 * r->numerator / g2;
   rzlt->denominator = l->denominator / g2 * r->denominator / g1;
   return rzlt;

}

Rational Ratl_Inverse(Rational l, Rational rzlt) {

   if (l->numerator == 0) {
       printf("divide by zer0 error\n");
       exit(1);
   }
   else if (l->numerator > 0) {
       rzlt->numerator = l->denominator;
       rzlt->denominator = l->numerator;
   }
   else {
       rzlt->numerator = -l->denominator;
       rzlt->denominator = -l->numerator;
   }
   return rzlt;

}

Rational Ratl_Divide(Rational l, Rational r, Rational rzlt) {

   return Ratl_Multiply(l, Ratl_Inverse(r, rzlt), rzlt);

}

int ipow(int base, int power ) {

   int v = base, v2 = 1;
   if (power < 0) return 0; // shouldn't happen
   while (power > 0) {
       if (power & 1) 
           v2 *=v;
       v = v*v;
       power >>= 1;
   }
   return v2;

}

Rational Ratl_Pow( Rational l, int power, Rational rzlt) {

   if (power >= 0) {
       rzlt->numerator = ipow(l->numerator, power);
       rzlt->denominator = ipow(l->denominator, power);
   }
   else {
       rzlt->numerator = ipow(l->denominator, -power);
       rzlt->denominator = ipow(l->numerator, -power);
   }
   return rzlt;

}

int Ratl_Compare(Rational l, Rational r) {

   int sign = (l->numerator > 0)? 1 : -1;
   sRational  comp;
   Rational pcomp;
   if ( 0 >= l->numerator * r->numerator)        // if opposite signs or one is zero
       return (l->numerator - r->numerator);
   pcomp = Ratl_Divide(l, r, &comp);
   return (pcomp->numerator - pcomp->denominator)*sign;

}

typedef enum {

   LT, LE, EQ, GE, GT, NE } CompOp;

// boolean comparisons int Ratl_Cpr( Rational l, CompOp compOp, Rational r) {

   int v;
   int r1 = Ratl_Compare(l, r);
   switch(compOp) {
       case LT: v = (r1 <0)? 1 : 0; break;
       case LE: v = (r1<=0)? 1 : 0; break;
       case GT: v = (r1 >0)? 1 : 0; break;
       case GE: v = (r1>=0)? 1 : 0; break;
       case EQ: v = (r1==0)? 1 : 0; break;
       case NE: v = (r1!=0)? 1 : 0; break;
   }
   return v;

}

double Ratl_2Real(Rational l) {

   return l->numerator *1.0/l->denominator;

}

int Ratl_2Int(Rational l) {

   return l->numerator /l->denominator;

}

int Ratl_2Proper(Rational l) {

   int ipart = l->numerator/l->denominator;
   l->numerator %= l->denominator;
   return ipart;

}

char *Ratl_2String(Rational l, char *buf, int blen) {

   char ibuf[40];
   sprintf(ibuf,"%d/%d", l->numerator, l->denominator );
   if (buf==NULL) return buf;
   if ((int)strlen(ibuf) < blen)
       strcpy(buf, ibuf);
   else  {
       strncpy(buf, ibuf, blen-4);
       strcat(buf, "...");
   }
   return buf;

}

Rational Int_2Ratl(int i, Rational rtnl) {

   rtnl->numerator = i;
   rtnl->denominator = 1;
   return rtnl;

}

Rational Real_2Ratl(double r, double eps, Rational rtnl) {

   int denom;
   double v1,v2;
   int isNeg = (r<0);
   if ( isNeg) r = -r;
   denom=0; 
   do {
       denom++;
       v1 = (r+eps)*denom;
       v2 = r*denom;
       v2 = fabs(v2 - (int) v1);
   } while ( v2 > denom*eps);
   rtnl->numerator = (int)v1 * ((isNeg)? -1 : 1);
   rtnl->denominator = denom;
   return rtnl;

}

Rational Ratl_Abs(Rational l, Rational rzlt) {

   rzlt->numerator = abs(l->numerator);
   rzlt->denominator = abs(l->denominator);   // should already be nonnegative
   return rzlt;

}</lang> Testing <lang c>void find_perfects() {

   int n, n2, k;
   int end = 1<<19;
   sRational r1, r2, r3;
   Rational f1, f2;
   Rational sum = NewRational( 0, 1 );
   for (n=2; n< end; n++) {
       sum = Ratl_Inverse(Int_2Ratl(n, &r1), sum);
       n2 = (int)sqrt(n)+1;
       for (k=2; k<n2; k++) {
           if ( n % k == 0) {
               f1 = Ratl_Inverse(Int_2Ratl(k,&r1), &r2);
               f2 = Ratl_Inverse(Int_2Ratl(n/k,&r1),&r3);
               Ratl_Add(sum, f1,sum);
               Ratl_Add(sum, f2,sum);
           }
       }
       if (sum->denominator == 1) {
           printf("Perfect number %d sum is %d\n", n, Ratl_2Int(sum));
       }
   }
   Ratl_Delete(sum);

}


int main(int argc, char *argv[]) {

   char ratstr[32], rs1[32],rs2[32];
   double pi = 3.14159265;
   sRational rtemp1, rtemp2;
   Rational rz;
   Rational r1 = NewRational( 5,7 );
   Rational r2 = NewRational( 4,5 );
   Rational r3 = NewRational( 3,4);
   printf("r3 = %s\n", Ratl_2String(r3, ratstr,32));
   rz = Ratl_Multiply( r1,r2, &rtemp1);
   printf("%s = %s * %s\n", Ratl_2String(rz, ratstr,32),
                    Ratl_2String(r1, rs1,32), Ratl_2String(r2, rs2, 32));
   rz = Ratl_Divide( r1,r3, &rtemp2);
   printf("%s = %s / %s\n", Ratl_2String(rz, ratstr,32),
                    Ratl_2String(r1, rs1,32), Ratl_2String(r3, rs2, 32));
   rz = Ratl_Add( r2,r3, &rtemp1);
   printf("%s = %s + %s\n", Ratl_2String(rz, ratstr,32),
                    Ratl_2String(r2, rs1,32), Ratl_2String(r3, rs2, 32));
   rz = Ratl_Subtract( r2,r3, &rtemp1);
   printf("%s = %s - %s\n", Ratl_2String(rz, ratstr,32),
                    Ratl_2String(r2, rs1,32), Ratl_2String(r3, rs2, 32));
   printf("%d = %s > %s\n", Ratl_Cpr( r2, GT, &rtemp2),
                    Ratl_2String(r2, rs1,32), Ratl_2String(&rtemp2, rs2, 32));
   rz = Ratl_Pow( r2,-3, &rtemp1);
   printf("%s = %s ^ -3\n", Ratl_2String(rz, ratstr,32),
                    Ratl_2String(r2, rs1,32));
   printf("%s = %f\n", Ratl_2String( &rtemp2, ratstr, 32), Ratl_2Real( &rtemp2));
   rz =Real_2Ratl( pi, 0.000001, &rtemp2);
   printf("%10.7f ~= %s ~=%10.7f\n", pi, Ratl_2String(rz, ratstr, 32),
                                  Ratl_2Real(rz));
   find_perfects();
   return 0;

}</lang>