Re: Type casting C++

Messaggioda Super Squirrel » 27/01/2015, 14:55

Ho avuto alcune difficoltà a capire alcuni passaggi visto che non conosco struct e vector, cmq il programma sembra funzionare anche se i controlli sull'inserimento non sono molto curati.
per esempio
2/0 ----> 2/1
0/2 ---> 0/2
1/-2 ----> non lo legge
3// ---> 3/1
. ----> 0/1
2.3.4 --->23/10

mi scuso se ho frainteso io le finalità del programma

La lettura dei due numeri funziona solo se l'utente scrive correttamente, inoltre si aspetta esattamente l'espressione NUMERO/NUMERO.


l'algoritmo funziona sia per x/y (dove x e y possono essere interi o decimali, positivi o negativi) sia per x (intero o decimale, positivo o negativo).
ho aggiunto anche i controlli sull'inserimento(caratteri validi e loro limitazioni, divisione per 0, successione validi di caratteri validi...):

Codice:
#include <iostream>
#include <cstdint>
#include <string>
#include <cstdlib>

int64_t mcd(int64_t a, int64_t b)
{
    if(a < 0)
    {
        a = -a;
    }
    int64_t r = a % b;
    while(r != 0)
    {
        a = b;
        b = r;
        r = a % b;
    }
    return b;
}

void normalizza_frazione(int64_t &num, int64_t &den)
{
    if(num == 0)
    {
        den = 1;
    }
    else
    {
        if(den < 0)
        {
            num = -num;
            den = -den;
        }
        int64_t c = mcd(num, den);
        num = num / c;
        den = den / c;
    }
}

void prodotto_frazione(int64_t &num_1, int64_t &den_1, int64_t num_2, int64_t den_2)
{
    num_1 = num_1 * num_2;
    den_1 = den_1 * den_2;
    normalizza_frazione(num_1, den_1);
}

void inserisci_frazione(int64_t &num, int64_t &den, bool &x)
{
    num = 0;
    den = 1;
    int64_t a = 1, b = 1, c = 1;
    int virgola = 0, meno = 0, fratto = 0, v_1, v_2, m_1, m_2, f;
    x = 1;
    std::string v;
    std::cin >> v;
    for(int i = 0; i < v.size(); i++)
    {
        if(v[i] < '-' || v[i] > '9')
        {
            x = 0;
            break;
        }
        if(v[i] == '.')
        {
            virgola++;
            if(virgola > 2)
            {
                x = 0;
                break;
            }
            if(virgola == 1)
            {
                v_1 = i;
            }
            else
            {
                v_2 = i;
            }
        }
        if(v[i] == '-')
        {
            meno++;
            if(meno > 2)
            {
                x = 0;
                break;
            }
            if(meno == 1)
            {
                m_1 = i;
            }
            else
            {
                m_2 = i;
            }
        }
        if(v[i] == '/')
        {
            fratto++;
            if(fratto > 1)
            {
                x = 0;
                break;
            }
            f = i;
        }
    }
    while(x == 1)
    {
        if(virgola > 0)
        {
            if(v[v_1 - 1] < '0' || v[v_1 + 1] < '0')
            {
                x = 0;
                break;
            }
            if(virgola == 2)
            {
                if(v[v_2 - 1] < '0' || v[v_2 + 1] < '0' || fratto == 0 )
                {
                    x = 0;
                    break;
                }
            }
        }
        if(meno > 0)
        {
            if(v[m_1 + 1] < '0')
            {
                x = 0;
                break;
            }
            if(meno == 2)
            {
                if(v[m_2 + 1] < '0' || fratto == 0)
                {
                    x = 0;
                    break;
                }
            }
        }
        if(fratto > 0)
        {
            if(v[f - 1] < '0')
            {
                x = 0;
                break;
            }
            if(virgola == 2)
            {
                if(v_1 > f || v_2 < f)
                {
                    x = 0;
                    break;
                }
            }
            if(meno == 2)
            {
                if(m_1 > f || m_2 < f)
                {
                    x = 0;
                    break;
                }
            }
        }
        break;
    }
    if(x == 1)
    {
       for(int i = v.size(); i > -1; i--)
       {
           if(v[i] > '/' && v[i] < ':')
           {
               num = num + (v[i] - '0') * c;
               c = c * 10;
           }
           if(v[i] == '-')
           {
               num = -num;
           }
           if(v[i] == '.')
           {
               den = c;
           }
           if(v[i] == '/')
           {
               a = num;
               b = den;
               num = 0;
               den = 1;
               c = 1;
           }
       }
       if(a != 0)
       {
           prodotto_frazione(num, den, b, a);
       }
       else
       {
           x = 0;
       }
    }
    if(x == 0)
    {
        std::cout << std::endl << "Inserimento non valido";
    }
}

