/** DEBUT BIGINT addition(BIGINT, BIGINT); DEBUT **/ BIGINT addition(BIGINT nb1, BIGINT nb2) { BIGINT resultat; int tmp; unsigned int retenue = 0; initListe(&resultat); /// Gestion du signe du résultat /// if(nb1.signe == MOINS && nb2.signe == PLUS) { nb1.signe = PLUS; resultat = soustraction(nb1, nb2); resultat.signe = MOINS; return resultat; } else if (nb1.signe == PLUS && nb2.signe == MOINS) { nb2.signe = PLUS; return resultat = soustraction(nb1, nb2); } else if(nb1.signe == MOINS && nb2.signe == MOINS) { resultat.signe = MOINS; nb1.signe = PLUS; nb2.signe = PLUS; } while(!listeVide(nb1) && !listeVide(nb2)) { tmp = nb1.fin->valeur + nb2.fin->valeur + retenue; retenue = tmp / 10; empilerListe(&resultat, tmp % 10); nb1.fin = nb1.fin->precedent; nb2.fin = nb2.fin->precedent; } /// Necessaire si nb1.nbEl > nb2.nbEl, il faut finir l'addition avec le reste des chiffres de nb1.nbEl /// /** J'ai séparé volontairement cette condition de la boucle principale, pour éviter une condition qui n'est pas nécessaire ** dans le cas ou nb1.nbEl = nb2.nbEl. Cela ajoute une répétition dans l'ecriture mais un léger gain en performance **/ while(!listeVide(nb1)) { tmp = nb1.fin->valeur + retenue; retenue = tmp / 10; empilerListe(&resultat, tmp % 10); nb1.fin = nb1.fin->precedent; } /// Necessaire si nb2.nbEl > nb1.nbEl, il faut finir l'addition avec le reste des chiffres de nb2.nbEl /// /** J'ai séparé volontairement cette condition de la boucle principale, pour éviter une condition qui n'est pas nécessaire ** dans le cas ou nb2.nbEl = nb1.nbEl. Cela ajoute une répétition dans l'ecriture mais un léger gain en performance **/ while(!listeVide(nb2)) { tmp = nb2.fin->valeur + retenue; retenue = tmp / 10; empilerListe(&resultat, tmp % 10); nb2.fin = nb2.fin->precedent; } /// Ajout de la retenue de fin, si elle existe. Exemple 99 + 10 = 1 retenue et 09 => 109 // if(retenue) empilerListe(&resultat, 1); nettoyerNb(&resultat); return resultat; }
void nettoyerNb(BIGINT *nb) { int out = 1; if(!nb->debut->valeur && nb->nbEl > 1) { while(out && !listeVide(*nb)) { if(!nb->debut->valeur) { depilerListe(nb); } else { out = 0; } } if(listeVide(*nb)) empilerListe(nb, 0); } }
void afficherListe(BIGINT liste) { if(liste.signe == MOINS) printf("-"); while(!listeVide(liste)) { printf("%d", liste.debut->valeur); liste.debut = liste.debut->suivant; } }
void viderListe(BIGINT *ptrListe) { while(!listeVide(*ptrListe)) { depilerListe(ptrListe); } initListe(ptrListe); }
/** DEBUT int comparer_nb(BIGINT, BIGINT); DEBUT **/ int comparer_nb(BIGINT nb1, BIGINT nb2) { int max = 0; if(nb1.signe > nb2.signe) return SUP; else if(nb1.signe < nb2.signe) return INF; if(nb1.nbEl > nb2.nbEl) return (nb1.signe) ? SUP : INF; else if (nb1.nbEl < nb2.nbEl) return (nb2.signe) ? INF : SUP; while( max == 0 && (!listeVide(nb1) && !listeVide(nb2))) { if(nb1.debut->valeur > nb2.debut->valeur) max = SUP; else if(nb1.debut->valeur < nb2.debut->valeur) max = INF; nb1.debut = nb1.debut->suivant; nb2.debut = nb2.debut->suivant; } return max; }
// parcours inverse : du dernier vers le premier void parcoursListeSymI (ListeS* ls, void (*f) (Objet*)) { if (listeVide(ls)) { printf ("Liste symétrique vide\n"); } else { Element* ptc = dernier (ls); while (ptc != NULL) { f (ptc->reference); ptc = precedent (ptc); } } }
BIGINT clone(BIGINT nb) { BIGINT clone; initListe(&clone); while(!listeVide(nb)) { insererFin(&clone, nb.debut->valeur); nb.debut = nb.debut->suivant; } return clone; }
// insérer "objet" en fin de la liste symétrique ls void insererEnFinDeListeSym (ListeS* ls, Objet* objet) { Element* nouveau = creerElement(); nouveau->reference = objet; nouveau->suivant = NULL; if (listeVide(ls)) { // liste symétrique vide nouveau->precedent = NULL; ls->premier = nouveau; } else { nouveau->precedent = ls->dernier; ls->dernier->suivant = nouveau; } ls->dernier = nouveau; }
// valeur du polynôme po pour un x donné double valeurPolynome (Polynome* po, double x) { Liste* li = po; double resu = 0; if (listeVide (li) ) { printf ("Polynôme nul\n"); exit (1); } else { ouvrirListe (li); while (!finListe (li)) { Monome* ptc = (Monome*) objetCourant (li); resu += ptc->coefficient*puissance(x, ptc->exposant); } } return resu; }
/** DEBUT BIGINT divisionScolaire(BIGINT, BIGINT); DEBUT **/ BIGINT divisionScolaire(BIGINT nb1, BIGINT nb2) { BIGINT resultat, ligne; BIGINT tmp; initListe(&resultat); initListe(&ligne); /// Variable pour vidage mémoire des calculs intermédiaires /// initListe(&tmp); /// Gestion du signe du résultat /// resultat.signe = nb1.signe * nb2.signe; nb1.signe = PLUS; nb2.signe = PLUS; if(comparer_nb(nb1, nb2) == INF) { empilerListe(&resultat, 0); return resultat; } else if(comparer_nb(nb1, nb2) == EGAL) { empilerListe(&resultat, 1); return resultat; } else if(nb2.debut->valeur == 0 && nb2.nbEl == 1) { /// Impossible de diviser par zero /// return; } while(!listeVide(nb1)) { insererFin(&ligne, 0); ligne.fin->valeur = nb1.debut->valeur; insererFin(&resultat, 0); nettoyerNb(&ligne); while(comparer_nb(ligne, nb2) >= EGAL) { resultat.fin->valeur += 1; tmp = soustraction(ligne, nb2); viderListe(&ligne); ligne = tmp; } nb1.debut = nb1.debut->suivant; } nettoyerNb(&resultat); return resultat; }
void insererFin(BIGINT *ptrListe, NOMBRE valeur) { CELLULE *tmp = malloc(sizeof(CELLULE)); if(!tmp) exit(1); tmp->valeur = valeur; tmp->suivant = NULL; tmp->precedent = ptrListe->fin; if(listeVide(*ptrListe)) { ptrListe->debut = tmp; } else { ptrListe->fin->suivant = tmp; } ptrListe->fin = tmp; ptrListe->nbEl += 1; }
/** DEBUT BIGINT multiplicationBasique(BIGINT, BIGINT); DEBUT **/ BIGINT multiplicationBasique(BIGINT nb1, BIGINT nb2) { BIGINT resultat, ligne, tmp; int j, signe_nb1, signe_nb2; signe_nb1 = nb1.signe; signe_nb2 = nb2.signe; nb1.signe = PLUS; nb2.signe = PLUS; initListe(&resultat); /// Variable pour vidage mémoire des calculs intermédiaires /// initListe(&tmp); /// Cas ou nb1 ou nb2 seraient égal à 0, on renvoie 0 directement /// if(egal_zero(nb1) || egal_zero(nb2)) { empilerListe(&resultat, 0); return resultat; } ligne = nb1; while(!listeVide(nb2)) { for(j = 1; j <= nb2.fin->valeur; j += 1) { tmp = addition(resultat, ligne); viderListe(&resultat); resultat = tmp; } nb2.fin = nb2.fin->precedent; insererFin(&ligne, 0); } /// Gestion du signe du résultat /// resultat.signe = signe_nb1 * signe_nb2; return resultat; }
booleen pilevide(Pile* p){ return listeVide(p); }
/** DEBUT BIGINT multiplicationKaratsuba(BIGINT, BIGINT); DEBUT **/ BIGINT multiplicationKaratsuba(BIGINT nb1, BIGINT nb2) { BIGINT x0, x1, y0, y1, p0, p1, p2, resultat; BIGINT tmp, tmp2; int m, i, signe_nb1, signe_nb2; signe_nb1 = nb1.signe; signe_nb2 = nb2.signe; nb1.signe = PLUS; nb2.signe = PLUS; nb1.signe = PLUS; nb2.signe = PLUS; initListe(&resultat); /// Variables pour calculs intermédiaires /// initListe(&x0); initListe(&x1); initListe(&y0); initListe(&y1); initListe(&p0); initListe(&p1); initListe(&p2); /// Variables pour vidage mémoire des calculs intermédiaires /// initListe(&tmp); initListe(&tmp2); /// On enlève les 0 devant nb1 et nb2, car la taille du nombre est importante dans l'execution de l'algorithme de karatsuba /// nettoyerNb(&nb1); nettoyerNb(&nb2); /// m = milieu du plus grand nombre. Exemple : 9828839 => m = 4, 192893 => m = 3 /// m = (max_element(nb1, nb2) + 1) / 2; /// Creation de x0 et x1, dont nb1 = x1 * B^m + x0 /// if(nb1.nbEl <= m) { x0 = clone(nb1); empilerListe(&x1, 0); } else { for(i = 0; i < m; i += 1) { empilerListe(&x0, nb1.fin->valeur); nb1.fin = nb1.fin->precedent; } while(!listeVide(nb1)) { empilerListe(&x1, nb1.fin->valeur); nb1.fin = nb1.fin->precedent; } } /// Creation de y0 et y1, dont nb2 = y1 * B^m + y0 /// if(nb2.nbEl <= m) { y0 = clone(nb2); empilerListe(&y1, 0); } else { for(i = 0; i < m; i += 1) { empilerListe(&y0, nb2.fin->valeur); nb2.fin = nb2.fin->precedent; } while(!listeVide(nb2)) { empilerListe(&y1, nb2.fin->valeur); nb2.fin = nb2.fin->precedent; } } /// On enlève les 0 devant x0, x1, y0 et y1, car la taille du nombre est importante dans l'execution de l'algorithme de karatsuba /// nettoyerNb(&x0); nettoyerNb(&x1); nettoyerNb(&y0); nettoyerNb(&y1); /// Calculs d'après l'algorithme de karatsuba (voir description) /// p0 = multiplication(x0, y0); p2 = multiplication(x1, y1); tmp = addition(x0, x1); tmp2 = addition(y0, y1); p1 = multiplication(tmp, tmp2); viderListe(&tmp); viderListe(&tmp2); viderListe(&x0); viderListe(&x1); viderListe(&y0); viderListe(&y1); tmp = soustraction(p1, p2); p1 = soustraction(tmp, p0); viderListe(&tmp); puissancede10(&p1, m); puissancede10(&p2, (m * 2)); tmp = addition(p0, p2); resultat = addition(p1, tmp); viderListe(&tmp); /// Gestion du signe du résultat /// resultat.signe = signe_nb1 * signe_nb2; return resultat; }
/** DEBUT BIGINT soustraction(BIGINT, BIGINT); DEBUT **/ BIGINT soustraction(BIGINT nb1, BIGINT nb2) { BIGINT resultat; int tmp; unsigned int retenue = 0; initListe(&resultat); //nettoyerNb(&nb1); //nettoyerNb(&nb2); if(egal_zero(nb2)) return clone(nb1); else if(egal_zero(nb1)) { nb2.signe = nb2.signe * -1; return clone(nb2); } /// Gestion du signe du résultat /// if(nb1.signe == MOINS && nb2.signe == PLUS) { nb1.signe = PLUS; resultat = addition(nb1, nb2); resultat.signe = MOINS; return resultat; } else if(nb1.signe == PLUS && nb2.signe == MOINS) { nb2.signe = PLUS; resultat.signe = PLUS; return resultat = addition(nb1, nb2); } else if(nb1.signe == MOINS && nb2.signe == MOINS) { BIGINT tmp = nb1; nb1 = nb2; nb2 = tmp; nb2.signe = PLUS; nb1.signe = PLUS; } if(comparer_nb(nb1, nb2) == INF) { BIGINT tmp = nb1; nb1 = nb2; nb2 = tmp; resultat.signe = MOINS; } /// Necessaire si nb2.nbEl > nb1.nbEl, il faut finir la soustraction avec le reste des chiffres de nb2.nbEl /// /** J'ai séparé volontairement cette condition de la boucle principale, pour éviter une condition qui n'est pas nécessaire ** dans le cas ou nb2.nbEl = nb1.nbEl. Cela ajoute une répétition dans l'ecriture mais un léger gain en performance **/ while(!listeVide(nb2)) { tmp = (nb1.fin->valeur - retenue - nb2.fin->valeur); if(nb1.fin->valeur > 0) retenue = 0; if(tmp < 0) { tmp = tmp + 10; retenue = 1; } empilerListe(&resultat, tmp % 10); nb1.fin = nb1.fin->precedent; nb2.fin = nb2.fin->precedent; } /// Necessaire si nb1.nbEl > nb2.nbEl, il faut finir la soustraction avec le reste des chiffres de nb1.nbEl /// /** J'ai séparé volontairement cette condition de la boucle principale, pour éviter une condition qui n'est pas nécessaire ** dans le cas ou nb1.nbEl = nb2.nbEl. Cela ajoute une répétition dans l'ecriture mais un léger gain en performance **/ while(!listeVide(nb1)) { tmp = nb1.fin->valeur - retenue; if(nb1.fin->valeur > 0) retenue = 0; if(tmp < 0) { tmp = tmp + 10; retenue = 1; } empilerListe(&resultat, tmp % 10); nb1.fin = nb1.fin->precedent; } nettoyerNb(&resultat); return resultat; }