Rappresentazioni Binarie di Numeri Decimali

Tutti sappiamo che gli uomini contano con dieci dita e quindi hanno sviluppato un sistema di numerazione decimale, mentre i computer utilizzano un sistema binario, perché nei circuiti la corrente o c’é (1) oppure non c’é (0), quindi i computer contano così perché hanno due dita? Il termine bit che è stato coniato difatti significa BInary digiT che in inglese dal latino significa appunto “due dita”. La conversione di un numero decimale intero positivo in binario è estremamente semplice, basta divederlo per 2, memorizzare il resto e riapplicare iterativamente la divisione sul risultato ottenuto finché questo non si azzera.

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

int main(int argc, char* argv[])
{
   int k = 67;
   char sRet[9] = "00000000";
   int i = 0;

   if (k > 255 || k < -127)
      return -1;

   while (true)
   {
      div_t dv = div(k, 2);
      if (dv.quot <= 0)
     {
         sRet[7 - i] = '1';
         break;
      }

      if (dv.rem == 0)
          sRet[7 - i] = '0';
      else
          sRet[7 - i] = '1';

      k = dv.quot;

      i++;
   }

   printf("La rappresentazione binaria di %d: %.8s", k, sRet);

   scanf_s("a");

   return 0;
}

Rappresentare un intero negativo è più complesso, occorre eliminare il segno, applicare l’algoritmo qui sopra e poi convertire il risultato facendone il complemento a due, tenendo presente che un numero binario negativo ha “1” come bit più significativo.

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

int main(int argc, char* argv[])
{
   int k = -67;
   char sRet[9] = "00000000";
   int i = 0;
   long lVal;
   char sVal[9];
   int j;

   if (k > 255 || k < -127)
      return -1;

   j = abs(k);

   while (true)
   {
      div_t dv = div(j, 2);
      if (dv.quot <= 0)
      {
           sRet[7 - i] = '1';
           break;
       }

       if (dv.rem == 0)
           sRet[7 - i] = '0';
       else
           sRet[7 - i] = '1';

        j = dv.quot;

        i++;
   }

   if ( k < 0)
   {
       lVal = atol(sRet);
       lVal -= 1;

       strcpy_s(sRet, "11111111");
        _ltoa_s(lVal, sVal, 10);
        j = (int)strlen(sVal);

       for (i = 7; i >= 0; i--)
       {
            if (sVal[j - 1] == '1')
	   sRet[i] = '0';
	j--;
	if (j - 1 < 0)
	   break;
        }
   }

   printf("La rappresentazione binaria di %d: %.8s\n", k, sRet);

   scanf_s("a");

   return 0;
}

Per la conversione dei numeri decimali razionali il compito diviene ancora più complicato perché la parte intera si converte come in precedenza, mentre la parte frazionaria si moltiplica per 2 fino a quando non si raggiunge 1, se questo non avviene abbiamo un ciclo all’infinito e quindi un numero razionale in binario diventa irrazionale, provate ad esempio con 0.1 per vedere come si comporta:

  1. 0.1 * 2 = 0.2
  2. 0.2 * 2 = 0.4
  3. 0.4 * 2 = 0.8
  4. 0.8 * 2 = 1.6
  5. 0.6 * 2 = 1.2
  6. 0.2 * 2 = 0.4

Come potete notare al punto 6 siamo nello stesso risultato del punto 2 e quindi abbiamo un ciclo infinito. Questo fenomeno causa dei problemi a gestire i dati valutari con dei numeri in virgola mobile, difatti si perdono dei valori negli arrotondamenti, che se fatte su piccole cifre non arrecano problemi, ma pensate ad una banca con milioni di movimentazioni e milioni di possibili arrotondamenti impercettibili unitariamente, ma che insieme danno come risultato una bella differenza. Per risolvere questo problema sono state creati dei tipi di dato appositi ( in Microsoft con la struttura CURRENCY da cui proviene COleCurrency di MFC ) formati da uno o più interi che hanno lo scopo di rappresentare la parte frazionaria di un numero razionale, che poi vengono fusi in un unico valore virtuale che presenta la precisione necessaria. Ovviamente più interi vengono usati più la velocità computazionale diminuisce.

Informazioni su Giampaolo Rossi

Sviluppatore di software gestionale da oltre 28 anni.
Questa voce è stata pubblicata in Programmazione e contrassegnata con . Contrassegna il permalink.