void mostra_frazione(int64_t num, int64_t den)
{
    normalizza_frazione(num, den);
    if(den == 1)
    {
    std::cout << num << "\t";
    }
    else
    {
    std::cout << num << "/" << den << "\t";
    }
}

int main()
{
    int64_t a , b;
    bool x;
    std::cout << "Caratteri validi: . - / 0 1 2 3 4 5 6 7 8 9";
    std::cout << std::endl << std::endl << "Inserire valore: ";
    inserisci_frazione(a, b, x);
    if(x == 1)
    {
        std::cout << std::endl << "Frazione ridotta: ";
        mostra_frazione(a, b);
    }
    std::cout << std::endl <<std::endl;
    system("PAUSE");
}


credo di aver preso in considerazione ogni controllo sull'inserimento, in caso contrario ogni critica è ben accetta.
Chi dorme in democrazia, si sveglia in dittatura.
Super Squirrel
Senior Member
Senior Member
 
Messaggio: 34 di 1486
Iscritto il: 16/05/2013, 22:05

Re: Type casting C++

Messaggioda vict85 » 27/01/2015, 15:15

Ho dato per scontato che l'utente inserisse il - solo al numeratore e ho accolto le considerazioni di claudio86 sul fatto che /2 volesse essere un 1/2, che .2 fosse un 0.2 e che 2. fosse uguale a 2 . Il fatto che . fosse uguali a 0.0 è stato la conseguenza diretta. Il mio programma avrebbe potuto tranquillamente accogliere 2/0 ma pur di supporre che 2/ fosse uguale a 2 ho dovuto assicurarmi che non ponessi mai a 0 il denominatore (nel momento in cui veniva un / si deve porre a 0 il denominatore per assicurarsi che l'algoritmo ricorsivo funzioni).

In un certo senso ho scritto un algoritmo che cercasse di interpretare il risultato anche in caso di errore di inserimento, seppur in caso di situazioni non contemplate blocchi l'esecuzione del programma e inserisca nel vettore il numero generato finora. È possibilissimo modificare il programma in modo che inserisca il valore solo quando il numero è inserito correttamente.

P.S.: Se ho capito bene il tuo corso di programmazione è finito. Pertanto DISINSTALLA DEV-C++ e installa code::blocks, codelite oppure visual studio community 2013. Oppure ancora usa notepad++ (o altri editor di testo seri) insieme al terminale. Quel programma viene ancora usato solo perché i professori universitari sono pigri e non hanno voglia di installare code::blocks su tutti i pc dell'università. Ma è attualmente il peggio che puoi trovare sul “mercato”. Legato a questo elimina la riga system("PAUSE");
vict85
Moderatore
Moderatore
 
Messaggio: 7288 di 19253
Iscritto il: 16/01/2008, 00:13
Località: Berlin

Re: Type casting C++

Messaggioda vict85 » 27/01/2015, 15:50

Ora è molto più restrittivo nell'accettare elementi. Seppur non presenti alcun codice che informa l'utente dell'errore.

Codice:
#include <cctype>
#include <iostream>
#include <cstdint>
#include <string>
#include <vector>

typedef int64_t i64;

struct frac {
   i64 num, den;
};

void leggi_frazione(char const b[], std::vector<frac> &v);
void leggi_frazione2(char const b[], std::vector<frac> &v, frac &f, i64 sgn, i64 fs, i64 ds);

int main()
{
   std::cout << "Inserisci le frazioni separati da spazi in uno dei seguenti modi: " << std::endl;
   std::cout << "1) Numero intero   es.: 1234  " << std::endl;
   std::cout << "2) Frazione        es.: 12/5 " << std::endl;
   std::cout << "3) numero decimale es.: 12.34" << std::endl;
   std::cout << "L'inserimento di caratteri diversi da quelli indicati terminera' la lettura " << std::endl;

   std::string s;
   std::getline(std::cin, s);
   std::vector<frac> v;
   leggi_frazione(s.c_str(), v);

   std::cout << "Valori letti : " << std::endl;
   for (frac f : v)
   {
      std::cout << f.num << '/' << f.den << ' ';
   }
   std::cout << std::endl;
}

