2015-11-24 20 views
7

Sto avendo grosse difficoltà con quanto segue che ho bisogno di fare per un incarico:
a. Dichiarare una struttura dati che contiene un numero razionale.
b. Scrivi f'xns che farà +, -, *,/numeri razionali.
Tutti i f'xns devono passare 3 parametri, ciascuno dei quali punta a una struttura dati del tipo che ho dichiarato nella parte a; 2 dei parametri = operandi, 3 = risultato.
c. Scrivi un f'xn che accetta un puntatore alla struttura dati come parametro e restituisce il GCD del numero. & denom.
d. Usa il tuo f'xn dalla parte c per scrivere un f'xn che ridurrà una frazione (numero razionale) ai minimi termini. Passa in un puntatore alla frazione e ottieni la frazione modificata dal f'xn.
e. Scrive le funzioni di input e output in modo che un utente possa inserire una frazione nel formato 1/5, ad esempio.C Fraction Arithmetic

All'utente deve essere consentito immettere qualsiasi numero di problemi e il programma deve fornire la risposta nei termini minimi.

Sono sulla buona strada? Credo di avere a-c giù, ma non d e soprattutto e. Qualcuno può guidarmi o aiutarmi a correggere il mio copione?

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; 
} 

Modifica dopo aver rimosso typedef grazie per commentare le risposte:

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; 
} 
+2

Per quanto mi riguarda, siete un po 'sulla buona strada; tuttavia, è possibile introdurre una funzione per ridurre le frazioni per impedire troppo rapidamente i valori del numeratore e del denominatore. – Codor

+8

Il tipo 'struct Fraction' non è interamente correlato al tipo' Fraction', che è un tipo di struttura anonima (senza tag) con un nome typedef di 'Fraction'. Probabilmente dovresti combinare i due, sebbene sia possibile utilizzarne uno. Quello che è sbagliato è avere entrambi. –

+1

Si può fare meglio nella funzione 'getLCM'. Sarebbe una buona idea normalizzare la frazione prima di tornare numerando e denomina con gcd. (Scrivi una funzione per normalizzare) È possibile rimuovere "typedef' o' struct Fraction' per evitare confusione. –

risposta

3

alcune osservazioni con il tuo codice:

  • Non è accuratamente seguite le vostre esigenze perché la funzione GCD prende 2 interi quando è necessario prendere un puntatore per struct e le tue funzioni prendono 2 struct come parametro e ne restituiscono un altro quando lo fanno dovrebbe prendere 3 (puntatori a) strutture.
  • La funzione GCD utilizza un bel implementazione GCD (grazie a Jonathan per il suo commento), anche se qualche commento che spiega il motivo per cui sarebbe bello per i futuri lettori
  • come eri detto in commento, si dovrebbe ridurre razionali prima di fare operazioni su di loro per evitare inutili overflow e quando si aggiungono o si sottrae i razionali, si dovrebbe usare il LCM dei denomi per lo stesso motivo
  • L'algoritmo LCM è scarso. Come il vostro GCD è bello perché non utilizzare semplicemente: LCM(a,b) = a * b/GCD(a,b) calcolato come lcm = (a/gcb) * b per ridurre il rischio di overflow (grazie a @nm per la forma semplificata)
  • forma ridotta a/b è un '/ b' dove un '= a/GCD (a, b) e b '= b/GCD (a, b)
  • Che dire di un formato "%d/%d" per input e output, con i due membri di una struct?

Ultimo ma non meno importante, il formato "%c%*c" per avere risposta ad una domanda y/n è possibile ma pericoloso: si rischia di ottenere il ritorno a capo del precedente input in risposta! Scegliere uno di input orientato alla linea (con fgets + sscanf) o l'immissione di modulo libero (con scanf o fscanf) e attenersi ad esso.%1s in un char response[2] è molto più sicuro ...

E scrivere con attenzione nel commento che si elaborano solo razionali positivi o si prende cura del segno! Un tale dettaglio può rendere gli utenti di una libreria piuttosto arrabbiati ... per non parlare di insegnanti che si accalorano di diteggiatura (credits per Jonathan Leffler).

