Einen eigenen Datentyp erstellen? (größer als double?)

  • Allgemein

Es gibt 25 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Einen eigenen Datentyp erstellen? (größer als double?)

    Hallo!

    da ich in letzter Zeit ein wenig an meinem Fraktal/Mandelbrot-Generator arbeite, habe ich mich gefragt ob es nicht eine Möglichkeit gibt einen größeren Datentyp als double zu verwenden, da ich doch gefühlt "recht schnell" an das maximum gekommen bin und ich doch gerne tiefer in das Fraktal schauen würde! Wenn es so eine Möglichkeit gibt (da bin ich mir schon relativ sicher), dann wäre ich sehr dankbar über Tipps und Hilfestellungen!

    Valerian
    MathUtils besitzt eine Rational-Klasse, mit der sich Zahlen beliebig genau darstellen lassen (nicht unendlich genau, also Pi usw. lassen sich logischerweise nicht 100% genau darstellen). Du solltest es aber nicht übertreiben, bei riesigen Zahlen werden Berechnungen sehr lange dauern (und mit sehr lange meine ich sehr sehr sehr lange).
    BigInteger ist doch nur Ganzzahl oder? Bei der Mandelbrotmenge rechnet man aber in Fließkommazahlen oder?
    Ich dachte Decimal ist kleiner als Double?
    Wegen dem Zahlenbereich, wie sollte ich den Umrechnen? Gibt es da bestimmte Vorgehensweisen?
    Danke schonmal der schnellen Hilfe!
    Valerian
    Das mit Double (4,94065645841246544E-324 bis 1,79769313486231570E+308) und Decimal (+/-1E-28) muss mir noch wer erklären (16/8Bit sagen ja schon die Lösung, aber die E-Zahlen verwirren mich)... Trotzdem danke!
    Ich werde mich mal an dem x Mod c Ansatz versuchen und ein wenig tüfteln

    Valerian
    Soweit hatte ich es schon verstanden, jedoch steht bei Double E-324 und bei Decimal E-28 und das ist ist mein "Verwirrungsfaktor". 10^-324 ist doch viel "kleiner" (damit auch genauer) als 10^-28, oder sind die Zahlen falsch/anders zu interpretieren?
    Double kann viel größere und viel kleinere zahlen darstellen, das ist richtig. Allerdings nur durch Exponenten, das heißt, ist eine Zahl enorm groß, dann werden kleinere Anteile einfach abgeschnitten, 10000000000000000001 würde z.B. auf 10000000000000000000 gerundet. Außerdem ist der Exponent bei Double zur Basis 2, was zur Folge hat, dass Zahlen, die im Dezimalsystem exakt dargestellt werden können, möglicherweise gerundet werden. Double verwendet man dann, wenn man schnell Berechnungen durchführen will, bei denen 100%ige Genauigkeit keine Rolle spielt und für die möglicherweise große Zahlenräume benötigt werden.
    Decimal hingegen verfolgt ein anderes Ziel. Die darstellbaren Zahlen sind vom Betrag her nicht so groß, da der Exponent nicht so groß werden kann. Dafür ist der Exponent zur Basis 10 und die Mantisse ist größer, sodass Berechnungen in für Menschen üblichen Größenordnungen ohne Rundungsfehler getätigt werden können. Dafür ist der Decimal wesentlich langsamer als ein Double
    Statt einem Byte-Array ist ein Integer-Array zu empfehlen. Allerdings wird auch das nicht so einfach, wie du dir das vorstellst und es wird einfach verdammt langsam. Addition, Subtraktion und Multiplikation lassen sich relativ effizient implementieren, eine Division habe ich nicht effizient hinbekommen. Ich habe es dann irgendwann gelassen.
    Trotzdem sollte man sich die Eigenschaft von Fraktalen zunutze machen, wenn es diese schon gibt.

    Gruß
    ~blaze~
    Ich habe bemerkt, dass eigene Datentypen und genauere (decimal) enorme Verlangsamungen erzäugen, daher werden diese Methoden wohl ausfallen (Ich habe mit double ein 1920x1080 Pixel Bereich mit 1000 Iterationen gerechnet, das hat 32 Sekunden bei 3,1GHz single-Prozess gedauert. Decimal war nach 15 Minuten noch nicht fertig...)
    Falls ich nicht alle double Variablen durch decimal hätte ersetzen sollen, dann entschuldigt meinen Leichtsinn ;)
    Valerian

    Gelöschter Benutzer schrieb:

    "x Mod c"
    Modulo bedeutet im eigentlichen Sinne: Rest bei Ganzzahldivision. Logisch gesehen brauchst Du also keine Gleitkomma-Arithmetik, da Du im Bereich der Reellen Zahlen jede Division restlos ausführen kannst.
    Was sagt denn Deine Aufgabenstellung?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Also bis jetzt arbeite ich noch mit ganz vielen Nachkommastellen (ein Schritt bis zum nächsten zu errechnenden Punkt ist 0,006 und wird beim heran Zoomen immer wieder durch 1,1 geteilt), doch ich versuche nun das ganze ein wenig in den "größeren" Bereich zu schieben... falls es dort Tipps gibt wäre ich dankbar :)
    mein Algorythmus zum errechnen ist dieser hier: (welcher aber kaum zu ändern ist oder?)
    Spoiler anzeigen

    Quellcode

    1. double _viewX = 0;
    2. double _viewY = 0;
    3. double _scale = 0.006;
    4. int _iterations = 32;
    5. public Bitmap getImage(int p_width, int p_height)
    6. {
    7. Bitmap tmp = new Bitmap(p_width, p_height);
    8. double left = _viewX;
    9. double top = _viewY;
    10. for (int x = 0; x < tmp.Width; x++) // Pixel leftright
    11. {
    12. top = _viewY;
    13. for (int y = 0; y < tmp.Height; y++) // Pixel topdown
    14. {
    15. int color = getPixelColor(left, top);
    16. if (color == _iterations) // main area
    17. tmp.SetPixel(x, y, _matchColor);
    18. else // colored area
    19. {
    20. tmp.SetPixel(x, y, Color.White);
    21. }
    22. top += _scale;
    23. }
    24. left += _scale;
    25. }
    26. return tmp;
    27. }
    28. int getPixelColor(double p_x, double p_y)
    29. {
    30. double leftN = 0; // left n
    31. double topN = 0; // top n
    32. double leftN1 = 0; // left n+1
    33. double topN1 = 0; // top n+1
    34. int i;
    35. for (i = 0; i < _iterations; i++)
    36. {
    37. topN = 2 * leftN1 * topN1 + p_y;
    38. leftN = leftN1 * leftN1 - topN1 * topN1 + p_x;
    39. if (topN * topN + leftN * leftN > 4) // Pythagoras > 2 - break
    40. break;
    41. topN1 = topN;
    42. leftN1 = leftN;
    43. }
    44. return i;
    45. }

    Valerian

    Gelöschter Benutzer schrieb:

    welcher aber kaum zu ändern ist
    Probier mal, die höchste Auflösung auf Ganzzahl abzubilden.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Tut mir leid, aber ich stehe gerade auf dem Schlauch :/ wenn ich das ganze sozusagen umdrehe mit 1/x, dann ist ja die komplette Rechnung so wie ich sie hatte nicht mehr möglich, dennoch fast alles mit Ganzzahl rechenbar.
    Oder soll ich versuchen die höchste Auflösung, die ich erreichen will ein zu gespeichern und von dieser dann dividieren, dann brauche ich aber einen enorm großen gespeicherten Wert, denn sonst rutsche ich ja wieder in den Fließkommazahlen-bereich?
    Oder meintest du das anders?
    Danke trotzdem!