2016-05-02 12 views
2

Mit der folgenden einfachen C++leicht unterschiedliche Antworten beim Wechsel Assoziativität

#include <iostream> 
using namespace std; 
int main() 
{ 
    int euro, cents_v1, cents_v2, do_again; 
    double price; 

    do_again = 1; 

    while(do_again != 0){ 

     cout<<"Insert price in Euro with cents"<<endl; 
     cin>>price; 

     euro = price; 
     cents_v1 = price*100 - euro*100; 
     cents_v2 = (price - euro) * 100; 

     cout<<"Total: "<<euro<<" euro and "<<cents_v1<<" cents"<< endl; 
     cout<<"Total: "<<euro<<" euro and "<<cents_v2<<" cents"<< endl; 

     cout <<"\nDo it again? 1: yes, 0: no."<<endl; 
     cin>>do_again; 

    } 
    return 0; 

} 

Sie ausüben können zwei verschiedene Antworten erhalten, wenn der Eingang ist, zum Beispiel 31.13:

Insert price in Euro with cents 
31.13 
Total: 31 euro and 13 cents 
Total: 31 euro and 12 cents 

Do it again? 1: yes, 0: no. 

Wie damit umgehen Problem? Gibt es eine Regel bei der Programmierung, um dieses Problem in komplizierteren Situationen zu vermeiden oder zu kontrollieren?

+2

Die Standardantwort auf diese Frage [Was jeder Informatiker über Fließkomma wissen sollte] (https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) –

+0

FP-Ergebnisse in konvertieren Ganzzahlen können aufgrund der Kürzung stark leiden. Rundung vorschlagen. 'cents_v1 = rund (Preis * 100 - euro * 100);' – chux

Antwort

1

Aufgrund von Rundungsfragen sollten Sie nie float oder double verwenden, um Währungseinheiten darzustellen (sie sind nicht exakt und wenn es um Geld geht, wollen die Leute genau sein).

Versuchen Sie, die folgende Zeile Code hinzufügen:

std::cout << std:: setprecision(17) << price << "\n"; 

Mit Ihrer Eingabe das Ergebnis:

31.129999999999999 

Also entweder Sie brauchen eine Klasse zu erstellen, Ihr Geld zu repräsentieren (keine schlechte Idee). Oder verwenden Sie eine Ganzzahl (als Ganzzahlen sind immer genau). So speichern Sie den Geldbetrag als die Anzahl der Cent nicht die Anzahl der Euro. Dann nur beim Anzeigen in Euro und Cent umrechnen.

class DecimalCurrencyUnit 
{ 
    long cents; 
    public: 
     DecimalCurrencyUnit() 
      : cents(0) 
     {} 
     DecimalCurrencyUnit(long euros, long cent) 
      : cents(euros * 100 + cent) 
     {} 
     friend std::ostream& operator<<(std::ostream& s, DecimalCurrencyUnit const& out) 
     { 
      return s << '€' 
        << (out.cents/100) << "." 
        << std::setw(2) << std::setfill('0') << (out.cents % 100); 
     } 
     friend std::istream& operator>>(std::istream& s, DecimalCurrencyUnit& in) 
     { 
      long euros; 
      long cent; 
      char s; 
      char x; 
      if ((s >> s >> euros >> x >> cent) && s == '€' && x == '.' && cent < 100) 
      { 
       in.cents = euros * 100 + cent; 
      } 
      else 
      { 
       s.setsetate(std::ios::bad); 
      } 
      return s; 
     } 
     // Add standard operators here for *+/- etc. 
} 
+1

Vielleicht 'lang lang', um sicher zu sein, dass sogar die Staatsschulden meines Landes dargestellt werden können ... –

+0

@Bob__: Wenn du das in der Produktion machen willst Eine Bibliothek mit beliebiger Genauigkeit könnte eine bessere Idee sein. Wenn du nur "lang lang" herumkommst –

3

Gleitpunktaddition und -multiplikation sind kommutativ, aber nicht assoziativ oder distributiv. Daher können cents_v1 und cents_v2 tatsächlich unterschiedliche Werte darstellen, wie Sie festgestellt haben.

Eine allgemeine Technik zur Vermeidung dieser Typen von Gleitkomma-Fehlern ist die Verwendung einer arithmetischen Bibliothek mit beliebiger Genauigkeit. Es gibt quite a few of these, und ich kenne sie nicht genug, um sie einander zu empfehlen. Die Verwendung von Zahlen mit beliebiger Genauigkeit verursacht natürlich eine Leistungseinbuße, aber bis Sie wissen, dass Ihre Arithmetik ein Flaschenhals ist, ist es unklug, weiter zu optimieren.

Wenn Sie unbedingt Fließkomma-Arithmetik verwenden müssen, gibt es eine Vielzahl von Faustregeln, um die Genauigkeit bei langen Gleitkommaberechnungen zu verbessern. Sehen Sie sich einige numerische Methoden Texte für weitere Informationen. Es gibt auch eine gute Forschung zur Genauigkeit in der Fließkomma-Berechnung, die einige rather cool software erzeugt hat.