Farbgebung der Mandelbrotmenge

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von ~blaze~.

    Farbgebung der Mandelbrotmenge

    Hallo zusammen,

    Ich hab die letzten Tage ein relativ gutes Grundgerüst zum erstellen bzw. darstellen der Mandelbrotmenge aufgesetzt. Mittels Multithreading läuft dass selbst im höchsten Decimalstellen bereich innerhalb von Sekunden durch.

    Wie schon bei Double, habe ich auch hier ( wenn auch viel später ) die grenze der Genauigkeit erreicht.

    (Siehe die Bilder)

    Jetzt stellt sich mir die Frage : Gibt es einen Datentyp der eine höhere endliche Genauigkeit hat? Muss ja schon. Wenn ich mir andere Fraktalgeneratoren anschaue, dann können die schon um einiges weiter.
    Sollte dass funktionieren, kann ich feststellen ob die Genauigkeit am "Ende" ist? So dass ich erst ab diesem Punkt mit dem neuen Datentyp weiterrechne? Ich denke mal, dass es verständlich ist dass die Ladezeiten um einiges höher werden.

    LG
    Bilder
    • okay.jpg

      356,89 kB, 1.920×1.080, 165 mal angesehen
    • schlecht.jpg

      359,81 kB, 1.920×1.080, 127 mal angesehen
    Meist hilft in solchen Fällen, den Algorithmus anzupassen, eine Möglichkeit wäre, iterativ zu rechnen.

    Bei BigInteger hast du eine fast unbegrenzte an Stellen.
    Aber das geht ordentlich auf die Performance.
    Und ist auf Ganzzahlen begrenzt.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Mit BigInteger ist es wirklich möglich eine sehr hohe Anzahl an Stellen zu rechnen.

    also z.B.

    VB.NET-Quellcode

    1. exp = 9 'Anzahl Stellen
    2. a = 978.123456789
    3. b = 123.987645321
    4. biginteger = (a*10^exp) * (b*10^exp)
    5. c = cDbl(biginteger / (10^(2*exp)))


    etc.

    Freundliche Grüsse

    exc-jdbi
    @Bagplatt Kannst Du mir mal erläutern, an welcher Stelle im Algorithmus da eine solche Genauigkeit erforderlich ist?
    Ich hab auch ein solches Programm, da sind mir derartige Effekte völlig unbekannt.
    Ich nehme mal eher an, dass in Deinem Algorithmus ein Fehler steckt.
    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!
    @RodFromGermany Ja^^ ein Fehler habe ich bereits gefunden. Da alles in mehrere Threads läuft übergebe ich eine Struktur mit allen nötigen Daten. Dort war statt Decimal noch Double drinnen. Denke mal dass da schon von Decimal nach Double und wieder nach Decimal genug verloren ging. Aber selbst wenn : Welchen Datentyp verwendest du? Würde ich nicht früher oder später selbst mit Decimal an die Grenze gelangen?
    @Bagplatt Da muss ich zu Hause mal nachsehen, soweit ich mich entsinne, reichen Integer und Double.
    Wozu brauchst Du mehrere Threads?
    Parallel.For bzw. Parallel.ForEach sollte da völlig genügen.
    Ich glaube, Du hast Dich an die Parallelisierung gemacht, bevor der Algorithmus in Ordnung war.
    Vielleicht gehst Du zurück, bringst den Algo in Ordnung und parallelisierst ihn dann, so lässt sich der Fehler leichter beheben.
    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!
    Ich hab vorher schon einmal dass Programm ohne Threads gemacht. Da lief dass bis auf Ungenauigkeit ab einer bestimmten tiefe gut. Ich hatte verschiedene Test´s gemacht, und bei 5-6 verschiedene Threads die ein Teilbereich kalkulieren war die Geschwindigkeit am besten.

    Ja, ich glaube der Fehler war, dass meine Struktur die ich den Threads zur Verfügung stelle statt Decimal ein Double Typ war. Sprich die Bereiche die im main noch genaue waren, wurden in der Struktur ungenau, und da nützt dass auch nichts wenn ich es im Thread wieder
    zu Decimal wandel, wenn der Teilbereich selbst schon nicht mehr genau war^^

    #Edit
    Ja das war der Fehler, ist jetzt genauer. Auch die Rechenzeit steigt drastisch ^^

    @RodFromGermany Welche Funktion nimmst du zur Farbgebung? Ich hab im englischen Wiki eine Funktion gefunden die einzelnen Farben aus einer Palette abstufen soll, sprich einen glatten Übergang ermöglichen soll. Leider funktioniert dasss ganze überhaupt nicht : csharphelper.com/blog/2014/07/…othly-shaded-colors-in-c/

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Bagplatt“ ()

    Bagplatt schrieb:

    Welche Funktion nimmst du zur Farbgebung?
    Muss ich heute abend zu Hause mal nachsehen.
    ====
    Gugst Du hier: vb-helper.com/howto_net_fractal_mandelbrot.html
    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!

    RodFromGermany schrieb:

    Gugst Du hier: vb-helper.com/howto_net_fractal_mandelbrot.html



    Ja dass ist einfach eine Farbpalette. Nur entstehen da ja logischerweise verschiedene Stufen. Ich trage nachher mal den Code von der Funktion ein wo ich gerne verwenden würde nach.

    #Nachtrag

    VB.NET-Quellcode

    1. Class xyz
    2. Private rgb_Colors(50) As Color
    3. Public Sub New()
    4. For i As Integer = 0 To 50
    5. rgb_Colors(i) = Color.FromArgb(255, rnd.Next(0, 255), rnd.Next(0, 255), rnd.Next(255))
    6. Next
    7. End Sub
    8. Private Sub DrawMandel()
    9. 'For mandelx ect.
    10. 'For mandely ect.
    11. 'Hier wird die Eigentliche Iteration ausgeführt. Wenn die Daten vorhanden sind Farbe berechnen. Unten
    12. 'next
    13. 'next
    14. For i As Integer = 0 To 2 'Für Fehler Reduktion. Was auch immer noch für Fehler entstehen können
    15. maxIteration = maxIteration - 1
    16. x = xx - yy + xmin + (ix * xadd)
    17. y = xy + xy + ymin + (iy * yadd)
    18. xx = x * x
    19. yy = y * y
    20. xy = x * y
    21. curBetrag = xx + yy
    22. Next
    23. Dim mu As Double =( maxIteration + 1) - Math.Log(Math.Log(betrag_2)) / 4
    24. Dim smtColor As Color = GetColor(mu)
    25. bmp.setPixel(ix,iy,smtColor)
    26. End Sub
    27. Private Function GetColor(ByVal mu As Double) As Color 'Hier kracht es ständig
    28. Dim clr1 As Integer = CInt(mu)
    29. Dim t2 As Double = mu - clr1
    30. Dim t1 As Double = 1 + t2
    31. clr1 = clr1 Mod rgb_Colors.Count
    32. Dim clr2 As Integer = (clr1 + 1) Mod (rgb_Colors.Count)
    33. Dim r As Byte = CByte(rgb_Colors(clr1).R * t1 + rgb_Colors(clr2).R * t2)
    34. Dim g As Byte = CByte(rgb_Colors(clr1).G * t1 + rgb_Colors(clr2).G * t2)
    35. Dim b As Byte = CByte(rgb_Colors(clr1).B * t1 + rgb_Colors(clr2).B * t2)
    36. Return Color.FromArgb(255, r, g, b)
    37. End Function
    38. End Class


    Ich griege da ständig OutOfRange oder Division durch 0 Fehler.

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „Bagplatt“ ()

    ich bin jetzt nicht genau drin in der aktuellen Diskussion, aber vor laaaangem hab ich auch mal ein Mandelbrot gemacht, in C, und zwar mit Integer. Wenn man es durchdacht anstellt, braucht man keine Doubles, und die Performance war echt gut.
    Allerdings habich vergessen, wie ich es anstelltete.
    Vermutlich mit BitShifts und Integer-Division.
    Und wo es jetzt BigInteger gibt, denke ich, dass man die Auflösung damit echt beliebig skalieren kann.

    ErfinderDesRades schrieb:

    Vermutlich mit BitShifts und Integer-Division.

    Dass hab ich mir schon so ungefähr vorgestellt :

    Bagplatt schrieb:

    Geht dass eventuell direkt über ein Byt/e System?

    Aber die Ungenauigkeit war bedingt von einem Fehler.

    Quellcode

    1. Klasse speichert die 4 Werte als Decimal.
    2. Strukturen speichern die Werte als Double.
    3. Strukturen werden den Threads übergeben.
    4. Threads wandelt wieder in Decimal um.

    @ErfinderDesRades Seit ich diese Struktur geändert habe, bin ich noch nicht so weit gekommen das Maximum auszuloten. Kannst du dir mal den letzten Post von mir anschauen? Eigentlich sollen dort Farblich weiche Übergänge entstehen. Funktioniert nur nicht so ganz.

    Ich bin gerade an einem kleinem Beispielprojekt. Versuche mal die zusammenhänge der Iterationen mittels

    Quellcode

    1. Dim mu As Double =( maxIteration + 1) - Math.Log(Math.Log(betrag_2)) / 4
    herauszufinden.

    Um einen Farblich weichen Übergang zu realisieren, müsste ja die nächste Iterationsstufe der umliegenden Pixel bekannt sein. Ergo müsste die Funktion "mu" den Betrag der umliegenden Px errechnen. Dann könnte ich auch mittels lineare interpolation :

    VB.NET-Quellcode

    1. Private Function lerp(ByVal v0 As Double, ByVal v1 As Double, ByVal t As Double) As Double
    2. Return (1 - t) * v0 + t * v1
    3. End Function


    den Übergang gestalten.

    Naja, so oder so ähnlich.

    P.S.

    Warum wird mir die Box nicht angezeigt ? So wie RodFromGermany mit der Parallel.For
    Hi
    ist nicht der Vorteil bei Fraktalen, dass man sie aufgrund ihrer Eigenschaften beliebig skalieren kann? Die sollten sich ja nach irgendeinem bestimmten Wert wiederholen.

    Wenn du es effizienter gestalten möchtest, kannst du übrigens in einem späteren Optimierungsprozess auch eine eigene Structure implementieren, die den Prozentwert als Byte darstellt (wobei 0 eben 0%, 255 dann 100% entspricht). Außerdem würde ich auf die Color-Structure verzichten und eine eigene schreiben, die nur die ARGB-Farben enthält (oder AHCY).

    So wie ich es sehe, hast du außerdem t1 falsch berechnet. Außerdem solltest du bei Arrays auf die Length-Eigenschaft und nicht auf die Count-Extension zurückgreifen.

    Hättest du den Fraktal-Code reingestellt, hätte man da btw. evtl. auch nochmal drüberschauen können.

    Viele Grüße
    ~blaze~
    @~blaze~

    ~blaze~ schrieb:

    Hättest du den Fraktal-Code reingestellt, hätte man da btw. evtl. auch nochmal drüberschauen können.


    Stimmt. Da funktioniert nichts gerade. Hab dass eben total verschossen alles. Hab mir meine eigene Klasse Complex erstellt. Doch diese funktioniert nicht, so durfte ich alles nochmal machen. Eine Berechnung wo mir eben aufgefallen ist, werde ich im Code besser kennzeichnen. Meine Klasse Complex würde ich gerne verwenden, dann brauch ich nicht alles so zerstückeln. Doch da weis ich auch nicht ob der *Operator richtig ist.

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Option Explicit On
    3. Public Class Mandelbrot
    4. Private m_PictureSize As Size
    5. Private m_xmin As Decimal
    6. Private m_ymin As Decimal
    7. Private m_xmax As Decimal
    8. Private m_ymax As Decimal
    9. Private m_Threads As Integer = 4
    10. Private m_MaxBetrag As Decimal = 4
    11. Private m_MaxIteration As Integer = 400
    12. Private m_Coloring As ColorMod = ColorMod.Stufen
    13. Enum ColorMod
    14. Stufen
    15. LineaInterpo
    16. End Enum
    17. Public Sub New(ByVal Size As Size, ByVal xmin As Decimal, ByVal ymin As Decimal, ByVal xmax As Decimal, ByVal ymax As Decimal)
    18. m_PictureSize = Size
    19. m_xmin = xmin
    20. m_ymin = ymin
    21. m_xmax = xmax
    22. m_ymax = ymax
    23. End Sub
    24. Public Sub CreateThreads()
    25. 'Zuerst die Grundlegenden Informationen für alle Threads
    26. Dim xadd As Decimal = (Math.Abs(m_xmin) + m_xmax) / m_PictureSize.Width
    27. Dim yadd As Decimal = (Math.Abs(m_ymin) + m_ymax) / m_PictureSize.Height
    28. completeProcess = m_PictureSize.Width * m_PictureSize.Height
    29. 'Für die Threads muss nun die einzelnen Bereiche eingeteilt werden
    30. Dim t_width As Integer = CInt(m_PictureSize.Width / m_Threads)
    31. Dim t_rest As Integer = 0
    32. If t_width * m_Threads < m_PictureSize.Width Then
    33. 'Es entstand ein Rest, dieser wird dem letzten Thread angefügt
    34. t_rest = m_PictureSize.Width - (t_width * m_Threads)
    35. End If
    36. 'Nun wird eine Liste mit allen Bereichen erstellt
    37. For i As Integer = 0 To m_Threads - 1
    38. 'Die Bereiche auser ymax müssen berechnet werden
    39. Dim neuMinX As Decimal = CDec(m_xmin + ((i * t_width) * xadd))
    40. Dim neuMinY As Decimal = m_ymin
    41. Dim neuMaxX As Decimal = CDec(neuMinX + ((i * t_width) * xadd))
    42. Dim neuMaxY As Decimal = m_ymax
    43. Dim nrct As New Rectangle(New Point(i * t_width, 0), New Size(t_width, m_PictureSize.Height))
    44. ThreadsArgs.Add(New MandelRegion With {.Iteration = m_MaxIteration, .MaxBetrag = m_MaxBetrag, _
    45. .Rect = nrct, .xAdd = xadd, .xmax = neuMaxX, .xmin = neuMinX, _
    46. .yAdd = yadd, .ymax = neuMaxY, .ymin = neuMinY, .color = m_Coloring})
    47. Dim tpg As New Threading.ParameterizedThreadStart(AddressOf Progress)
    48. ThreadsPool.Add(New Threading.Thread(tpg))
    49. Next
    50. End Sub
    51. Private ThreadsPool As New List(Of Threading.Thread)
    52. Private ThreadsArgs As New List(Of MandelRegion)
    53. Private ThreadsFinished As Integer = 0
    54. Public Event Finished(ByVal bmp As Bitmap)
    55. Private FinishRegions As New List(Of Input)
    56. Delegate Sub dlgFinishThread(ByVal ins As Input)
    57. Private currentProcess As Integer
    58. Private completeProcess As Integer
    59. Private lastProcess As Integer
    60. Public Event currentProgress(ByVal e As Integer)
    61. Delegate Sub dlgCurrentProgress(ByVal e As Integer)
    62. Public Event FinishTime(ByVal start As TimeSpan, ByVal ends As TimeSpan, ByVal diff As TimeSpan)
    63. Private t1 As TimeSpan
    64. Private t2 As TimeSpan
    65. Private Sub _currentProgress(ByVal e As Integer)
    66. currentProcess += e
    67. Dim op As Integer = CInt(completeProcess \ 100)
    68. Dim ff As Integer = currentProcess \ op
    69. If Not lastProcess = ff Then
    70. lastProcess = ff
    71. RaiseEvent currentProgress(ff)
    72. End If
    73. End Sub
    74. Private Sub FinishThread(ByVal ins As Input)
    75. FinishRegions.Add(ins)
    76. ThreadsFinished += 1
    77. If ThreadsFinished = m_Threads Then
    78. 'Bild zeichnen
    79. Dim bmp As New Bitmap(m_PictureSize.Width, m_PictureSize.Height)
    80. Dim g As Graphics = Graphics.FromImage(bmp)
    81. For Each nss As Input In FinishRegions
    82. g.DrawImage(nss.bmp, nss.rct.X, nss.rct.Y, nss.rct.Width, nss.rct.Height)
    83. Next
    84. g.Dispose()
    85. RaiseEvent Finished(bmp)
    86. t2 = New TimeSpan(TimeOfDay.Day, TimeOfDay.Hour, TimeOfDay.Minute, TimeOfDay.Second, TimeOfDay.Millisecond)
    87. Dim t3 As TimeSpan = t2.Subtract(t1)
    88. RaiseEvent FinishTime(t1, t2, t3)
    89. End If
    90. End Sub
    91. Private Sub Progress(ByVal Param As Object)
    92. Dim finish As New dlgFinishThread(AddressOf FinishThread)
    93. Dim blob As MandelRegion = DirectCast(Param, MandelRegion)
    94. Dim current As New dlgCurrentProgress(AddressOf _currentProgress)
    95. Dim bmp As New Bitmap(blob.Rect.Width, blob.Rect.Height)
    96. Dim xadd As Decimal = blob.xAdd
    97. Dim yadd As Decimal = blob.yAdd
    98. Dim x As Decimal
    99. Dim y As Decimal
    100. Dim xx As Decimal
    101. Dim yy As Decimal
    102. Dim xy As Decimal
    103. Dim maxBetrag As Decimal = blob.MaxBetrag
    104. Dim curBetrag As Decimal = 0
    105. Dim maxIteration As Decimal = blob.Iteration
    106. For ix As Integer = 0 To blob.Rect.Width - 1
    107. For iy As Integer = 0 To blob.Rect.Height - 1
    108. x = blob.xmin + (ix * xadd) ' Wenn xmin > 0 ist müsste ich den Wert ja eigentlich abziehen.
    109. y = blob.ymin + (iy * yadd) ' Wenn ymin > 0 ist müsste ich den Wert ja eigentlich abziehen.
    110. 'Doch z.B. x = (ix*xadd) - Math.Abs(blob.xmin) funktioniert warum auch immer nicht.
    111. xx = x * x
    112. yy = y * y
    113. xy = x * y
    114. curBetrag = xx + yy
    115. Do While curBetrag < maxBetrag And maxIteration > 0
    116. maxIteration = maxIteration - 1
    117. x = xx - yy + blob.xmin + (ix * xadd) 'Hier dass gleiche wie oben. Sobald x > 0 ist dreht sich dass ganze bild auf die andere Seite.
    118. y = xy + xy + blob.ymin + (iy * yadd)
    119. xx = x * x
    120. yy = y * y
    121. xy = x * y
    122. curBetrag = xx + yy
    123. Loop
    124. If maxIteration = 0 Then
    125. bmp.SetPixel(ix, iy, Color.Black)
    126. Else
    127. Select Case blob.color
    128. Case ColorMod.Stufen
    129. Dim cr As Integer = CInt(255 - maxIteration - Math.Log(Math.Log(maxBetrag) / Math.Log(4)) / Math.Log(2))
    130. bmp.SetPixel(ix, iy, Color.FromArgb(cr Xor 255, cr, cr))
    131. Case ColorMod.LineaInterpo
    132. 'Hier sollte der Code von oben rein. Probiere dass bevor alles spinnt in einzelnen Projekten aus
    133. End Select
    134. End If
    135. curBetrag = 0
    136. maxIteration = 200
    137. Next
    138. current.Invoke(blob.Rect.Height - 1)
    139. Next
    140. finish.Invoke(New Input With {.rct = blob.Rect, .bmp = bmp})
    141. End Sub
    142. Public Function lerp(ByVal v0 As Double, ByVal v1 As Double, ByVal t As Double) As Double
    143. Return (1 - t) * v0 + t * v1
    144. End Function
    145. Public Sub StartRender()
    146. t1 = New TimeSpan(TimeOfDay.Day, TimeOfDay.Hour, TimeOfDay.Minute, TimeOfDay.Second, TimeOfDay.Millisecond)
    147. For i As Integer = 0 To ThreadsPool.Count - 1
    148. ThreadsPool(i).Start(ThreadsArgs(i))
    149. Next
    150. End Sub
    151. #Region "Property"
    152. Public Property SetMaxBetrag() As Decimal
    153. Get
    154. Return m_MaxBetrag
    155. End Get
    156. Set(ByVal value As Decimal)
    157. m_MaxBetrag = value
    158. End Set
    159. End Property
    160. Public Property SetMaxIteration() As Integer
    161. Get
    162. Return m_MaxIteration
    163. End Get
    164. Set(ByVal value As Integer)
    165. m_MaxIteration = value
    166. End Set
    167. End Property
    168. Public Property SetThreads() As Integer
    169. Get
    170. Return m_Threads
    171. End Get
    172. Set(ByVal value As Integer)
    173. m_Threads = value
    174. End Set
    175. End Property
    176. Public Property SetColoring() As ColorMod
    177. Get
    178. Return m_Coloring
    179. End Get
    180. Set(ByVal value As ColorMod)
    181. m_Coloring = value
    182. End Set
    183. End Property
    184. Public ReadOnly Property GetXMIN() As Decimal
    185. Get
    186. Return m_xmin
    187. End Get
    188. End Property
    189. Public ReadOnly Property GetYMIN() As Decimal
    190. Get
    191. Return m_ymin
    192. End Get
    193. End Property
    194. Public ReadOnly Property GetXMAX() As Decimal
    195. Get
    196. Return m_xmax
    197. End Get
    198. End Property
    199. Public ReadOnly Property GetYMAX() As Decimal
    200. Get
    201. Return m_ymax
    202. End Get
    203. End Property
    204. #End Region
    205. End Class
    206. Public Structure MandelRegion
    207. Public Iteration As Integer
    208. Public MaxBetrag As Decimal
    209. Public xmin As Decimal
    210. Public ymin As Decimal
    211. Public xmax As Decimal
    212. Public ymax As Decimal
    213. Public xAdd As Decimal
    214. Public yAdd As Decimal
    215. Public Rect As Rectangle
    216. Public color As Mandelbrot.ColorMod
    217. End Structure
    218. Public Structure Input
    219. Public bmp As Bitmap
    220. Public rct As Rectangle
    221. End Structure


    Hier mal der Code von der Klasse Complex die ich gerne verwenden würde :

    Spoiler anzeigen

    VB.NET-Quellcode

    1. ​Option Explicit On
    2. Option Strict On
    3. Public Class Complex
    4. Private m_Re As Decimal
    5. Private m_Img As Decimal
    6. Public ReadOnly Property GetReal() As Decimal
    7. Get
    8. Return m_Re
    9. End Get
    10. End Property
    11. Public ReadOnly Property GetImaginär() As Decimal
    12. Get
    13. Return m_Img
    14. End Get
    15. End Property
    16. Public Sub New(ByVal Real As Decimal, ByVal Imaginär As Decimal)
    17. m_Re = Real
    18. m_Img = Imaginär
    19. End Sub
    20. Public Shared Operator +(ByVal p1 As Complex, ByVal p2 As Complex) As Complex
    21. Return New Complex(p1.m_Re + p2.m_Re, p1.m_Img + p2.m_Img)
    22. End Operator
    23. Public Shared Operator -(ByVal p1 As Complex, ByVal p2 As Complex) As Complex
    24. Return New Complex(p1.m_Re - p2.m_Re, p1.m_Img - p2.m_Img)
    25. End Operator
    26. Public Shared Operator *(ByVal p1 As Complex, ByVal p2 As Complex) As Complex
    27. Return New Complex((p1.m_Re * p2.m_Re) - (p1.m_Img * p2.m_Img), (p1.m_Re * p2.m_Img) + (p2.m_Re * p1.m_Img))
    28. End Operator
    29. Public Shared Operator /(ByVal p1 As Complex, ByVal p2 As Complex) As Complex
    30. Return New Complex(CDec(((p1.m_Re * p2.m_Re) + (p1.m_Img * p2.m_Img)) / _
    31. ((p2.m_Re ^ 2) + (p2.m_Img ^ 2))), _
    32. CDec(((p2.m_Re * p1.m_Img) - (p2.m_Img * p1.m_Re)) / _
    33. ((p2.m_Re ^ 2) + (p2.m_Img ^ 2))))
    34. End Operator
    35. Public ReadOnly Property Magnitude() As Decimal
    36. Get
    37. Return CDec(Math.Sqrt((m_Re * m_Re) + (m_Img * m_Img)))
    38. End Get
    39. End Property
    40. Public Overrides Function ToString() As String
    41. Return "Re:" & m_Re & "|Im:" & m_Img
    42. End Function
    43. End Class


    Könnt ihr ja auch mal drüber schauen ob die Berechnungen so stimmen.
    Complex solltest du als Structure implementieren, das ist weitaus effizienter (übrigens bringt System.Numerics eine Complex-Struktur mit, die du verwenden hättest können, die aber nicht auf Decimal arbeitet).

    x ^ 2 ist ineffizient, verwende lieber x * x (selbiges auch für x^3 und x^4 = (x * x) * (x * x), wahrscheinlich sind auch x^5, usw. bis zu einem gewissen Wert noch effizienter zu berechnen, so rein von der Logik her). An sich arbeitet sie aber glaube ich richtig.

    Ich würde an deiner Stelle übrigens auch auf Decimal verzichten und zu Double oder Integer bzw. einer eigenen Struktur greifen, die das elegant verwaltet. Außerdem wäre bei der Verwendung des Threads mit einem Parameter des Thread-Handlers die Empfehlung, einen Lambda-Ausdruck zu verwenden, der die Parameter direkt übergibt. Das ist typisiert und hat vernachlässigbare Nachteile.
    Dein Event widerspricht übrigens außerdem den typischen Konventionen (EventHandler[(Of T)] bzw. Signatur (Object sender, T e) mit T As EventArgs). Warum du _currentProgress über den Delegaten aufrufst, ist mir auch nicht ganz klar, aber ich schätze, dass du dir dabei was gedacht hast.
    Der Fluss wäre auch noch etwas verbesserungswürdig. Ich würde bspw. - wenn du die CreateThreads-Methode schon öffentlich hast (was ich nicht machen würde, ich würde die Zahl der Threads im Konstruktor festsetzen) - die SetThreads-Eigenschaft löschen und die Zahl der Threads direkt der CreateThreads-Methode übergeben.
    An sich wäre da allerdings einiges zu verbessern. Überleg' dir beim Design immer, wie du möglichst alle Bedienfehler ausschließen kannst. Durch Parameter, Strukturen, eigens eingeführte Datentypen, Generika, Interfaces, usw. lässt sich da wirklich viel machen. Überlege dir diesbezüglich auch, ob der Code auch zweimal aufgerufen werden kann, ohne dass es zu Fehlern kommt (z.B. durch die allen Threads zugängliche Liste).
    Btw.: Es ist unnötig, in Zeile 82 nach der Integer-Division zu Integer zu konvertieren. Das Ergebnis ist bereits Integer.
    Vergiss außerdem nicht, öffentliche Eigenschaften auf Fehlbesetzungen zu überprüfen.

    Ich weiß, dass die Codestilbemerkungen nicht wirklich themenbezogene Lösungen bieten, aber an sich hilft es dir, Struktur und Ordnung in deinem Code zu schaffen und logische Fehler auszuräumen.

    Bzgl. der Anmerkung in den Zeilen 127ff.: Versuch' es mal mit einer abgewandelten Modulo-Operation. Deine Zahl n setzt sich ja quasi so zusammen: n = k * m + r, wobei du r herausfinden möchtest (wenn ich es richtig verstanden habe). Dann musst du quasi n - k * m rechnen und k erhältst du durch Floor(n / m). Die normale Modulo-Operation berechnet für negative Zahlen ein mir nicht ganz logisches erscheinendes Ergebnis. Ich glaube aber, dass man irgendwie sowas machen konnte: ((n mod k) + k) mod k, um ein sinnvolles Ergebnis für negative Zahlen zu errechnen. Was davon effizienter ist, weiß ich allerdings nicht.
    Ganz klar ist mir aber nicht, was gemacht werden soll, insofern kann mein Vorschlag auch Quatsch sein.

    Ich glaube außerdem, dass die fehlende Threadsicherheit bei deinem Code ein massives Problem sein dürfte. Das ist aber ein großes Thema. Eventuell kannst du mit Spin waiting über Interlocked effizient den Listenzugriff, usw. sperren. Noch besser wäre es, wenn das überflüssig würde. Da kenne ich mich aber mit der Berechnung der Mandelbrotmenge nicht genug aus - hat mich auch noch nie wirklich interessiert.

    Viele Grüße
    ~blaze~

    ~blaze~ schrieb:

    x ^ 2 ist ineffizient, verwende lieber x * x (selbiges auch für x^3 und x^4 = (x * x) * (x * x), wahrscheinlich sind auch x^5, usw. bis zu einem gewissen Wert noch effizienter zu berechnen, so rein von der Logik her). An sich arbeitet sie aber glaube ich richtig.
    Wusste ich, aber habs vergessen zu schreiben.

    ~blaze~ schrieb:

    auf Decimal verzichten und zu Double
    Ich habe vorher mit Decimal gearbeitet. Aber dabei kam immer diese ungenauigkeit auf. Bei Decimal jetzt nicht mehr. Den Grund weis ich nicht.

    ~blaze~ schrieb:

    einen Lambda-Ausdruck zu verwenden, der die Parameter direkt übergibt. Das ist typisiert und hat vernachlässigbare Nachteile.
    Dass 1x1 ? ^^

    ~blaze~ schrieb:

    Dein Event widerspricht übrigens außerdem den typischen Konventionen (EventHandler[(Of T)] bzw. Signatur (Object sender, T e) mit T As EventArgs)
    Ja, dass ist mir bewusst. Eigentlich habe ich dass alles nur mal implementiert damit ich ein Ergebnis sehe, bzw. ob die Rechnung an sich stimmt. Ausarbeiten und putzen tue ich immer, wenn ich ein Projekt neu starte und die Basis übernehme.

    ~blaze~ schrieb:

    _currentProgress über den Delegaten aufrufst
    Gehört dass nicht mit zur Threadsicherheit? Progress() läuft ja als Thread, und ein Event raisen erscheint mir dann nicht mehr als Threadsicher.

    ~blaze~ schrieb:

    ch würde bspw. - wenn du die CreateThreads-Methode schon öffentlich hast
    Klar, da komme ich wieder zu meine (wenn auch schlechtem) Vorgehen, wenn ich die einzelne subs von Main aufrufe, sehe ich direkt den Fehler, bzw. welcher Sub ihn auslöst. Und ich weis ja zmd. ein wenig was ich da geschrieben habe^^

    ~blaze~ schrieb:

    Überlege dir diesbezüglich auch, ob der Code auch zweimal aufgerufen werden kann
    Nein. Beim "zoom" wird eine neue Klasse erstellt. Sprich die letzten xy werden temp gespeichert.

    ~blaze~ schrieb:

    Ich glaube außerdem, dass die fehlende Threadsicherheit bei deinem Code ein massives Problem sein dürfte
    Genau dass hab ich eigentlich versucht nicht zu machen. Deswegen übergebe ich ja dass BLOB Object. Und dass Bild wird über einen Delegaten zur Sub in die List geleitet. Bisher hat es da noch nicht gekracht. Oder kann es wenn 2-3 Threads zur gleichen Zeit fertig sind, und dann zu 3 auf die List(of ) zugreifen krachen? Und ein SyncLock hilft da bst. nichts...

    ~blaze~ schrieb:

    Bzgl. der Anmerkung in den Zeilen 127ff.: Versuch' es mal mit einer abgewandelten Modulo-Operation. Deine Zahl n setzt sich ja quasi so zusammen: n = k * m + r, wobei du r herausfinden möchtest (wenn ich es richtig verstanden habe). Dann musst du quasi n - k * m rechnen und k erhältst du durch Floor(n / m). Die normale Modulo-Operation berechnet für negative Zahlen ein mir nicht ganz logisches erscheinendes Ergebnis. Ich glaube aber, dass man irgendwie sowas machen konnte: ((n mod k) + k) mod k, um ein sinnvolles Ergebnis für negative Zahlen zu errechnen. Was davon effizienter ist, weiß ich allerdings nicht.


    Eigentlich ist dass ja ganz simpel (zmd. im meinem Kopf :D ) Normalerweiße sollte dass mit Math.Abs(xmin) - real funktionieren
    Wenn xmin < 0 wird es durch Math.Abs > 0 und kann abgezogen werden
    Wenn xmin > 0 wird es durch Math.Abs nicht weiter beeinflusst(?) und kann auch abgezogen werden.

    Eigentlich. Ein paar Teile hab ich so weit verstanden und werde ich mal verbessern, danke an dieser Stelle schonmal @~blaze~
    Wie sieht es mit den logischen Operatoren der Klasse Komplex aus?

    LG
    Es ist sehr häufig besser, den Grund für Ungenauigkeiten zu eliminieren, wenn es möglich ist, als auf einen größeren Datentypen zu wechseln. Außerdem ist Decimal anders zu handhaben, als Double.

    Sowohl Current, als auch Finish werden synchron zum Aufrufer-Thread aufgerufen und sind daher nicht synchronisiert. List(Of T).Add ist nicht threadsicher, daher musst du einen Synchronisationsmechanismus verwenden.
    Falls da ein Missverständnis vorliegt: Delegaten führen Code nicht in einem anderen Thread aus; sie verweisen lediglich auf eine Methode. Diese wird bei Invoke direkt auf dem Thread ausgeführt, der sie aufgerufen hat.
    Events sind übrigens nichts anderes, als Delegaten (Multicast-Delegaten), um die noch ein Konstrukt aus Methoden geworfen wurde und das syntaktisch besser zugänglich ist.

    Wenn du mir vernünftig erklärst, was genau die Rechnungen in den Zeilen 127ff. machen sollen, kann ich dir ggf. helfen.

    Bagplatt schrieb:

    Nein. Beim "zoom" wird eine neue Klasse erstellt. Sprich die letzten xy werden temp gespeichert.

    Was bei Instanzen hässlich ist.

    Viele Grüße
    ~blaze~
    @Bagplatt Double ist völlig ausreichend. Ich hab meinen Algo von hier: Mandelbrot wird falsch gezeichnet
    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!

    ~blaze~ schrieb:

    Wenn du mir vernünftig erklärst, was genau die Rechnungen in den Zeilen 127ff


    Ist eigentlich gar nicht so schwer.
    Wenn xmin jetzt -1.5 ist, stellt dies den linken Punkt (x:0) auf dem Bild dar. xmax ist jetzt 1.0 und stellt die Breite auf dem Bild dar. Sprich der Abstand von xmin zu xmax ist gleich der Bildbreite. Ich habe nun einen Punkt auf dem Bild ausgewählt, und will diesen auf diese Skala umrechnen.

    Ich will jzt Px. 45 umrechnen
    Pro Pixel entspricht dass dann Math.Abs(xmin)+Math.Abs(xmax) / Bildbreite
    Math.Abs weil xmax auch in den - Bereich wandern kann.
    Der Pixel entspricht dann auf der Skala Math.Abs(xmin) - (45*ProPx)

    So sollte dass doch eigentlich funktionieren? X/

    ~blaze~ schrieb:

    Was bei Instanzen hässlich ist.
    Verstehe ich, bisher bin ich aber nicht dazu gekommen, alle Daten zu leeren und für eine neue Berechnung vorzubereiten, da ich schon beim erstellen an sich auf Probleme gestoßen bin, von daher muss bis die Basis funktioniert, die "Mehrfachverwendung" der Instanz warten.
    Du kannst mir aber mal ein Tipp geben wie ein Synchronisationsmechanismus ausschauen könnte :)

    RodFromGermany schrieb:

    @Bagplatt Double ist völlig ausreichend. Ich hab meinen Algo von hier: Mandelbrot wird falsch gezeichnet
    Danke werde ich mir anschauen :thumbsup:

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Bagplatt“ ()

    Dir ist bewusst, dass es ungefähr unendlich viele Möglichkeiten gibt, etwas auf eine Skala abzubilden (zumindest rein mathematisch betrachtet)? Sogar noch ein paar mehr!

    Wenn du einfach nur linear abbilden möchtest, machst du halt (x - xmin) / (xmax - xmin) und hast den Wert auf [0, 1] abgebildet. Aber aus deiner Beschreibung werde ich beim besten Willen nicht schlau.

    Das ist halt die Frage. Ich habe eigentlich keine Lust, mich in das Verfahren einzulesen. Schau' dir am besten RodFromGermany's Beispiel an.
    Außerdem: Versuch' dich selbst an der Optimierung deines Algorithmus auf Parallelisierung. Parallel.For ist dein gegenüber der von dir gewählten Threading-Strategie vermutlich eh dein bester Freund. Denke immer daran, möglichst selten möglichst kurz zu sperren. Sperren ist teuer und ist in parallelen Prozessen ausgesprochen oft ein Flaschenhals.

    Viele Grüße
    ~blaze~