Sviluppo di REALI_ENORMI

Progettiamo una stuttura dati per i reali enormi.
Decidiamo di utilizzare due array, uno per le cifre (quindi caratteri) intere ed uno per quelle decimali, inoltre il numero sarà rappressentato utilizzando anche degli zeri inutili, pertanto ci saranno sempre 50 cifre intere e 50 cifre decimali.
Il segno sarà tenuto a parte.
Un reale enorme
in in-1 ... i1 i0, d0 d1 ... dm-1 dm
viene così realizzato:

La corrispondente dichiarazione di tipo C è
typedef char CIFRE[50];

typedef REALE_ENORME struct 
    {   char Segno;
        CIFRE Decimale, Intera;
    };
Sviluppiamo ora le varie funzioni che appaiono nell'interfaccia del modulo.
Scrittura di un reale enorme
void Scrittura_Reale_Enorme(REALE_ENORME re)
{   
    int i, j;

    if(re.Segno == '-')
        Scrivi_Car('-');;
    for(i = 49; i >= 0 && re.Intera[i] == '0'; i--) ;
    if(i == -1) 
        Scrivi_Car('0');
    else 
        for( ; i >= 0 ; i--) Scrivi_Car(re.Intera[i]);
    for(i = 49; i >= 0 && re.Decimale[i] == '0'; i--) ;
    if(i != -1){
        Scrivi_Car(',');
        for( j = 0; j <=i ;j++) Scrivi_Car(re.Decimale[j]);
    }
}
Lettura di un reale enorme
REALE_ENORME Leggi_Reale_Enorme(void)
{  
    CIFRE cif;
    int i,j;
    REALE_ENORME re;
  
    re.Segno = Leggi_Car();
    if(re.Segno != '+' && re.Segno != '-')
        printf("ERRORE: un reale non puo\' iniziare con %c \n",re.Segno);
    Leggi_Cifre(cif,'\0');
   /* le cifre intere sono messe in cif aggiungendo '\0' per completare
       vengono poi riordinate oppurtunamente quando ricopiate in re.Intera */
    for(i=49; i >= 0 && cif[i] == '\0'; i--) 
        re.Intera[i]= '0';
    for(j = 0; i >= 0; i--,j++)
        re.Intera[j] = cif[ i];        
    Salta(',');
    Leggi_Cifre(re.Decimale,'0');
    return re;
}
che utilizza la funzione ausiliaria
void Leggi_Cifre(CIFRE cif,char c)
/*legge la sequenza di cifre decimali dal file `ingresso.txt' completa 
l'array con il carattere c*/
{
   int i;
  
   for(i=0; i < 50; i++)
        cif[i] = c;        
   for(i = 0; (i < 50) && (isdigit(Guarda_Car())); i++) 
       cif[i] = Leggi_Car();
}
Somma di due reali enormi
La somma di due numeri reali enormi re1 e re2 è definita come segue:
se re1 e re2 hanno lo stesso segno
segno di re1 (valore assoluto(re1) + valore assoluto(re2))
se re1 e re2 hanno segno diverso
se valore assoluto(re1) > valore assoluto(re2)
segno di re1 (valore assoluto(re1) - valore assoluto(re2))
se valore assoluto(re2) > valore assoluto(re1)
segno di re2 (valore assoluto(re2) - valore assoluto(re1))
se valore assoluto(re1) = valore assoluto(re2)
+ 0
REALE_ENORME Somma(REALE_ENORME re1, REALE_ENORME re2)
{  
    int j; 
    REALE_ENORME re; 
 
    if(re1.Segno == re2.Segno =='+'){  /*stesso segno*/
        re = Somma_Pos(re1, re2);
        re.Segno = re1.Segno;
    }
    else if(Maggiore_Assoluto(re1, re2)){ /*re1 è maggiore in valore assoluto di re2*/
        re = Differenza_Pos(re1, re2);
        re.Segno = re1.Segno;
    }
    else if(Maggiore_Assoluto(re2, re1)){ /*re2 è maggiore in valore assoluto di re*/
        re = Differenza_Pos(re2, re1);
             re.Segno = re2.Segno;
    }
    else /* re conterrà 0 */
       { re.Segno = '+';
         for(j = 0; j < 50; j++)
             re.Decimale[j] = re.Intera[j] = '0';         
       };
    return re;
}
che utilizza le seguenti funzioni ausiliarie
BOOL Maggiore_Assoluto(REALE_ENORME re1, REALE_ENORME re2)
/*vera ses re1 è maggiore strettamente di re2*/
{
    int i, sono_uguali = TRUE;

    for(i = 49; sono_uguali && (0 *lt;= i); i--)
        if(re1.Intera[i] != re2.Intera[i])
                sono_uguali = FALSE;
        if(! sono_uguali)
            return re1.Intera[i+1] > re2.Intera[i+1];
        else{  /* controllo parti decimali*/
             for(i=0; sono_uguali && i < 50; i++)
                if(re1.Decimale[i] != re2.Decimale[i])
                    sono_uguali = FALSE;
            if(! sono_uguali)
                return re1.Decimale[i-1] > re2.Decimale[i-1];
            else
                return FALSE;
            };
}
 
