Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C Fraction Arithmetic

I'm having great difficulty with the following that I need to do for an assign:
a. Declare a data structure that contains a rational number.
b. Write f'xns that will +, -, *, / rational numbers.
All f'xns have to pass 3 parameters, each pointing to a data structure of the type I declared in part a; 2 of the parameters = operands, 3rd = result.
c. Write a f'xn that takes a pointer to your data structure as a parameter and returns the GCD of the numer. & denom.
d. Use your f'xn from part c to write a f'xn that will reduce a fraction (rational number) to lowest terms. Pass in a pointer to the fraction and have the fraction modified by the f'xn.
e. Write input and output functions so that a user can enter a fraction in the form 1/5 for example.

The user should be allowed to enter any number of problems, and the program should output the answer in lowest terms.

Am I on the right track? I believe I have a-c down, but not d and especially e. Can someone please guide me or help me correct my script?

int GCD (int numer, int denom)
{
    int result;
    while (denom > 0) {
        result = numer % denom;
        numer = denom;
        denom = result;
    }
    return numer;
}

int getLCM (int numer, int denom)
{
    int max;
    max = (numer > denom) ? numer : denom;
    while (1) {
        if (max % numer == 0 && max % denom == 0)
            break;
        ++max;
    }
    return max;
}

struct Fraction 
{
    int numer;
    int denom;
};

typedef struct 
{
    int numer;
    int denom; 
};
Fraction

Fraction add_fractions (Fraction a, Fraction b)
{
    Fraction sum;
    sum.numer = (a.numer * b.denom) + (b.numer * a.denom);
    sum.denom = a.denom * b.denom;
    return sum;
}

Fraction subtract_fractions (Fraction a, Fraction b)
{
    Fraction sum;
    sum.numer = (a.numer * b.denom) - (b.numer * a.denom);
    sum.denom = a.denom * b.denom;
    return sum;
}

Fraction multiply_fractions (Fraction a, Fraction b)
{
    Fraction sum;
    sum.numer = (a.denom * b.denom);
    sum.denom = (a.numer * b.numer);
    return sum;
}

Fraction divide_fractions (Fraction a, Fraction b)
{
    Fraction sum;
    sum.numer = (a.denom * b.numer);
    sum.denom = (a.numer * b.denom);
    return sum;
}

int main ()
{
    char response;

    printf ("FRACTION ARITHMETIC PROGRAM\n");
    printf ("Enter your problem (example 2/3 + 1/5):\n");
    scanf (, &problem);

    if (denom == 0 || denom < 0) {
        printf ("Illegal input!!\n");
        printf ("Another problem (y/n)?  ");
        scanf ("%c%*c", &response);
    } else {
        printf ("The answer is  ");

        printf ("Another problem (y/n)?  ");
        scanf ("%c%*c", &response);
    }

    while ((response == 'y') || (response == 'Y')) {
        printf ("\nWould you like to play again?\n");
        scanf ("%c%*c", &response);
    }

    while ((response == 'n') || (response == 'N'))
        printf ("Goodbye and thank you");

    return 0;
}

Edit after removing typedef thanks to comment responses:

struct Fraction {
    int numer;
    int denom;
};

struct Fraction add_fractions (struct Fraction a, struct Fraction b)
{
    struct Fraction sum;
    sum.numer = (a.numer * b.denom) + (b.numer * a.denom);
    sum.denom = a.denom * b.denom;
    return sum;
}

struct Fraction subtract_fractions (struct Fraction a, struct Fraction b)
{
    struct Fraction sum;
    sum.numer = (a.numer * b.denom) - (b.numer * a.denom);
    sum.denom = a.denom * b.denom;
    return sum;
}

struct Fraction multiply_fractions (struct Fraction a, struct Fraction b)
{
    struct Fraction sum;
    sum.numer = (a.denom * b.denom);
    sum.denom = (a.numer * b.numer);
    return sum;
}