+1

"perché non usare semplicemente: LCM (a, b) = a * b/GCD (a, b)". Perché overflow. –

+0

@ n.m .: il problema di overflow è già stato preso in considerazione alla fine della frase. E se 'lcm = (a/gcb) * (b/gcd) * gcd' fuoriesce, non si può fare nient'altro! –

+0

Scusa, la mia capacità di attenzione è limitata oggi ... perché non solo 'a/gcd (a, b) * b'? –

2

È possibile utilizzare un enum per gli operatori e una funzione per accendere gli operatori poiché tutti gli operatori seguono uno schema simile. Questo semplifica il codice. Ecco esempio di alcune delle implementazioni, è possibile aggiungere il resto:

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; 
} 
+0

Non credo che il tuo codice di semplificazione sia valido da remoto. Si consideri una frazione presentata come 15/9; dovresti finire con 5/3, ma il tuo codice restituirebbe 2/1, che non è affatto la stessa cosa. –

+0

L'ho risolto. potrebbero esserci dei miglioramenti nell'implementazione ma stavo sottolineando la logica. la semplificazione non è nemmeno nella domanda quindi non si dovrebbe votare solo per quello. – Lukas

+0

Gli elenchi puntati (c) e (d) nella domanda riguardano la semplificazione delle frazioni. Il tuo codice "fisso" è ancora sbagliato. Devi usare GCD e/o LCM e non lo sei. Non hai nemmeno tentato di seguire le specifiche nella domanda w.r.t funzioni prendendo tre puntatori, uno per operazione. –

0

ho cambiato la somma e moltiplicare le funzioni per ridurre al minimo troppo pieno, anche se non ho cambiato ad accettare 3 argomenti (io preferisco in questo modo).

#include <stdio.h> 
#include <stdlib.h> 

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

int gcd(int numer, int denom) { 
    int result; 
    while (denom != 0) { 
    result = numer % denom; 
    numer = denom; 
    denom = result; 
    } 
    return numer; 
} 

int lcm(int a, int b) { 
    return (a/gcd(a,b)) * b; 
} 

Fraction simplify (Fraction a) { 
    int cd; 
    cd = gcd(a.numer, a.denom); 
    a.numer /= cd; 
    a.denom /= cd; 
    return a; 
} 

Fraction add_fractions (Fraction a, Fraction b) { 
    Fraction sum; 
    int lcmd; 
    a = simplify(a); 
    b = simplify(b); 
    lcmd = lcm(a.denom, b.denom); 
    sum.numer = (lcmd/a.denom * a.numer) + (lcmd/b.denom * b.numer); 
    sum.denom = lcmd; 
    return simplify(sum); 
} 

Fraction subtract_fractions (Fraction a, Fraction b) { 
    Fraction sum; 
    int lcmd; 
    a = simplify(a); 
    b = simplify(b); 
    lcmd = lcm(a.denom, b.denom); 
    sum.numer = (lcmd/a.denom * a.numer) - (lcmd/b.denom * b.numer); 
    sum.denom = lcmd; 
    return simplify(sum); 
} 

void swap(int *a, int *b) { 
    int tmp = *a; 
    *a = *b; 
    *b = tmp; 
} 

Fraction multiply_fractions (Fraction a, Fraction b) { 
    Fraction sum; 
    a = simplify(a); 
    b = simplify(b); 
    swap(&a.numer, &b.numer); // another round of simplifications to avoid (minimize) overflows below 
    a = simplify(a); 
    b = simplify(b); 
    sum.numer = (a.numer * b.numer); 
    sum.denom = (a.denom * b.denom); 
    return sum; 
} 

Fraction divide_fractions (Fraction a, Fraction b) { 
    swap(&b.numer, &b.denom); 
    return multiply_fractions(a, b); 
} 