REALE_ENORME Somma_Pos(REALE_ENORME re1, REALE_ENORME re2)
{
    int x, riporto = 0, i;
    REALE_ENORME re;

    for(i = 49; i >= 0; i--){
        x = riporto + Num(re1.Decimale[i]) + Num(re2.Decimale[i]);
        if(x > 9){
            re.Decimale[i] = Cifra(x % 10);
            riporto = 1;
        }
        else {
            re.Decimale[i] = Cifra(x);
            riporto = 0;
        };
     };

    for(i = 0; i < 50; i++){
        x = riporto + Num(re1.Intera[i]) + Num(re2.Intera[i]);
       if(x > 9){
           re.Intera[i] = Cifra(x % 10);
           riporto = 1;
       }
       else {
           re.Intera[i] = Cifra(x);
           riporto = 0;
       };
    };

    if(riporto == 1)
        printf("OVERFLOW\n");

   return re;
}

char Cifra(int n)
{
    return n + '0';
}

int Num(char c)
{
    return c - '0';
}

REALE_ENORME Differenza_Pos(REALE_ENORME re1, REALE_ENORME re2)
/*differenza tra due numeri positivi, quando il primo è maggiore del secondo */
{
    int x, riporto = 0, i;
    REALE_ENORME re;
    
    for(i = 49 ; i >= 0; i--){
        if((Num(re1.Decimale[i]) + riporto) >= Num(re2.Decimale[i])){
            re.Decimale[i] = Cifra((Num(re1.Decimale[i]) + riporto) - Num(re2.Decimale[i]));
            riporto = 0;
        }
        else{
            re.Decimale[i] = Cifra((Num(re1.Decimale[i]) + riporto + 10) - Num(re2.Decimale[i]));
            riporto = -1;
       };
    };
    for(i = 0; i < 50 ; i ++){
        if((Num(re1.Intera[i]) + riporto) >= Num(re2.Intera[i])){
            re.Intera[i] = Cifra((Num(re1.Intera[i]) + riporto) - Num(re2.Intera[i]));
            riporto = 0;
        }
        else{
            re.Intera[i] = Cifra((Num(re1.Intera[i]) + riporto + 10) - Num(re2.Intera[i]));
            riporto = -1;
       };
    };
    if(riporto == -1)
        printf("ERRORE : re1 doveva essere piu\' grande\n");

    return re;
};
Differenza di due numeri reali
REALE_ENORME Differenza(REALE_ENORME re1, REALE_ENORME re2)
{
    re2.Segno = - re2.Segno;
    return Somma(re1, re2);
}
Prodotto di due numeri reali
Applicando la proprietà distributiva della somma rispetto al prodotto e notando che

