Taschenrechner

    • VB.NET

    Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von picoflop.

      Taschenrechner

      oder wasauchimmer man "scripten" will ;)

      ACHTUNG !!! Benötigt VS PRO (geht zumindest nicht mit Express!)

      VB.NET-Quellcode

      1. '
      2. ' Orignal in C#:
      3. ' http://www.gamedev.net/community/forums/topic.asp?topic_id=264462
      4. ' Abgewandelt in VB
      5. '
      6. Imports Microsoft.VisualBasic
      7. Imports System.CodeDom
      8. Imports System.CodeDom.Compiler
      9. Public Class NetScripter
      10. Public Sub Test()
      11. Dim d As Double = DoCalc("1 + 4 * (2^0.5)")
      12. Debug.Print(d)
      13. End Sub
      14. Public Function DoCalc(ByVal mathexp As String) As Double
      15. Dim scr As New System.Text.StringBuilder
      16. scr.AppendLine("Public Class DummyClass")
      17. scr.AppendLine("Public Shared Function DoCalc() As Double")
      18. scr.AppendLine("Return " & mathexp)
      19. scr.AppendLine("End Function")
      20. scr.AppendLine("End Class")
      21. Dim res As CompilerResults = ExecuteScript(scr.ToString)
      22. Return res.CompiledAssembly.GetType("DummyClass").GetMethod("DoCalc").Invoke(Nothing, Nothing)
      23. End Function
      24. Public Shared Function ExecuteScript(ByVal scripttext As String) As CompilerResults
      25. Dim codeProvider As CodeDomProvider = CodeDomProvider.CreateProvider("VisualBasic")
      26. Dim codeCompiler As ICodeCompiler = codeProvider.CreateCompiler
      27. Dim params As New CompilerParameters
      28. With params
      29. .GenerateExecutable = False
      30. .GenerateInMemory = True
      31. .IncludeDebugInformation = False
      32. .TreatWarningsAsErrors = False
      33. .ReferencedAssemblies.Add("system.dll")
      34. .ReferencedAssemblies.Add("System.Windows.Forms.dll")
      35. End With
      36. Dim results As CompilerResults = codeCompiler.CompileAssemblyFromSource(params, scripttext)
      37. If results.Errors.Count = 0 Then
      38. Else
      39. ' irgendeine Fehlerbehandlung
      40. Throw New Exception("mupf!")
      41. End If
      42. Return results
      43. End Function
      44. End Class


      Wie man sieht kann man eigentlich so ziemlich jeden Schweinkram damit machen. Einfach mal rumspielen ;)

      NACHTRAG:
      Bitte aufpassen, wenn man direkt Benutzereingaben übernimmt! Schließlich gehts hier letztlich um eval() und der User könnte ja zB auch Programmcode zum Löschen von Dateien etc eingeben ...

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

      @K:
      Frage: Was passiert bei dir, wenn der Code einen Fehler enthält?
      Frage: Wie lange brauchst du mit deinem System um das zu machen, was bei mir in "Test" steht (also denselben Term berechnen)? (Bei mir auf meinem NB: 0.22 sek)
      Ausgehend von DIESEM Thread:
      [Release] Quadsoft.ExpressionParser - Ein Parser für mathematische Ausdrücke

      Hab ich das ganze mal umgeschrieben, um zu zeigen, wie man mit CodeDom extrem performante Sachen machen kann. Dabei hab ich es noch nicht mal sonderlich optimiert!

      Die Klasse, die zum erzeugen des dynamischen Assemblies verwendet wird:
      Spoiler anzeigen

      VB.NET-Quellcode

      1. '
      2. ' Orignal in C#:
      3. ' http://www.gamedev.net/community/forums/topic.asp?topic_id=264462
      4. ' Abgewandelt in VB
      5. '
      6. Imports Microsoft.VisualBasic
      7. Imports System.CodeDom
      8. Imports System.CodeDom.Compiler
      9. Public Class NetScripter
      10. Public Function Test(ByVal s As String) As Byte()
      11. Return DoCalc(s, s, s)
      12. End Function
      13. Public Function DoCalc(ByVal rexp As String, ByVal gexp As String, ByVal bexp As String) As Byte()
      14. Dim scr As New System.Text.StringBuilder
      15. scr.AppendLine("Imports System.Math")
      16. scr.AppendLine("Public Class DummyClass")
      17. scr.AppendLine("Public Shared Function DoCalc() As byte()")
      18. scr.AppendLine("Dim result(256*256*3-1) As byte")
      19. scr.AppendLine("For y as integer = 0 to 255")
      20. scr.AppendLine("For x as integer = 0 to 255")
      21. scr.AppendLine("result(y*256*3 + x*3)= CInt(" & rexp & ") and &hff")
      22. scr.AppendLine("result(y*256*3 + x*3 + 1)= CInt(" & gexp & ") and &hff")
      23. scr.AppendLine("result(y*256*3 + x*3 + 2)= CInt(" & bexp & ") and &hff")
      24. scr.AppendLine("Next x")
      25. scr.AppendLine("Next y")
      26. scr.AppendLine("Return result")
      27. scr.AppendLine("End Function")
      28. scr.AppendLine("End Class")
      29. Dim res As CompilerResults = ExecuteScript(scr.ToString)
      30. Return res.CompiledAssembly.GetType("DummyClass").GetMethod("DoCalc").Invoke(Nothing, Nothing)
      31. End Function
      32. Public Shared Function ExecuteScript(ByVal scripttext As String) As CompilerResults
      33. Dim codeProvider As CodeDomProvider = CodeDomProvider.CreateProvider("VisualBasic")
      34. Dim codeCompiler As ICodeCompiler = codeProvider.CreateCompiler
      35. Dim params As New CompilerParameters
      36. With params
      37. .GenerateExecutable = False
      38. .GenerateInMemory = True
      39. .IncludeDebugInformation = False
      40. .TreatWarningsAsErrors = False
      41. .ReferencedAssemblies.Add("system.dll")
      42. .ReferencedAssemblies.Add("System.Windows.Forms.dll")
      43. End With
      44. Dim results As CompilerResults = codeCompiler.CompileAssemblyFromSource(params, scripttext)
      45. If results.Errors.Count = 0 Then
      46. Else
      47. ' irgendeine Fehlerbehandlung
      48. For Each s As String In results.Output
      49. Debug.Print(s)
      50. Next
      51. Throw New Exception("mupf!")
      52. End If
      53. Return results
      54. End Function
      55. End Class


      Aufruf zb so:
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Imports NCalc
      2. Public Class Form1
      3. Private bm As Bitmap
      4. Public Sub CreateBitmap()
      5. If bm Is Nothing Then
      6. bm = New Bitmap(256, 256, System.Drawing.Imaging.PixelFormat.Format24bppRgb)
      7. Dim bmdata As System.Drawing.Imaging.BitmapData = bm.LockBits(New Drawing.Rectangle(0, 0, bm.Width, bm.Height), Imaging.ImageLockMode.ReadWrite, Imaging.PixelFormat.Format24bppRgb)
      8. Dim ptr As IntPtr = bmdata.Scan0
      9. Dim bytes As Integer = Math.Abs(bmdata.Stride) * bm.Height
      10. Dim s As String = "Sin( y / 8 + Cos( x / 5 ) / 2 ) * 127 + 127"
      11. Dim x As New NetScripter()
      12. Dim rgbvalues() As Byte = x.Test(s)
      13. System.Runtime.InteropServices.Marshal.Copy(rgbvalues, 0, ptr, rgbvalues.Length)
      14. bm.UnlockBits(bmdata)
      15. PictureBox1.Width = bm.Width
      16. PictureBox1.Height = bm.Height
      17. PictureBox1.Image = bm
      18. PictureBox1.Refresh()
      19. End If
      20. End Sub
      21. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
      22. Dim stp As New Stopwatch
      23. stp.Start()
      24. CreateBitmap()
      25. stp.Stop()
      26. MessageBox.Show(stp.ElapsedMilliseconds.ToString)
      27. End Sub
      28. End Class

      Das ganze läuft also INKLUSIVE kompilieren UND "zeichnen" (Django zeichnet nicht, Django jongliert mit Bytes ;) ) bei MIR (Turion X2 mit 1.8 GHz) in rund 300 MILLIsekunden.

      CodeDom macht Spass ;)
      dürfte eigt. auch kein Problem sein, das Lock/Unlock innerhalb von CodeDom zu machen, damit man nur ein Bitmap übergeben muss ;)

      Bzw. Man könnte doch auch GDI+ verwenden um auf das Bild zu zeichnen, gut ist möglicherweiße langsamer(aber man bekommt ja wiederum Performancevorteile durch den verwendeten Bresenham-Algorithmus)...über DrawCurve, könnte man dann auch mit weniger Werten(weniger Rechnen->mehr Performance) eine relativ schöne Kurve zeichnen, außerdem hat man die Möglichkeit Antialiasing zu verwenden ;)

      Bzw. mist fällt mir gerade auf: es wird ja gar keine einfache Gleichung übergeben, dann geht das so gut auch wieder nicht(ein paar X-Werte könnte man denke ich trotzallem überspringen^^)
      Ich wollte auch mal ne total überflüssige Signatur:
      ---Leer---

      jvbsl schrieb:

      dürfte eigt. auch kein Problem sein, das Lock/Unlock innerhalb von CodeDom zu machen, damit man nur ein Bitmap übergeben muss

      Klar.
      Aber da ich mit AppendLine den Schrott übergebe, habe ich lieber mehr in der "richtigen" IDE geschrieben ;)

      Ich denke, was am meisten bringen dürfte:

      - Äußere Schleife (Y) mit Tasks.Parallel.For machen oder einfach in PLINQ kapseln (braucht also FW4). Dann macht er jede innere Schleife auf nem eigenen Kern und da Dual-Core ja schon fast Minimum ist, dürfte man da sicherlich nochmal so 30-70% rausholen. Konnt ich jetzt so nicht testen, weil mein Notebook nur 2008 drauf hat und der große momentan abgeklemmt ist. Theoretisch könnte man auch selber ein Multithreading drumherum schreiben ... aber wer will das schon ;)

      - Lookup Table für Cos und Sin anlegen. Könnte man den Expression String einfach mit Replace umbiegen (also Cos wird zu MyCos usw). Das ganze dann halt nur einmal berechnen und in der gewünschten genauigkeit.

      Ist halt nur die frage, ob das bei so kleinen Bitmaps überhaupt der Brüller ist. Das Kompilieren und das umzu frißt ja immer einen bestimmten Sockelbetrag an Rechenzeit
      Hmm. Ich find das immer mühselig und ineffizient, so zum rumspielen immer gleich ein neues Projekt anlegen zu müssen, und dann läufts meist nichtmal auf Anhieb - kannst du nicht vlt. deine Source komplet zippen und anhängen? - weil du hast es doch schon, und ich müsstes erst noch aufbauen.

      ErfinderDesRades schrieb:

      Hmm. Ich find das immer mühselig und ineffizient, so zum rumspielen immer gleich ein neues Projekt anlegen zu müssen, und dann läufts meist nichtmal auf Anhieb

      Und ich hasse es, jedesmal komplette Projekte runterladen zu müssen, wenn mich nur ein bestimmter Teilbereich interessiert ... ;)

      Nachtrach:
      Ich hab mal den kompilierten Code testweise so umgebaut, dass er nach dem Dim des Arrays dieses sofort return'ed. Es werden also KEINERLEI Berechnungen durchgeführt. Das Ergebnis ist ... nun ja ;)
      Mit Berechnungen: 310ms (Durchschnitt)
      Ohne Berechnungen: 250ms (Durchschnitt)

      dh man kann sich das optimieren vermutlich sparen, weil bei "kleinen" Bitmaps der Overhead durch kompilieren, invoken etc schon deutlich größer als die reine Rechenzeit ist.

      Schade eigentlich ;)
      Dateien

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