struct Fraction divide_fractions (struct Fraction a, struct Fraction b)
{
    struct Fraction sum;
    sum.numer = (a.denom * b.numer);
    sum.denom = (a.numer * b.denom);
    return sum;
}
like image 451
usuallystuck Avatar asked Nov 24 '15 07:11

usuallystuck


2 Answers

Some remarks with your code:

  • You do not thoroughly follow your requirements because GCD function takes 2 integers when it is required to take a pointer to struct, and your functions take 2 struct as parameter and return another one when they should take 3 (pointers to) structs.
  • Your GCD function uses a nice GCD implementation (thanks to Jonathan for its comment), even if some comment explaining the why would be nice for future readers
  • As you were said in comment, you should reduce rationals before doing operations on them to avoid unnecessary overflows, and when adding or subtracting rationals, you should use the LCM of the denoms for same reason
  • Your LCM algorithm is poor. As your GCD is nice why not simply use: LCM(a,b) = a * b / GCD(a,b) computed as lcm = (a/gcb) * b to reduce overflow risk (thanks to @n.m. for the simplified form)
  • Reduced form of a/b is a'/b' where a'=a/GCD(a,b) and b'=b/GCD(a,b)
  • What about a "%d/%d" format for both input and output, with the two members of a struct?

Last but not least, format "%c%*c" to get answer to a y/n question is possible but dangerous: you are likely to get the newline of preceding input into response! Choose one of line oriented input (with fgets + sscanf) or free form input (with scanf or fscanf) and stick to it. %1s into a char response[2] is much safer...

And carefully write in comment that you only process positive rationals or take care of sign! Such a detail can make users of a library rather angry ... not to mention nitpicking teachers (credits for Jonathan Leffler).

like image 183
Serge Ballesta Avatar answered Oct 22 '22 15:10

Serge Ballesta


You can use an enum for operators and a function to switch on the operators since all operators follow a similar pattern. This simplifies the code. Here is example of some of the implementations, you can add the rest:

typedef struct node {
    int nom;
    int denom;
} Tfraction;

typedef enum {PLUS, MINUS, MULTIPLY, DIVIDE} Ops;

int calculate(int x, Ops op, int y) {
    switch (op) {
        case PLUS: return x + y;
        case MINUS: return x - y;
        case MULTIPLY: return x * y;
        case DIVIDE: return x / y;
    }
}

//reccursive gcd
int gcdr (int a, int b) {
    if (a == 0) return b;
    return gcdr(b % a, a);
}

void simplify(Tfraction *fraction) {
    int gcd = gcdr(fraction->nom, fraction->denom);
    fraction->nom /= gcd;
    fraction->denom /= gcd;
}

Tfraction compute(Tfraction a, Tfraction b, Ops op) {
    if (op == DIVIDE) {
        int temp = b.nom;
        b.nom = b.denom;
        b.denom = temp;
        op = MULTIPLY;
    }

    if (op == MULTIPLY) {
        Tfraction result = { calculate(a.nom, op, b.nom), calculate(a.denom, op, b.denom) };
        simplify(&result);
        return result;
    }
    if (a.denom == b.denom) {
        Tfraction result = { calculate(a.nom, op, b.nom), a.denom };
        simplify(&result);
        return result;
    }
    else {
        Tfraction result = { (calculate((a.nom * b.denom), op, (b.nom * a.denom))), (a.denom * b.denom) };
        simplify(&result);
        return result;
    }
}

int main ()
{
    //Test
    Tfraction f1 = {2, 4}, f2 = {4, 2};

    printf("Addition: %d/%d\n", compute(f1, f2, PLUS).nom, compute(f1, f2, PLUS).denom);
    printf("Subtraction: %d/%d\n", compute(f1, f2, MINUS).nom, compute(f1, f2, MINUS).denom);
    printf("Multiplication: %d/%d\n", compute(f1, f2, MULTIPLY).nom, compute(f1, f2, MULTIPLY).denom);
    printf("Division: %d/%d\n", compute(f1, f2, DIVIDE).nom, compute(f1, f2, DIVIDE).denom);

    return 0;
}
like image 2
Lukas Avatar answered Oct 22 '22 16:10

Lukas