Visualizzazione dei risultati da 1 a 4 su 4
  1. #1

    [C++] Sottrazione ritorna risultato inaspettato

    Buonasera a tutti.
    Sto sviluppando un semplice programma per la gestione di un conto bancario. C'è però un piccolo bug che non riesco davvero ad eliminare: azzardo a dire sia un errore del compilatore.
    Posto il codice più significativo, se ve ne serve altro ditemelo.
    main
    codice:
    int main(int argc, char** argv){
      ContoCorrente conto(200, 0.3, "Mario Rossi");
      cout << "Quanto vuoi prelevare?" << endl;
      double N;
      cin >> N;
      conto.prelevaSoldi(N);
      conto.show();
       return 0;
    }
    ContoCorrente:relevaSoldi (overload di una funzione della classe base)
    codice:
    void ContoCorrente::prelevaSoldi(double _importo )
    {
     if ( (_importo + costo_op ) <= ContoBancario::saldo   ){
       ContoBancario::prelevaSoldi( _importo  );
       ContoBancario::prelevaSoldi (costo_op);
     }
     else
     cerr << "Non puoi prelevare più di quanto hai!" << endl;
      
    }
    Funzione della classe base
    codice:
    void ContoBancario::prelevaSoldi(double importo)
    {
      
     if(importo == 0) 
          cout << "Perché prelevare 0 euro?" << endl;   
     
       else if (importo <= saldo){
         cout << importo << (importo == 1 ? " euro è stato prelevato.\n" :  " euro sono stati prelevati.\n");
         saldo = saldo - importo;    
      }
       else
          cerr << "Non puoi prelevare più di quanto hai!" << endl;
       
      
    }
    Esempio 1 :
    codice:
    Il conto a nome Mario Rossi contenente 200 euro è stato creato con successo.
    Dati attuali:
            Intestatario: Mario Rossi
            Saldo: 200
            Costo per operazione: 0.3
    Quanto vuoi prelevare?
    100
    100 euro sono stati prelevati.
    0.3 euro sono stati prelevati.
    Il conto a nome Mario Rossi contiene 99.7 euro.
    L'errore si presenta quando inserisco il saldo iniziale - costo per operazione. In questo caso, 199.70 (199.70 + 0.30 = 200)
    codice:
    Il conto a nome Mario Rossi contenente 200 euro è stato creato con successo.
    Dati attuali:
            Intestatario: Mario Rossi
            Saldo: 200
            Costo per operazione: 0.3
    Quanto vuoi prelevare?
    199.70
    199.7 euro sono stati prelevati.
    0.3 euro sono stati prelevati.
    Il conto a nome Mario Rossi contiene 1.13798e-14 euro.
    Il risultato è chiaramente ambiguo. Devo far notare che se codificassi:
    codice:
    void ContoCorrente::prelevaSoldi(double _importo )
    {
     if ( (_importo + costo_op ) <= ContoBancario::saldo   ){
       ContoBancario::prelevaSoldi( _importo + costo_op  );
    
    
     }
     else
     cerr << "Non puoi prelevare più di quanto hai!" << endl;
      
    }
    funziona senza problemi.
    Confido nel Vs. aiuto.
    Ringrazio ed ossequio,
    signoredeltempo.

  2. #2
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,480
    Per evitare equivoci e facilitare la correzione puoi postare tutto il codice in maniera che sia compilabile al primo colpo?
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  3. #3
    Quote Originariamente inviata da oregon Visualizza il messaggio
    Per evitare equivoci e facilitare la correzione puoi postare tutto il codice in maniera che sia compilabile al primo colpo?
    Eccoli:
    Conto Bancario.h
    codice:
    //classe base
    #ifndef Conto_Bancario_H
     #define Conto_Bancario_H
      #include <iostream>
      #include <string>
    class ContoBancario
    {
    protected:
           double saldo;
           std::string proprietarioConto;
    public:
          void show() const;
          ContoBancario(double , std::string);
          std::istream& operator>>(double ); //deposita sul conto
         void prelevaSoldi(double );
    };
    #endif // Conto_Bancario_H
    Conto Corrente.h
    codice:
    #ifndef CONTO_CORRENTE_H
     #define CONTO_CORRENTE_H
    #include "Conto Bancario.h"
    #include <iostream>
    #include <string>
    using std::string;
    using std::istream;
    using std::ostream;
    
    class ContoCorrente : public ContoBancario
    {
    public: 
    /*
     * Contocorrente 
     * @param 
     * 1 Saldo inziale = 0.0
     * 2 Costo per ogni operazione = 0.0
     * 3 Intestatario conto  = ""
     */
    ContoCorrente(double = 0.0, double = 0.0, string = ""); //avverti in caso di 0 per parametro due
    void prelevaSoldi(double);
    private:
    double costo_op;  
    };
    #endif
    Conto Bancario.cpp
    codice:
    #include "Conto Bancario.h"
    #include <string>
    #include <iostream>
    using namespace std;
    
    
    ContoBancario::ContoBancario(double _saldo, string proprietario)
    {
    
    
      saldo = (_saldo > 0 ? _saldo : 0);
      proprietarioConto = (proprietario.length() > 0 ? proprietario : "");
      if (saldo != 0 && proprietarioConto.length() >= 0)
      {
        std::cout << "Il conto a nome " << proprietarioConto << " contenente " << saldo << " euro è stato creato con successo." << endl;
      } 
    }
    
    
    void ContoBancario::prelevaSoldi(double importo)
    {
      
     if(importo == 0) 
          cout << "Perché prelevare 0 euro?" << endl;   
     
       else if (importo <= saldo){
         cout << importo << (importo == 1 ? " euro è stato prelevato.\n" :  " euro sono stati prelevati.\n");
         saldo = saldo - importo;    
      }
       
       else
          cerr << "Non puoi prelevare più di quanto hai!" << endl;
       
      
    }
    
    
    
    
    istream& ContoBancario::operator>>(double importo)
    {
      saldo = saldo + importo;
      cout << importo << (importo > 1 ?" euro sono stati aggiunti.\n" : " euro è stato aggiunto.\n"  );
      
    }
    
    
    void ContoBancario::show() const
    {
    
    
      cout << "Il conto a nome " << proprietarioConto 
           << " contiene " << saldo << " euro."<< endl;
      
    }
    Conto Corrente.cpp
    codice:
    #include <iostream>
    #include "Conto Bancario.h"
    #include "Conto Corrente.h"
    #include <cstdlib>
    
    
    using namespace std;
    
    ContoCorrente::ContoCorrente(double saldo , double costoOP , string owner ) :  ContoBancario(saldo, owner )
    {
      if (costoOP < 0){
        cout << "Il costo per operazione non può essere inferiore di 0." << endl;
        exit(-1);   
      }
      else
        costo_op = costoOP;
        
      cout << "Dati attuali:" << endl
           << "\tIntestatario: " << ContoBancario::proprietarioConto << endl
           << "\tSaldo: " << ContoBancario::saldo << endl
           << "\tCosto per operazione: " << costo_op << endl;
    }
    
    
    void ContoCorrente::prelevaSoldi(double _importo )
    {
     if ( (_importo + costo_op ) <= ContoBancario::saldo   ){
       ContoBancario::prelevaSoldi( _importo + costo_op );
     
     }
     else
     cerr << "Non puoi prelevare più di quanto hai!" << endl;
      
    }
    Ma che fine hanno fatto gli spoiler?

  4. #4
    Non puoi usare i double (o qualunque tipo di numero in virgola mobile a base binaria) per importi monetari, o in generale quando è fondamentale che i numeri decimali siano rappresentati senza approssimazioni.
    Infatti molti numeri che hanno un'espressione decimale finita (ad esempio, 0.1) in binario sono numeri periodici, che non sono rappresentabili esattamente all'interno di un double (che ha una precisione limitata). Per questo motivo, normalmente gli importi monetari si memorizzano con un tipo in virgola fissa (il concetto di fondo è memorizzare in un intero i centesimi invece degli euro) oppure con dei tipi in virgola mobile con base decimale.
    Amaro C++, il gusto pieno dell'undefined behavior.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.