int main() { 
    int a, b; 
    Fraction f1 ,f2, res; 

    printf("gcd(12,9)=%d\n", gcd(12,9)); 
    printf("gcd(9,12)=%d\n", gcd(9,12)); 

    printf("gcd(4,12)=%d\n", gcd(4,12)); 

    printf("gcd(8,12)=%d\n", gcd(8,12)); 
    printf("gcd(12,8)=%d\n", gcd(12,8)); 

    puts("-"); 

    printf("lcm(12,9)=%d\n", lcm(12,9)); 
    printf("lcm(9,12)=%d\n", lcm(9,12)); 

    printf("lcm(8,12)=%d\n", lcm(8,12)); 
    printf("lcm(12,8)=%d\n", lcm(12,8)); 

    printf("lcm(4,12)=%d\n", lcm(4,12)); 
    printf("lcm(3,5)=%d\n", lcm(3,5)); 
    printf("lcm(4,5)=%d\n", lcm(4,5)); 
    printf("lcm(3,4)=%d\n", lcm(3,4)); 

    puts("-"); 

    f1.numer = 12; 
    f1.denom = 9; 
    printf(" %d/%d simplified to", f1.numer, f1.denom); 
    f1 = simplify(f1); 
    printf(" %d/%d \n", f1.numer, f1.denom); 

    f1.numer = 8; 
    f1.denom = 12; 
    printf(" %d/%d simplified to", f1.numer, f1.denom); 
    f1 = simplify(f1); 
    printf(" %d/%d \n", f1.numer, f1.denom); 

    puts("-"); 

    f1.numer = 1; f1.denom = 4; 
    f2.numer = 1; f2.denom = 4; 
    res = add_fractions(f1, f2); 
    printf(" %d/%d + %d/%d = %d/%d \n", f1.numer, f1.denom, f2.numer, f2.denom, res.numer, res.denom); 

    f1.numer = 1; f1.denom = 4; 
    f2.numer = 1; f2.denom = 12; 
    res = add_fractions(f1, f2); 
    printf(" %d/%d + %d/%d = %d/%d \n", f1.numer, f1.denom, f2.numer, f2.denom, res.numer, res.denom); 

    f1.numer = 1; f1.denom = 3; 
    f2.numer = 5; f2.denom = 6; 
    res = add_fractions(f1, f2); 
    printf(" %d/%d + %d/%d = %d/%d \n", f1.numer, f1.denom, f2.numer, f2.denom, res.numer, res.denom); 

    f1.numer = 35; f1.denom = 100; 
    f2.numer = 1; f2.denom = 4; 
    res = subtract_fractions(f1, f2); 
    printf(" %d/%d - %d/%d = %d/%d \n", f1.numer, f1.denom, f2.numer, f2.denom, res.numer, res.denom); 

    f1.numer = 7; f1.denom = 10; 
    f2.numer = 1; f2.denom = 2; 
    res = subtract_fractions(f1, f2); 
    printf(" %d/%d - %d/%d = %d/%d \n", f1.numer, f1.denom, f2.numer, f2.denom, res.numer, res.denom); 

    f1.numer = 1; f1.denom = 2; 
    f2.numer = 1; f2.denom = 2; 
    res = multiply_fractions(f1, f2); 
    printf(" %d/%d x %d/%d = %d/%d \n", f1.numer, f1.denom, f2.numer, f2.denom, res.numer, res.denom); 

    f1.numer = 12; f1.denom = 5; 
    f2.numer = 5; f2.denom = 6; 
    res = multiply_fractions(f1, f2); 
    printf(" %d/%d x %d/%d = %d/%d \n", f1.numer, f1.denom, f2.numer, f2.denom, res.numer, res.denom); 

    f1.numer = 12; f1.denom = 21; 
    f2.numer = 7; f2.denom = 4; 
    res = multiply_fractions(f1, f2); 
    printf(" %d/%d x %d/%d = %d/%d \n", f1.numer, f1.denom, f2.numer, f2.denom, res.numer, res.denom); 

    f1.numer = 1; f1.denom = 5; 
    f2.numer = 1; f2.denom = 5; 
    res = divide_fractions(f1, f2); 
    printf(" %d/%d/%d/%d = %d/%d \n", f1.numer, f1.denom, f2.numer, f2.denom, res.numer, res.denom); 

}