in in-1 ... i1 i0, d0 d1 ... dm-1 dm

è uguale a

in* 10n + in-1* 10n-1 + ... + i1* 101 + i0* 100, d0* 101 + d1* 102 + ... + dm-1* 10m + dm* 10m+1

il prodotto è definito come segue:

REALE_ENORME Prodotto(REALE_ENORME re1, REALE_ENORME re2)
{
    int i;
    REALE_ENORME aux,aux1, re;
    char seg;

    /* segno*/
    seg = (re1.Segno == re2.Segno) ? '+' : '-';
    
    /*rendo re1,e re2 positivi*/
    re1.Segno = re2.Segno = '+';
    
    /* assegno 0 a re */
    for(i = 0 ; i <  50; i++)
        re.Intera[i] = re.Decimale[i] = '0';
    
    /* moltiplico per cifre decimali */
    for(i = 49 ; i >= 0 ; i--){
        aux = Per_Scalare(re1, Num(re2.Decimale[i]));
        aux1 = Per_10(aux, -(i+1));
        re = Somma(re, aux1);
    };

    /* moltiplico per cifre intere */
    for(i = 0 ; i < 50 ; i++){
        aux = Per_Scalare(re1, Num(re2.Intera[i]));
        aux = Per_10(aux, i);
        re = Somma(re, aux);
    };
    re.Segno = seg;
    return re;
 }
 
 REALE_ENORME Per_Scalare(REALE_ENORME re1, int n)
{
    int  riporto = 0, j, x;
    REALE_ENORME re;

    for(j = 49 ; j >= 0 ; j--){
        x = riporto + (n * Num(re1.Decimale[j])); 
        re.Decimale[j] = Cifra(x % 10);
        riporto = x / 10;
     };     
    for(j = 0 ; j < 50 ; j++){
        x = riporto + (n * Num(re1.Intera[j]));
        re.Intera[j] = Cifra(x % 10);
        riporto = x / 10;
    };
    if(riporto != 0)
        printf("OVERFLOW\n");
         
    re.Segno = re1.Segno;
    return re;
}

REALE_ENORME Per_10(REALE_ENORME re1, int i)
{
    REALE_ENORME re;
    int j;

    if(i == 0)  return re1;
    else if(i > 0){
        /* sposto indietro le vecchie cifre intere*/
        for(j = 49 - i ; j >= 0 ; j--)
            re.Intera[j + i] = re1.Intera[j];
        /* i cifre decimali diventano intere*/
        for(j = 0; j <= i-1 ; j++)
            re.Intera[(i - 1) - j] = re1.Decimale[j];
        /* sposto indietro le vecchie cifre decimali*/
        for(j = i; j <= 49 ; j++)
            re.Decimale[j - i] = re1.Decimale[j];
        /* aggiungo gli zeri decimali necessari */
            for(j = (49-i) + 1; j <= 49 ; j++)
            re.Decimale[j] = '0';
          re.Segno = re1.Segno;  
  return re;

   }
   else  /* i < 0 */
   {
       i = -i;
       /* sposto le vecchie cifre decimali*/
       for(j = 49 - i ; j >= 0 ; j--)
           re.Decimale[j + i] = re1.Decimale[j];
       /* i cifre intere diventano decimali*/
       for(j = 0; j <= i-1 ; j++)
           re.Decimale[ -j +(i -1)] = re1.Intera[j];
       /* sposto le vecchie cifre intere*/
       for(j = i; j <= 49 ; j++)
           re.Intera[j - i] = re1.Intera[j];
       /* aggiungo gli zeri interi necessari */
          for(j = 49-i+1; j <= 49 ; j++)
          re.Intera[j] = '0';
          re.Segno = re1.Segno;  
  return re;

  };
}
A questo punto abbiamo sviluppato due file che faranno parte del programma, l'interfaccia e il body di questo modulo; precisamente:
REALENORME.h e REALENORME.c.