void leggi_frazione(char const b[], std::vector<frac> &v)
{
   frac f = frac{ 0, 1 };

   // variabili di stato
   i64 sgn = 1;
   i64 fs = 0;
   i64 ds = 0;

   char const c = b[0];

   // stringa terminata
   if (c == '\0')
      return;

   // considera il segno
   if (c == '-')
   {
      sgn = -1;
      char const c2 = b[1];
      if (isdigit(c2))
         leggi_frazione2(b + 2, v, f, sgn, fs, ds);
      else
         return;
   }
   // ignora spazi iniziali
   else if (isspace(c))
   {
      leggi_frazione(b + 1, v);
   }
   // caso standard del numero
   else if (isdigit(c))
   {
      f.num = c - '0';
      leggi_frazione2(b + 1, v, f, sgn, fs, ds);
   }
}

void leggi_frazione2(char const b[], std::vector<frac> &v, frac &f, i64 sgn, i64 fs, i64 ds)
{
   char const c = b[0];

   if (c == '\0')
   {
      f.num *= sgn;
      v.push_back(f);
      return;
   }

   // modo alternativo per concludere
   if (isspace(c))
   {
      f.num *= sgn;
      v.push_back(f);
      leggi_frazione(b + 1, v);
   }
   // considera il caso in cui ci sia / o .
   else if (ispunct(c))
   {
      if (c == '/')
      {
         if (fs != 0 || ds != 0) // ERRORE DI INSERIMENTO
         {
            return;
         }
         else
         {
            fs = 1;
            char const c2 = b[1];
            if (isdigit(c2))
            {
               f.den = c2 - '0';
               leggi_frazione2(b + 2, v, f, sgn, fs, ds);
            }
            else if (c2 == '-')
            {
               sgn = -sgn;
               char const c3 = b[2];
               if (isdigit(c3))
               {
                  f.den = c3 - '0';
                  leggi_frazione2(b + 3, v, f, sgn, fs, ds);
               }
            }
            else
               return;
         }
      }
      else if (c == '.')
      {
         if (fs != 0 || ds != 0) // ERRORE DI INSERIMENTO
         {
            return;
         }
         else
         {
            ds = 1;
            char const c2 = b[1];
            if (isdigit(c2))
            {
               f.num *= 10;
               f.num += c2 - '0';
               f.den = 10;
               leggi_frazione2(b + 2, v, f, sgn, fs, ds);
            }
            else
               return;
            
         }
      }
   }
   // caso standard del numero
   else if (isdigit(c))
   {
      if (fs == 0)
      {
         f.num *= 10;
         f.num += c - '0';
      }
      else
      {
         f.den *= 10;
         f.den += c - '0';
      }

      if (ds != 0)
      {
         f.den *= 10;
      }
      leggi_frazione2(b + 1, v, f, sgn, fs, ds);
   }

}
vict85
Moderatore
Moderatore
 
Messaggio: 7289 di 19253
Iscritto il: 16/01/2008, 00:13
Località: Berlin

Re: Type casting C++

Messaggioda Super Squirrel » 27/01/2015, 16:18

P.S.: Se ho capito bene il tuo corso di programmazione è finito. Pertanto DISINSTALLA DEV-C++ e installa code::blocks, codelite oppure visual studio community 2013. Oppure ancora usa notepad++ (o altri editor di testo seri) insieme al terminale. Quel programma viene ancora usato solo perché i professori universitari sono pigri e non hanno voglia di installare code::blocks su tutti i pc dell'università. Ma è attualmente il peggio che puoi trovare sul “mercato”. Legato a questo elimina la riga system("PAUSE");


Si, allora il prof mi fece scaricare dev, ma da quando ho iniziato il programma sul rango e determinante di una matrice sto usando code::blocks ed effettivamente è tutta un'altra storia.
Per quanto riguarda la riga system("PAUSE"), se la tolgo e faccio partire il programma tramite code::blocks non ci sono problemi in quanto la chiusura del programma in questo caso non è automatica; se invece faccio partire l'exe direttamente(doppio clic sul file .exe per intenderci), la chiusura del programma è automatica.

Quindi se tolgo system("PAUSE") come posso impedire che il programma avviato direttamente dall'exe si chiuda??
Chi dorme in democrazia, si sveglia in dittatura.
Super Squirrel
Senior Member
Senior Member
 
Messaggio: 35 di 1486
Iscritto il: 16/05/2013, 22:05

Re: Type casting C++

Messaggioda vict85 » 27/01/2015, 17:41

Il modo più semplice consiste nell'aprire un terminale o una powershell e far partire il programma da lì. Altrimenti si può scrivere materialmente un codice equivalente o quasi (anche se spesso si finisce per usare conio.h che non è standard né portabile).
vict85
Moderatore
Moderatore
 
Messaggio: 7291 di 19253
Iscritto il: 16/01/2008, 00:13
Località: Berlin

Re: Type casting C++

