Overflow

di il
11 risposte

Overflow

Ciao ragazzi, vi propongo un semplice codice per il calcolo dell'MCD:

long a, b, mcd = 1, min, i;
    
    printf("Inserire il primo valore: ");
    scanf("%ld", &a);
    printf("Inserire il secondo valore: ");
    scanf("%ld", &b);
    printf("\n");
    
    if ((a == 0) && (b == 0))
    {
        mcd = 0;
    }
    else
    {
        if (a < b)
            min = a;
        else
            min = b;
        
        for (i = 2; i <= min; i++)
            if ((a%i == 0) && (b%i == 0) && (i > mcd))
                mcd = i;
    }
    
    printf("MCD(%ld,%ld) = %ld", a, b, mcd);
Funziona perfettamente finché i numeri sono piccoli.
Il problema è quando ad esempio come input gli do a =2103338580 e b=1353413460.
Come faccio a gestire numeri così grandi?

11 Risposte

  • Re: Overflow

    Ti suggerisco l'algoritmo presentato qui
    Aggiungo anche questo link
  • Re: Overflow

    candaluar ha scritto:


    Ti suggerisco l'algoritmo presentato qui
    Aggiungo anche questo link
    Grazie mille per la risposta.
    Ho visto l'algoritmo in questione, e se il mio obiettivo fosse ottimizzare il calcolo probabilmente lo seguirei.

    Però mi sto preparando ad un esame di Programmazione e mi esercito sin da subito ad ideare l'algoritmo solo ed esclusivamente con la mia testa (senza poter sbirciare null'altro). La mia testa ha ideato il codice proposto.
    Se durante l'esame ideassi un qualcosa di simile, vorrei capire perché non funziona, in modo da poter affrontare la situazione.

    Per quanto riguarda il mio algoritmo, penso sia un problema di grandezza dell'input. Come fare per gestire numeri così grandi? Pensavo che long fosse il tipo più adatto..
  • Re: Overflow

    Però mi sto preparando ad un esame di Programmazione e mi esercito sin da subito ad ideare l'algoritmo solo ed esclusivamente con la mia testa (senza poter sbirciare null'altro). La mia testa ha ideato il codice proposto.
    Sull'algoritmo che hai scritto ti suggerisco solo di invertire il for... in fin dei conti devi trovare il massimo, non tutti i divisori
    for (i = min; i >= 1; i--)
                if ((a%i == 0) && (b%i == 0) )
                {
                    mcd = i;
                    break;
                }
    Per quanto riguarda il mio algoritmo, penso sia un problema di grandezza dell'input.
    Ma chi è che ti da errore? Qual è?
    Come fare per gestire numeri così grandi? Pensavo che long fosse il tipo più adatto..
    Dipende da ambiente (32/64bit, Linux, Windows ...) e compilatore.
    Comunque, se vuoi guadagnare un ulteriore bit, puoi sempre utilizzare unsigned long al posto di long.
  • Re: Overflow

    Il long ha comunque dei limiti (poco più di 2 miliardi). Usa una unsigned long long (intero senza segno a 64 bit) se il tuo compilatore lo supporta (anche questo ha dei limiti ma per un esercizio va bene).
  • Re: Overflow

    Semplicemente non puoi utilizzare numeri così grandi perchè sono troppo grandi per il sistema operativo.
    come ti hanno suggerito puoi usare unsigned long long, accetta solo numeri positivi (senza segno) e togliendo il bit di segno hai un bit in più per i numeri.
  • Re: Overflow

    Se può interessare, e se può fornire qualche spunto per degli esercizi, aggiungo che in PHP esistono delle funzioni per lavorare con valori numerici di dimensione arbitraria che lavorano con una rappresentazione dei dati su stringhe.
  • Re: Overflow

  • Re: Overflow

    Quoto appieno Oregon. Come validamente accennato qui, i limiti dei tipi numerici dipendono strettamente dal compilatore, anche in funzione dall'architettura target. L'articolo cita inoltre le principali librerie gratuite per aritmetica intera a precisione arbitraria.

    Comunque il reale problema consiste unicamente nella scelta dell'algoritmo e nell'impostazione dell'esercizio, tutto il resto è decisamente secondario.

    PHP è l'ultima cosa a cui pensare : semmai in Python la gestione trasparente di tipi numerici interi di dimensione arbitraria è una validissima alternativa, molto ben implementata e ragionevolmente efficiente, considerando la natura del linguaggio.

    Riporto per l'ennesima volta un sorgente didattico, utile a determinare rapidamente gli intervalli numerici supportati dai compilatori mainstream più diffusi.
    
    /************************************************************************/
    /** Visualizza i limiti di campo per i tipi numerici di default.       **/
    /** Include la gestione dei tipi a 64 bit.                             **/
    /** Adatto ai seguenti compilatori:                                    **/
    /** - Intel C/C++                                                      **/
    /** - Borland C/C++                                                    **/
    /** - Microsoft Visual C/C++                                           **/
    /** - Digital Mars                                                     **/
    /** - Open Watcom                                                      **/
    /** - GCC e derivati                                                   **/
    /************************************************************************/
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    #include "int64bit.h"
    
    #define BUFF_SIZE 64
    
    #define H_SEP_STAR "************************************************************"
    #define H_SEP_LINE "------------------------------------------------------------"
    
    /*
    ** Inserisce i separatori di migliaia (europei) in una stringa numerica.
    */
    char *numfmt(const char *in, char *out)
    {
        int p = 0;
        int size = strlen(in) * 4 / 3;
    
        memset(out, ' ', size);
        out += size +1;
        *out-- = '\0';
        in += strlen(in) -1;
    
        do
        {
            if ((p > 0) && (0 == (p % 3)))
            {
                *out-- = '.';
            }
            *out-- = *in--;
            ++p;
        } while (isdigit(*in) || ('-' == *in));
    
        return ++out;
    }
    
    /************************************************************************/
    
    int main(void)
    {
        char num_buff[BUFF_SIZE+1];
        char fmt_buff[BUFF_SIZE+1];
    
        printf("\n%s\n%s\n%s\n", H_SEP_STAR, Compiler, H_SEP_STAR);
        printf("- UNSIGNED:\n"
               "char...........: [0, %u] (%d bits per char)\n",
               UCHAR_MAX, CHAR_BIT);
    
        snprintf(num_buff, BUFF_SIZE, "%u", USHRT_MAX);
        printf("short int......: [0, %s]\n", numfmt(num_buff, fmt_buff));
    
        snprintf(num_buff, BUFF_SIZE, "%lu", UINT_MAX);
        printf("int............: [0, %s]\n", numfmt(num_buff, fmt_buff));
    
        snprintf(num_buff, BUFF_SIZE, "%lu", ULONG_MAX);
        printf("long int.......: [0, %s]\n", numfmt(num_buff, fmt_buff));
    
    /* Forma alternativa, valida per vari compilatori Windows legacy:
    #if defined(_UI64_MAX)
        _ui64toa(_UI64_MAX, num_buff, 10);
        printf("long int 64....: [0, %s]\n", numfmt(num_buff, fmt_buff));
    #endif
    */
    
    #if defined(UINT64_MAX)
        snprintf(num_buff, BUFF_SIZE, "%"PRIu64, UINT64_MAX);
        printf("long int 64....: [0, %s]\n", numfmt(num_buff, fmt_buff));
    #endif
    
        puts(H_SEP_LINE);
        printf("- SIGNED:\n"
               "char...........: [%d, %d]\n", SCHAR_MIN, SCHAR_MAX);
    
        snprintf(num_buff, BUFF_SIZE, "%d", SHRT_MIN);
        printf("short int......: [%s", numfmt(num_buff, fmt_buff));
        snprintf(num_buff, BUFF_SIZE, "%d", SHRT_MAX);
        printf(", %s]\n", numfmt(num_buff, fmt_buff));
    
        snprintf(num_buff, BUFF_SIZE, "%d", INT_MIN);
        printf("int............: [%s", numfmt(num_buff, fmt_buff));
        snprintf(num_buff, BUFF_SIZE, "%d", INT_MAX);
        printf(", %s]\n", numfmt(num_buff, fmt_buff));
    
        snprintf(num_buff, BUFF_SIZE, "%d", LONG_MIN);
        printf("long int.......: [%s", numfmt(num_buff, fmt_buff));
        snprintf(num_buff, BUFF_SIZE, "%ld", LONG_MAX);
        printf(", %s]\n", numfmt(num_buff, fmt_buff));
    
    #if defined(INT64_MAX)
        snprintf(num_buff, BUFF_SIZE, "%"PRId64, INT64_MIN);
        printf("long int 64....: [%s,\n", numfmt(num_buff, fmt_buff));
        snprintf(num_buff, BUFF_SIZE, "%"PRId64, INT64_MAX);
        printf("                   %s]\n", numfmt(num_buff, fmt_buff));
    #endif
    
        /************************************************************************/
    
        puts(H_SEP_STAR);
        puts("- FP IEEE 754:");
        printf("float..........: [%g, %g]\n", FLT_MIN, FLT_MAX);
        printf("double.........: [%g, %g]\n", DBL_MIN, DBL_MAX);
        printf("long double....: [%Lg, %Lg]\n", LDBL_MIN, LDBL_MAX);
    
        puts(H_SEP_LINE);
        printf("FLT_EPSILON....: %g\n", FLT_EPSILON);
        printf("DBL_EPSILON....: %g\n", DBL_EPSILON);
        printf("LDBL_EPSILON...: %Lg\n", LDBL_EPSILON);
        puts(H_SEP_STAR);
    
        return 0;
    }
    /* EOF: TestLim.c */
    
    Lo header file associato:
    
    #ifndef __INT64BIT_H__
    #define __INT64BIT_H__
    
    #include <limits.h>
    #include <float.h>
    
    #if defined(__BORLANDC__)
        const char Compiler[] = "** Compiled with Borland C++"
                                "                              **";
     #if __BORLANDC__ >= 1400
         #include <stdint.h>
     #elif defined(_UI64_MAX)
         /* __BORLANDC__ >= 0x400 */
         typedef unsigned __int64 uint64_t;
         #define UINT64_MAX _UI64_MAX
         #define INT64_MAX _I64_MAX
         #define INT64_MIN _I64_MIN
     #endif
     #ifndef PRIu64
         #define PRIu64 "I64u"
         #define PRId64 "I64d"
     #endif
    #endif
    
    #if defined(_MSC_VER)
        const char Compiler[] = "** Compiled with Visual C/C++"
                                "                             **";
     #if _MSC_VER > 1500
         #include <stdint.h>
     #elif defined(_UI64_MAX)
         /* _MSC_VER >= 900 */
         typedef unsigned __int64 uint64_t;
         #define UINT64_MAX _UI64_MAX
         #define INT64_MAX _I64_MAX
         #define INT64_MIN _I64_MIN
     #endif
     #ifndef PRIu64
         #define PRIu64 "I64u"
         #define PRId64 "I64d"
     #endif
    #endif
    
    #if defined(__WATCOMC__)
        const char Compiler[] = "** Compiled with Open Watcom"
                                "                              **";
        #include <inttypes.h>
    #endif
    
    #if defined(__DMC__)
        const char Compiler[] = "** Compiled with Digital Mars"
                                "                             **";
        #include <inttypes.h>
    #endif
    
    #if defined(__INTEL_COMPILER)
        const char Compiler[] = "** Compiled with INTEL C    "
                                "                             **";
        #include <inttypes.h>
    #endif
    
    #if defined(__GNUC__)
        const char Compiler[] = "** Compiled with GCC         "
                                "                             **";
        #include <inttypes.h>
    #endif
    
    #endif /* __INT64BIT_H__ */
    /* EOF: int64bit.h */
    
  • Re: Overflow

    Scusatemi ragazzi!
    Innanzitutto grazie mille a tutti per le risposte. Purtroppo però non riesco a risolvere il problema dell'overflow!
    Provo a fare un esempio più pratico: se ho un automa che ha 1000 stati possibile ed ogni stato è il quadrato dello stato precedente, come faccio a trovare il valore dell'automa allo stato i-esimo abbastanza grande?

    Esempio:
    allo stato i = 0, s[0] = 39
    allo stato i = 1, s[1] = 39*39 = 1521
    allo stato i = 2, s[2] = 1521*1521
    ecc..

    Come faccio a sapere il valore dell'automa in s[50]?
    Ovviamente il mio codice che gestisce s come tipo unsigned long mi da 0, essendo troppo grande per riuscire a calcolarlo..
  • Re: Overflow

    Ti si è detto come fare ... Usa quelle librerie...
  • Re: Overflow

    Io farei così in modo da evitare numeri troppo grandi e risparmiare tempo (cerchiamo il più grande non il più piccolo tra i divisori).
Devi accedere o registrarti per scrivere nel forum
11 risposte