Zahlen im Computer


  • Administrator

    Guten Tag,

    Ich denke mal ich setze es hier hin. Es geht um C++ Werte, welche subtrahiert, addiert, dividiert und/oder multipliziert werden. Ich habe in einem Finanzprogramm, welches ich geproggt habe, plötzlich gemerkt, dass es Abweichungen weit hinter dem Komma gibt. Und zwar habe ich z.b. zwei Float Werte voneinander subtrahiert. Nämlich 1.0300000 minus 1.0000000. Der Computer gab als Resultat 0.0299704 aus. Die Abweichung ist minim genug, dass sie bei meinem Programm vernachlässigt werden kann, doch ich frage mich wieso diese Abweichung auftritt. Ich habe mich deshalb ein wenig mit Bitzahlen auseinander gesetzt und selber von Hand Subtraktionen durchgeführt. Und bei mir ist nie so ein Fehler passiert. Was mir dann aber klar wurde ist, dass ich nie Kommazahlen in meinen Zahlen hatte. Um auf den Punkt zu kommen, wieso kann der Computer das nicht genau rechnen? Bzw. werden Kommastellen nicht auch einfach per Bits angegeben, bzw. wie werden sie angegeben?

    Denn mir ist noch was in der MSDN aufgefallen. Da steht eine Erklärung zu Float-Werten und zu Double-Werten.
    float | 4 Bytes | 3.4E +/- 38 (7 digits)
    double | 8 Bytes | 1.7E +/- 308 (15 digits)

    8 Bytes sind ja 64 Bits. Und 2 hoch 64 gibt für mich 18'446'744'073'709'551'616. Das entspricht aber niemals einer Zahl von 1.7 * 10^308 * 2. Und dann erst noch mit 15 Nachkommastellen. Schon beim Float Wert kann ich es mir gar nicht vorstellen. Nun die Frage, wie wird das gemacht? Kann man 0 und 1 noch besser verwerten, als ich mir das so vorstelle?
    Vielen Dank für die Hilfe.

    Grüssli



  • floats sind fließkommazahlen, die werden intern anders dargestellt. nämlich durch eine mantisse und einen exponenenten. wie groß diese mantisse ist, gibt an, wieviele stellen genauigkeit diese zahl unterstüzt. es wird keine genauigkeit nach diesen stellen garantiert. float unterstützt 7 stellen genauigkeit.

    das ist beispielsweise die zahl 1.23456, aber auch 0.000000000000000123456.

    wie fließkommazahlen genau funktionieren, kannst du z.b. bei wikipedia nachgucken



  • IEEE 754



  • Hi.

    Wenn es um Geldbeträge geht, solltest Du besser nicht mit float oder double oder so rechnen. Bastel Dir da lieber einen eigenen Datentyp, der auf ints oder longs oder so basiert. Solche Ungenauigkeiten sind mit Fließkommazahlen nicht zu vermeiden, weil einige Fließkommazahlen als binäre Zahl unendlich viele Nachkommastellen haben. Eine Zahl 0,25 ist zwar sehr angenehm binär darzustellen, ein 0,1 hingegen hat binär unendlich viele Nachkommastellen.


  • Administrator

    Hmmm ok, so langsam weiss ich was floats und doubles wirklich sind (nämlich eine blöde Falle für Neulinge *g*) ...
    Hmmm, das ist allerdings blöd. Und ein eigenen Zahlentyp zu erstellen, erscheint mir noch schwierig zu sein. Vor allem wie man das am besten anstellt, um mit diesem dann auch rechnen zu können. Bzw. ihn dann auch in den allg. Funktionen der MFC verwenden zu können. Z.b. bei CString::Format anwenden zu können. Da müsste man ja alles in das Zahlentypobjekt reinpacken. Und wie macht man das dann. Ein Integer für die Stellen vor dem Komma und ein Integer bzw. ein positiver Integer für die Stellen nach dem Komma? Und wie verrechnet man dann die Integer, bei multiplikation und co. usw. usf. Alles lösbar, aber erscheint mir am Ende ja fast nochmals ein kleines Projekt zu sein. Das Projekt, "Der Eigene Zahlentyp" ^^

    Jedenfalls danke für die Hilfe. Ich werde sicherlich jetzt vorsichtiger mit Float- und Doublewerten umgehen. Für mein Programm ist es aber wirklich nicht tragisch. Da ich am Ende auf eine Stelle nach dem Komma runden muss. Und da die Abweichungen so klein sind, macht es am Ende kaum was aus. Und auch wenn es mal ein Zehntel daneben wäre, es wäre nicht tragisch. Bisher haben aber meine Werte immer mit denen übereingestimmt, welche per TR ausgerechnet wurden. Das Programm wurde ja schliesslich überprüft, nicht das da plötzlich irgendwo 1000.- fehlen 😉

    Nochmals vielen Dank.
    Grüssli


  • Mod

    Dravere schrieb:

    Und ein eigenen Zahlentyp zu erstellen, erscheint mir noch schwierig zu sein.

    So aufwändig ist das gar nicht. Das Stichwort dazu lautet Festkommaarithmetik. Im Prinzip nimmst du eine ganze Zahl und definierst dir die hintersten zwei Dezimalziffern als Nachkommastellen. Die Zahl int(123) wäre also der Festkommawert "1,23". Addition/Subtraktion sind dann klar, einfach die Integer-Wert addieren bzw. subtrahieren. Multiplikation/Division von zwei Festkommawerten benötigen allerdings einen Korrekturfaktor.
    Am Beispiel bei der Multiplikation:
    1,5*1,5 entspricht den Integern 150*150 = 22500, also dem Festkommawert "225,00". Das richtige Ergebnis wäre aber "2,25", der Korrekturfaktor für die Multiplikation ist also 1/100.

    CString::Format will man eigentlich eh nicht nutzen, da es doch std::stringstreams gibt. Dann reicht es nämlich, den operator<<(ostream&) für deine Klasse zu überladen, damit du deine Festkommawerte als String ausgeben kannst. Falls du diese Überladung nicht kennst oder willst, geht natürlich auch erstmal eine to_string()-Funktion.


Anmelden zum Antworten