Festkommazahlen



  • Hi Ihr! .

    Ich baue gerade, als kleine Übung für mich selbst, einen textbasierten Taschenrechner, der mathematische Ausdrücke als Inputstring akzeptiert und diese vereinfacht.

    Ich bin allerdings auf ein Problem gestoßen: dieser Taschenrechner arbeitet intern mit doubles, die per se sehr ungenau sein können, abhängig vom Zahlenbereich.
    Ich hatte das anfangs als nicht so wild eingeschätzt, aber jetzt, wo ich einige Tests gemacht habe, bin ich der Meinung, dass doubles oder floats als Basisdatentyp für einen Taschenrechner ungeeignet sind.

    Ich habe dann gelesen, dass gerade wegen der Genauigkeit z.B. in Datenbanken Festkomma- statt Gleitkommazahlen verwendet werden, welche so funktionieren wie unsere menschliche Standardschreibweise für Kommazahlen.

    Meine Frage ist also:
    Kann man in C mit Festkommazahlen arbeiten? Gibt es da Bibliotheken?

    Würde mich freuen wenn jemand ein, zwei Hinweise für mich hat!

    Gruß, Joshuah^^



  • du kannst auch einfach integers (z.b. int64_t bzw. long long int) nehmen und die dinger intern mit 100000 oder einer beliebigen anderen zehnerpotenz multiplizieren. dann hast du doch deine festkommazahlen.



  • Stimmt, ich bin auch bescheuert..

    https://www.mikrocontroller.net/topic/87745

    Da hat jemand das gleiche Prinzip gezeigt, um Euro und Cent abzubilden (intern wird mit Cent gerechnet, das Komma wird dann bei der Ausgabe hinzugefügt)

    Aber danke!



  • Mit Festkommazahlen kannst du aber keine sehr großen bzw. kleinen Zahlen darstellen.

    Wenn du 1000000 als Faktor nimmst, ist alles unter 0,000001 ein Hauch von Nichts.



  • @DirkB gut dass dus erwähnst!
    Wenn ich 32 Bit für den ungebrochenen Anteil verwende und 32 Bit für den gebrochenen, bin ich für den Bereich <1>0 hochpräzise, komme aber im ungebrochenen nicht über/unter +-2mrd.

    Vielleicht als Struct, ich muss mir da was einfallen lassen.

    Edit. Oder ich sage ich habe 40 Bit für den ungebrochenen und 24 für den gebrochenen, entschärft die Lage etwas.



  • @Joshuah sagte in Festkommazahlen:

    bin ich für den Bereich <1>0 hochpräzise,

    Nicht wirklich.
    10 Nachkommastellen sind nicht die Welt.



  • Bevor du ein 64-Bit-Int auf Fixpunkt vergewaltigst, kommst du mit long double weiter.

    Wo stellst du überhaupt Ungenauigkeiten fest?

    Schon mal überlegt, wie 0,1 in Fixpunkt aussehen würde?



  • @DirkB

    Zu Punkt 1:
    Ich persönlich empfinde 10 Nachkommastellen als genug. Ich kann ja Pi nicht mal auf 10 Stellen hinter dem Komma aufsagen.

    Punkt 2:
    Ich habe Algorithmen geschrieben, die Strings in doubles umwandeln und umgekehrt, weil ich Lust darauf hatte. Da habe ich gemerkt, dass die Zahlen, die ich eingegeben habe, minimal verfälscht wurden, also so ab der dritten Nachkommastelle.

    Punkt 3:
    Ja. Man braucht binär sehr viele Nachkommastellen, ich weiß nicht genau wie viele.



  • @Joshuah sagte in Festkommazahlen:

    Da habe ich gemerkt, dass die Zahlen, die ich eingegeben habe, minimal verfälscht wurden, also so ab der dritten Nachkommastelle.

    Bei Fließkommazahlen ist eher die signifikante Stelle interressant. (Also die erste von 0 verschiedene Stelle.)

    double hat ca. 16 Stellen. bei einem großen Wertebereich.
    Wenn du Fixpunkt mit 64 Bit machst, kommst du auf ca 19 Stellen mit einem (sehr) eingeschränktem Bereich.

    Bei solchen Überprüfungen kann man viel falsch machen. u.A. auch bei der Ausgabe.

    Punkt 3:
    Ja. Man braucht binär sehr viele Nachkommastellen, ich weiß nicht genau wie viele.

    Wieviel Nachkommstellen brauchst du im Dezimalsystem für 1/3 ?



  • Achso, es gibt auch noch long double. Das sind 80-Bit Fließkommazahlen.



  • @DirkB sagte in Festkommazahlen:

    Achso, es gibt auch noch long double. Das sind 80-Bit Fließkommazahlen.

    Das stimmt nicht. Es ist Implementation Defined. Bei x86 hängt es davon ab, welche Compiler Einstellungen genutzt werden. Intel empfiehlt nur noch SSE/AVX zu nutzen, und da ist sizeof(double) == sizeof(long double), wie bei der großen Masse an Plattformen. Nur bei Nutzung der x87 FPU wird 80Bit genutzt. Bei einigen Compilern wird eine Softwareemulation der QuadPrecision (128Bit) genutzt.

    Ferner gibt es einige wenige Plattformen, die Quad Precision in Hardware implementiert haben z.B. PA-RISC.

    Nachtrag:
    Beim g++ sind die Compileroption -mlong-double-64, -mlong-double-80, -mlong-double-128. Das nachfolgende Programm ist zwar in C++ geschrieben, aber die Konstanten heißen unter C genauso und die Informationen sind die gleichen.

    #include <iostream>
    #include <iomanip>
    #include <cfloat>
    
    using namespace std;
    
    int main () {
        cout << "FLT_RADIX " << FLT_RADIX << "\n\n";
        cout << scientific;
        cout << "float       sizeof: " << setw(2) << sizeof(float)       << " digits: " << setw(3) <<  FLT_MANT_DIG << " min exponent: " << setw(6) <<  FLT_MIN_EXP << " max exponent: " << setw(5) <<  FLT_MAX_EXP << " epsilon: " <<  FLT_EPSILON << "\n";
        cout << "double      sizeof: " << setw(2) << sizeof(double)      << " digits: " << setw(3) <<  DBL_MANT_DIG << " min exponent: " << setw(6) <<  DBL_MIN_EXP << " max exponent: " << setw(5) <<  DBL_MAX_EXP << " epsilon: " <<  DBL_EPSILON << "\n";
        cout << "long double sizeof: " << setw(2) << sizeof(long double) << " digits: " << setw(3) << LDBL_MANT_DIG << " min exponent: " << setw(6) << LDBL_MIN_EXP << " max exponent: " << setw(5) << LDBL_MAX_EXP << " epsilon: ";
    
        double eps = LDBL_EPSILON;
    
        cout << eps << "\n";
    }
    
    


  • Oder vielleicht doch was bewährtes nehmen?



  • Da die Anwendung hier "Taschenrechner" ist, würde ich erstmal bei einem einfachen "double" bleiben. Was für Rechnungen machst du denn, dass dir "double" nicht mehr ausreicht?

    Sieh es mal so: es gibt nur wenige Naturkonstanten, die überhaupt eine so große Genauigkeit haben (sogar die Feinstrukturkonstante passt locker in double). Daher ist der Ruf nach mehr Stellen hinterm Komma nicht immer sinnvoll. Ok, bei gewissen Rechnungen (z.B. wenn du Zahlen verschiedener Größenordnungen addierst), ist Fließkomma problematisch und man braucht "unterwegs" tatsächlich mehr Genauigkeit oder muss die Rechnung geschickt umformen.

    Aber dass du ab der dritten Nachkommastelle eine Verfälschung hattest (meinst du wirklich dritte Nachkommastelle oder eher dritte signifikante Stelle?), ist schon komisch. Wenn wirklich dritte Nachkommastelle: war deine Zahl extrem groß oder hast du irgendwas kompliziertes gerechnet?



  • @wob

    Es ist bei jeder Zahl etwas unterschiedlich, teilweise sind sie auch unverfälscht. Dritte Nachkommastelle (1.xxX) ist eine grobe Schätzung, wenn ich alle über einen Kamm scheren wollte.

    Also wie gesagt, ich habe Funktionen geschrieben, die doubles in strings (char-Arrays mit Nullbyte am Ende) umwandeln und umgekehrt. Dabei wird, je nach Größe der Zahl, diese ständig umgewandelt.
    Das bedeutet, dass beim Einlesen und Anzeigen schon gerechnet wird.

    Meine "Lösung" ist also ziemlich behindert, das wusste ich zu dem Zeitpunkt allerdings nicht.
    Mein Ziel war es, bis auf die Funktionen scanf und printf einfach alles was ich brauche neu zu schreiben, und dementsprechend auch nur stdio.h zu inkludieren. Das bedeutet natürlich, dass ich keinen Datentyp für Strings (oder auch bools) hatte.

    Würde ich nie nochmal machen. Ich bin gerade am Handy, von daher kann ich gerade keinen Code schicken, aber ich schätze ihr wisst ungefähr worauf das hinausläuft.


Log in to reply