Messaggioda Super Squirrel » 27/01/2015, 20:41

So che è molto poco elegante come cosa, ma potrebbe andare?
almeno così il programma sarebbe portabile e non ci sarebbe bisogno di aprirlo tramite code::block o prompt dei comandi.

Codice:
#include <iostream>

int main()
{
    std::cout << "HELLO!" << std::endl;
    char a;
    std::cout << "INSERIRE UN CARATTERE PER USCIRE: ";
    std::cin >> a;
}
Chi dorme in democrazia, si sveglia in dittatura.
Super Squirrel
Senior Member
Senior Member
 
Messaggio: 36 di 1486
Iscritto il: 16/05/2013, 22:05

Re: Type casting C++

Messaggioda vict85 » 27/01/2015, 21:09

Può andare. Anche se cin.get() è meglio.

Vedi anche qui sul perché chiamare system non è una buona cosa:
http://www.gidnetwork.com/b-61.html

Comunque puoi anche creare un file .bat (o .ps1) che contiene
Codice:
nome_file.exe
pause

e poi fai partire il bat invece che l'exe (il .ps1 potrebbe necessitare qualche operazione aggiuntiva per via delle sicurezze di windows). Chiama il programma pause dopo che la tua funzione ha concluso, ma non lo fa all'interno del tuo programma. Inoltre non modifichi in alcun modo il tuo programma massimizzando la portabilità. Di fatto code::blocks fa esattamente questo solo che gestisce lui questa operazione.
vict85
Moderatore
Moderatore
 
Messaggio: 7298 di 19253
Iscritto il: 16/01/2008, 00:13
Località: Berlin

Re: Type casting C++

Messaggioda claudio86 » 27/01/2015, 21:21

Vorrei rispondere con più calma ad alcuni punti, ma purtroppo in questo periodo il tempo libero tende a zero. Magari ci tornerò tra qualche giorno.

Intanto faccio un commento veloce su system("PAUSE"). Probabilmente ti sembra più comodo e veloce fare doppio click sul programma invece che farlo partire da una console, però in realtà la console diventerà parecchio più versatile man mano che ti abituerai. Potrai redirigere l'output su un file, passare argomenti ai tuoi programmi, concatenare diversi comandi, usare altre utility di terze parti (es. pandoc, ffmpeg, imagemagick…), se passerai ad altri linguaggi potrai usare il loro REPL (anche se in realtà ci sono interpreti per il C++, vedi Cling).
Semplicemente, lancia le applicazioni console da una console (a parte quando le lanci direttamente da Code::Blocks / Visual Studio).

Obietterai che il prompt dei comandi di Windows è orrendo. Concordo. Prova Cmder.
"This theorem, as many others, is proven by writing zero in a creative way…"
claudio86
Senior Member
Senior Member
 
Messaggio: 413 di 1130
Iscritto il: 09/01/2011, 15:12

Re: Type casting C++

Messaggioda vict85 » 27/01/2015, 22:20

claudio86 ha scritto:Obietterai che il prompt dei comandi di Windows è orrendo. Concordo. Prova Cmder.


Microsoft concorda con te, tanto che hanno creato la powershell (di cui non so molto). Sostanzialmente è una eredità troppo difficile da estirpare e sostituire che preferiscono non metterci le mani.
vict85
Moderatore
Moderatore
 
Messaggio: 7300 di 19253
Iscritto il: 16/01/2008, 00:13
Località: Berlin

Re: Type casting C++

Messaggioda claudio86 » 27/01/2015, 23:17

Testo nascosto, perché contrassegnato dall'autore come fuori tema. Fai click in quest'area per vederlo.
vict85 ha scritto:
claudio86 ha scritto:Obietterai che il prompt dei comandi di Windows è orrendo. Concordo. Prova Cmder.


Microsoft concorda con te, tanto che hanno creato la powershell (di cui non so molto). Sostanzialmente è una eredità troppo difficile da estirpare e sostituire che preferiscono non metterci le mani.


Credo che con Powershell abbiano solo migliorato la shell, ma non il terminale. Un po' come su Linux puoi usare bash, bb, zsh, csh (python, ruby…) come shell, e Terminal, Konsole, xterm… come terminale. Cmder è più un terminale, come shell usa cmd o powershell (python, ruby… forse si riesce anche bash, io non ho intenzione di provarci).
"This theorem, as many others, is proven by writing zero in a creative way…"
claudio86
Senior Member
Senior Member
 
Messaggio: 414 di 1130
Iscritto il: 09/01/2011, 15:12

Precedente

Torna a Informatica

Chi c’è in linea

Visitano il forum: Nessuno e 1 ospite