Algorithmus für die nte-Wurzel gesucht
-
@stefan2008:
Kann mich nur anschließen.
Ein paar Kritikpunkte, die du dir wirklich zu Herzen nehmen solltest:1. Wie schon gesagt, braucht deine Art der Zahlendarstellung unnötig viel Speicher und ist unnötig langsam. Computer rechnen nunmal bitweise und nicht mit Zeichen. Auf einem 64-Bit-Prozessor könntest du mit einem einzigen Befehl gleich 64 Stellen addieren (im Dualsystem, also ~20 Stellen im Dezimalsystem). So wie du es machst, kannst du nur eine einzige Stelle auf einmal addieren/subtrahieren. Mit der std::list kommt nochmal ein gewaltiger Speicher-Overhead dazu, um die doppelt verkettete Liste zu verwalten. Wenn überhaupt ein Container, dann einen std::vector benutzen! Am besten aber ein Array.
2. Fehler sollen nicht verschwiegen werden. Eine gute Bibliothek sollte m.M.n. Fehler auf jeden Fall mitteilen, sonst bleiben sie unentdeckt, und der Programmierer sucht an der falschen Stelle.
3. Du benutzt an vielen Stellen kein const-Schlüsselwort. Google mal nach "const correctness".
4. Parameter werden bei dir immer als Kopie übergeben - d.h. zum Beispiel bei einer Addition müssen beide Zahlen zuerst kopiert werden (inklusive der darin enthaltenen std::list). Das ist unnötig langsam. Übergabe per konstanter Referenz benutzt man da eigentlich.
5. Die Namensgebung: "Digit" heißt "Ziffer". Du willst damit aber eine Zahl darstellen, also ist der Name irreführend.
6. Deine Überladung des "!"-Operators ist irreführend, da man damit normalerweise die boolsche Negation in Verbindung bringt. Zudem steht dieser Operator vor der Zahl, während das Ausrufungszeichen bei der Fakultät hinter der Zahl steht.
7. Was sollen die Operatoren << und >> mit Kommazahlen tun? Mir fällt da nichts Sinnvolles ein. In der Beschreibung steht was von "bitweisem Verschieben". Wie soll das gehen, bzw. was soll da rauskommen?
-
Ich möchte try.. catch sovie exception vermeiden. Mein Datentyp soll nicht "versuchen" etwas zu rechen, sondern "soll es" rechnen. Wenn er ein Fehler bemerkt, filtert er diesen Fehler aus und gibt eine kleine Meldung aus (
Screenshots auf http://www.srbib.de/medien.html). Das mit den Nachkommastellen habe ich mir schon überlegt. Wenn man sich den Quelltext anschaut, sieht man, das ganz oben eine Konstante steht, die für die Nachkommastellenbegrenzung zuständig ist. Die kann man beliebig verändern. Ich habe es eigebaut, damit die Divison mit Fließkommazahlen überhaupt erst funktioniert. Hätte ich es weggelassen, so würde der Komma bei der Division nicht an der richtige Stelle stehn.
Das mit der Einführung einer neuen Zahl war eine Schnapsidee. Ich dachte, wenn sich Leute schon mit Wurzel ziehen von Negativen Zahlen Gedanken gemacht haben (sprich komplexe Zahlen), könnten sich andere Gedanken mit der Division durch null machen.PS: Die Fehler werden markiert und sind sichtbar, auch wenn die Bibliothek diese automatisch filtert (
Screenshot http://www.srbib.de/screenshots/screenshot4.png)
-
@stefan2008:
Warum gehst du nicht auf meine 7 Punkte ein?
-
Mir ist nochwas aufgefallen:
8. Deine Operatoren ++ und -- erhöhen/verringern nicht(!), wie man erwarten müsste, um 1, sondern sie beziehen sich nur die letzte Nachkommastelle.
-
@Kritiker2000
Ich gebe zu, bei den meisten Dingen hast Du recht. Meine Bibliothek hat schon Verbesserungsbedarf. Aber auf der anderen Seite, gibt es Eigenschaftswerte zurück, das man von Standarddatentypen nicht erwaten kann. Zum Beispiel, kann man abfragen ob die Zahl gerade, ungerade oder Nachkommastellen enthält.
-
@Kritiker2000
Mit den ++ und -- Operatoren wollte ich die Zahl mit den kleinstmöglichen Zahl, je nach dem wo sich die kleinste Zahl befindet, addieren / subtrahieren.
Ich dachte es wäre besser so.Ich habe viel Arbeit und Ideen reingesteckt. Soll ich jetzt alles vernichten?
-
Was würdest Du als Namen vorschlagen?
-
Man soll die Operatorüberladung nicht misbrauchen und du tust das. Benutze die Operatoren so wie man sie gewohnt ist und nicht wie du es gerade für sinnvoll hälst. Das verwirrt andere nur.
Ist doch deine Klasse, wenn du sie nicht so ändern willst, wie die Mehrheit es sich wünscht, dann ist das doch deine Entscheidung.
Ich persönlich sehe den Sinn hinter deinen Ideen nicht. Wenn ich solch eine Klasse schreiben würde, dann hätte ich
a) keine Beschränkung der Vor-/Nachkommastellen (höchstens Schrittweiten die eine bessere Performance mit sich bringen)
b) möglichst gute PerformanceWas hat ein Programmierer denn davon, dass der PC extrem ineffizient rechnet, so wie wir? Ich benutze den PC doch genau dafür, da er es besser kann wie ich.
Deshalb würde ich eine Basis wie 256 wählen und nicht die 10er Basis.
Als zugrunde liegende Datenstruktur würde ich mir überlegen ob ich Vorteile von einem std::bitset oder std::vector< bool > hätte, ansonsten ganz normal ein std::vector< uint8_t >, wobei uint8_t ein geeignetes typedef wäre auf einen 8Bit unsigned Typen.
Wenn es für die Performance keinen Unterschied macht würde ich statt 8Bit pro Byte allgemein 2^(Bits pro Byte) als Basis wählen.Nur so ein paar Ideen. Mir ginge es eher um die programmiertechnische Herausforderung bei solch einer Klasse, da ich diese eh nie selber nutzen würde und auf was fertiges (besseres) zurückgreifen würde.
-
Ja, es stimmt. Wenn ich mit mehr als ein Operator rechne beansprucht es sehr viel Zeit. Ich bin nicht gerade ein guter Programmierer, da ich mir alles selbst beigebracht und nicht studiert habe.
Eine Frage habe ich aber noch. Ein Bool ist ja ein Bit groß. Stimmt es, dass der CPU den Bool-Wert trotzdem Byteweise durchführt? Ich frage nur, weil es mich interessiert, ob ein Bool genauso schnell wie ein Long Integer gelesen wird.
-
Ein "bool" ist in C++ ein Byte groß. Brauch also genauso lange wie
ein "char", "short", "int" oder "long" in C++ um verarbeitet zu werden.
-
Chuck schrieb:
Ein "bool" ist in C++ ein Byte groß. Brauch also genauso lange wie
ein "char", "short", "int" oder "long" in C++ um verarbeitet zu werden.Die Größe eines Bools ist nicht so strikt festgelegt um dem Compiler Spielraum zur Optimierung zu geben, so kann er zum Beispiel mehrere Bools in ein einzelnes Byte packen, oder die Wortbreite der Architektur verwenden um die beste performance zu ermöglichen.
-
Wäre aber genauso schnell, wie ein einzelnes "int" zuverarbeiten *Ausrede such*.
-
Ich sehe eine riesen Baustelle vor mir; aber die Arbeit wird sich lohnen. Auf die Idee mit der Basis 256 wäre ich nicht gekommen. Also, wenn ich keine Kopie einer Zahl haben möchte, sollte ich ein Zeiger verwenden? Ich merke ich habe einige Gesichtspunkte ignoriert und muss einiges nachholen.
Ich könnte vielleicht ANSI-C++ mit Assembler kombinieren, um die Leistung zu optimieren. Ich würde gerne auf Zeichenketten verzichten, aber ich kenne keinen anderen Standarddatentyp, mit dem ich eine große Anzahl an Ziffern an meine Klasse übergeben kann. Ich frage mich, wie die meisten es Schafen, ein Datentyp zu erstellen, bei dem man die Ausführungszeichen weglassen kann. Zum Beispiel bei Datentypen, die länger als double sind.
-
stefan2008 schrieb:
Ich könnte vielleicht ANSI-C++ mit Assembler kombinieren, um die Leistung zu optimieren.
Schreib zuerst alles sauber und ordentlich in einer Hochsprache wie C++. Wenn Du später herausfindest, so besonders viel Rechenzeit verbraucht wird, kannst Du Dir immer noch überlegen, diesen kleinen Teil zu optimiern.
stefan2008 schrieb:
Also, wenn ich keine Kopie einer Zahl haben möchte, sollte ich ein Zeiger verwenden
Konstante Referenzen bieten sich eher an.
stefan2008 schrieb:
Ich würde gerne auf Zeichenketten verzichten, aber ich kenne keinen anderen Standarddatentyp, mit dem ich eine große Anzahl an Ziffern an meine Klasse übergeben kann.
Arrays....
stefan2008 schrieb:
Ich frage mich, wie die meisten es Schafen, ein Datentyp zu erstellen, bei dem man die Ausführungszeichen weglassen kann. Zum Beispiel bei Datentypen, die länger als double sind.
Such mal nach "big number class" oder sowas. Da findest du bestimmt shcon fertige Implementierungen, bei denen du Ideen sammeln kannst.
-
Die benutzen zur Eingabe alle Anführungszeichen bzw. unterstützen dies.