/* * * Operations sur les scalaires ( rationnels ) * */ #include #include #include "scalaires.h" #include "exceptions.h" #ifdef HAVE_CONFIG_H #include "config.h" #else #define _(x) x #endif /* * Cette precision est utilisee dans le cas ou nous devons convertir un double en rationnel */ #define PRECISION 1E6 typedisplay display; /* * Fonction interne uniquement */ static unsigned long long pgcd(unsigned long long a, unsigned long long b) { if (a < b) return pgcd(b, a); if (!b) return a; return pgcd(b, a % b); } /* * Les quelques fonctions utiles a tout le monde... Juste pour eviter de taper du code en n * exemplaire */ rationnel rat_constr_zero(void) { /* * renvoie 0 */ rationnel temp; temp.num = 0; temp.denom = 1; return temp; } rationnel rat_constr(unsigned long long num, unsigned long long denom) { /* * cree une fraction */ rationnel temp; int sgnnum = 1, sgndenom = 1; if (num < 0) { sgnnum = -1; num = -num; } if (denom < 0) { sgndenom = -1; denom = -denom; } if (!num) { temp.num = 0; temp.denom = 1; } else if (denom) { temp.num = sgnnum * sgndenom * num / pgcd(num, denom); temp.denom = denom / pgcd(num, denom); } else { exception(2, _("rat_constr: division by zero")); } return temp; } /* * Cette fonction est la pour faire beau. En fait, aucune routine ne l'utilise. Elle est ecrite "au * cas ou" */ rationnel rat_constr_from_double(double flt) { /* * cree une fraction a partir d un double */ return rat_constr(floor(flt * PRECISION), PRECISION); } void rat_destruct(rationnel rat) { /* * destructeur */ } double rat_to_double(rationnel rat) { /* * obtention du double correspondant a un rationnel */ return ((double) rat.num / (double) rat.denom); } rationnel rat_addition(rationnel rat1, rationnel rat2) { /* * addition */ return rat_constr(rat1.num * rat2.denom + rat2.num * rat1.denom, rat1.denom * rat2.denom); } rationnel rat_soustraction(rationnel rat1, rationnel rat2) { /* * soustraction */ return rat_constr(rat1.num * rat2.denom - rat2.num * rat1.denom, rat1.denom * rat2.denom); } rationnel rat_moinsunaire(rationnel rat1) { /* * moins unaire */ return rat_constr(-rat1.num, rat1.denom); } rationnel rat_multiplication(rationnel rat1, rationnel rat2) { /* * multiplication */ return rat_constr(rat1.num * rat2.num, rat1.denom * rat2.denom); } rationnel rat_division(rationnel rat1, rationnel rat2) { /* * division */ if (!rat2.num) exception(2, _("division by zero")); return rat_constr(rat1.num * rat2.denom, rat1.denom * rat2.num); } /* * On choisit deliberement de faire une puissance 'lente' pour eviter de faire des overflow trop * facilement */ rationnel rat_pow(rationnel rat, unsigned int p) { /* * puissance */ if (p == 0) { return rat_constr(1, 1); } for (p--; p; p--) { rat = rat_multiplication(rat, rat); } return rat; } /* * On convertit un rationnel en une chaine. Le booleen first indique si le rationnel devra etre * place en debut de chaine (pour les signes) */ char *rat_to_string(rationnel rat, int first) { static char resultat[128]; char temp[64]; resultat[0] = '\0'; if (rat.num < 0) { rat.num = -rat.num; if (first) { strcat(resultat, "-"); } else { strcat(resultat, "- "); } } else { if (!first) { strcat(resultat, "+ "); } } switch (display) { case DEC: if (rat.denom == 1) sprintf(temp, "%qd", rat.num); else sprintf(temp, "%qd/%qd", rat.num, rat.denom); break; case HEX: if (rat.denom == 1) sprintf(temp, "0x%qx", rat.num); else sprintf(temp, "0x%qx/0x%qx", rat.num, rat.denom); break; case OCT: if (rat.denom == 1) sprintf(temp, "0%qo", rat.num); else sprintf(temp, "0%qo/0%qo", rat.num, rat.denom); break; case FLT: sprintf(temp, "%g", rat_to_double(rat)); break; } strcat(resultat, temp); return resultat; }