Iteration über VBA dauert sehr sehr lange...alternativen?

  • Excel

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

    Iteration über VBA dauert sehr sehr lange...alternativen?

    Hallo Leute!

    Ich muss mit Excel den Druckverlust in Rohrleitungen ausrechnen. Jetzt ist eine der dafür benötigten Formeln nur über Iteration zu lösen.

    --> 1/sqrt(lambda)=-2*log(Rauhigkeit/Innendurchmesser/3.71+2.51/(Reynoldszahl*sqrt(lambda)))

    Ich habe mir da selber weitergeholfen mit ´nem relativ einfachem Code, da ich Anfänger bin und denke, dass das Newton Verfahren sowieso an dieser Stelle nicht wirklich weiterhilft. Mein Problem ist jetzt, dass, wenn ich die Berechnung durchführe, das ganze für fünf Zeilen Berechnung ca. eine halbe Minute braucht. Manchmal mehr, manchmal weniger...

    So weit so gut, mein bisheriger Code sieht ersteinmal so aus:

    Visual Basic-Quellcode

    1. Public Function Druckverlust(Rauhigkeit, R_i, Reynoldszahl)
    2. Dim y, x, a, z, i, c, j As Double
    3. z = 0.0001
    4. If Rauhigkeit = 0 Then
    5. a = 100000
    6. c = a
    7. For i = 1 To 500000
    8. x = Round(1 / Sqr(z), 6)
    9. y = Round(2 * Log(Reynoldszahl * Sqr(z) / 2.51) / Log(10), 6)
    10. If x <> y Then
    11. If x < y Then
    12. z = z - 0.0000001
    13. ElseIf x > y Then
    14. z = z + 0.0000001
    15. Else
    16. i = 500000
    17. End If
    18. End If
    19. Next i
    20. Else
    21. a = 100000
    22. c = a
    23. For i = 1 To 500000
    24. x = Round(1 / Sqr(z), 6)
    25. y = Round(-2 * Log((Rauhigkeit / R_i) / 3.71 + 2.51 / (Reynoldszahl * Sqr(z))) / Log(10), 6)
    26. If x < y Then
    27. z = z - 0.0000001
    28. ElseIf x > y Then
    29. z = z + 0.0000001
    30. Else
    31. i = 500000
    32. End If
    33. Next i
    34. End If
    35. Druckverlust = z
    36. End Function




    Funktionieren tut er soweit. Ich hoffe nur, dass irgendwer irgendeine Idee hat, das ganze Procedere zu beschleunigen! Dafür schonmal vielen Dank im Voraus.

    Gruß, rudi
    Das Problem dürfte sein das Du jede Schleife bis zu 500.000 mal durchläufst. Das ergibt zusammen rd. 1 Mio Schleifendurchläufe.

    Du müsstest das auf einen intelligenten Durchlauf umstellen. Einfach in der Mitte bei 250.000 anfangen und gucken ob Du nach oben oder nach unten weiter gehen musst. Musst Du nach unten weiter gehen wäre der nächste Step 125.000 und dort auch wieder gucken ob nach oben oder nach unten weiter usw. und so fort. Dadurch würdest Du die Anzahl der zu durchlaufenden Berechnungen massiv runterbrechen und am Ende bleiben dann höchstens noch ein paar hundert Berechnungen übrig wo früher im Extremfall bis zu 500.000 Berechnungen statt gefunden haben.

    Gruß

    Rainer
    Danke für die schnelle Antwort,aber ich glaube, ich verstehe deinen Ansatz noch nicht ganz. Ich brauche ja immerhin eine Genauigkeit von mindestens fünf Nachkommastellen. So wie ich das verstehe, möchtest du einfach die Schrittzahl immer halbieren, allerdings bringt mir das doch auf dauer für die Genauigkeit des Ergebnisses nichts oder?

    Gruß
    Ich würde das teilweise von der Zielwertsuche machen lassen.. Mal angenommen, du hast in Zelle A1 dein (erstmal falsches) Ergebnis stehen, da dort direkt die Formel (aus deinen drei Argumenten der Funktion) steht und in der Zelle A2 dein Druckverlust alias z. Dann kannst du in Zelle A3 eine weitere Formel so designen, dass diese bei Beachtung deiner Genauigkeit z. B. 0 wird. Die VBA-Routine bestünde dann nur noch aus folgender Angabe:

    Visual Basic-Quellcode

    1. Range("A3").GoalSeek Goal:=0, ChangingCell:=Range("A2")


    Dann iteriert Excel für dich so lange, bis es ein z gefunden hat, dass mindestens deine Genauigkeit erreicht.

    rentier schrieb:

    Danke für die schnelle Antwort,aber ich glaube, ich verstehe deinen Ansatz noch nicht ganz. Ich brauche ja immerhin eine Genauigkeit von mindestens fünf Nachkommastellen. So wie ich das verstehe, möchtest du einfach die Schrittzahl immer halbieren, allerdings bringt mir das doch auf dauer für die Genauigkeit des Ergebnisses nichts oder?


    Natürlich bringt Dir das was, dass ist eigentlich auch Funktionsweise der Iteration. ;)

    Iteration ist ja erstmal ein Näherungsverfahren.

    Beginnst Du bei Dir z.B. nicht bei 1 sondern bei 250.000 musst Du ermitteln ob Du mit dem dann erhaltenen Ergebnis zu hoch oder zu niedrig liegst. Liegst Du zu hoch, ist der nächste Schritt das gleiche mit dem Wert 125.000 durch zu führen. Liegst du zu niedrig wird eben das gleiche mit dem Wert 375.000 durchgeführt.

    Und durch den andauernden Abgleich ob zu hoch oder niedrig und dadurch die regelmäßige Halbierung der verbleibenden Restwerte kommst Du wesentlich schneller auf den exakten Wert.

    Das einzige was Du brauchst ist eine Gegenrechnung die Dir ausgibt das der Wert zu hoch oder zu niedrig ist.

    Einfaches Beispiel:

    Formel wäre:

    x + y = z

    Maximaler Wert für z wäre 100

    Füllen wir mal Beispielszahlen ein: 10 + 30 = ?

    Du kannst jetzt das Ergebnis für diese Rechnung per Iteration ermitteln, in dem Du eine Gegenrechnung aufstellst:

    z - y = a

    Anfangen tut man in der Mitte des maximalen Wertes

    50 - 30 = 20

    20 ist größer als x mit 10, also eine Stufe niedriger

    25 - 30 = - 5

    nun bist Du zu niedrig. Also eine Stufe hoch.

    (Nachkommstellen lasse ich mal aussen vor und rechne nur mit ganzen Zahlen, reicht ja als Beispiel)

    37 - 30 = 7

    immer noch zu niedrig. Also eine Stufe hoch.

    44 - 30 = 14

    jetzt biste wieder zu hoch. Also eine Stufe runter.

    40 - 30 = 10

    Punktlandung ... das gesuchte Ergebnis ist 40.

    So habe ich mit 5 Rechnungen alle möglichen Ergebnisse bis 100 überprüft und durch die Iteration das richtige Ergebnis ermittelt.

    Spart im Vergleich zu Deiner Methode bei 1 anzufangen und immer um 1 zu erhöhen gesamt 35 Berechnungen da Du ja 40 Rechnungen hättest machen müssen um auf das richtige Ergebnis zu gelangen.

    Wenn Du mit Nachkommastellen arbeitest, kannst du das bis zur 1000sten Nachkommastelle machen wenn du es so willst.

    Jetzt besser ausgedrückt was ich meine?

    Gruß

    Rainer
    Das mit der Zielsuchfunktion habe ich schon probiert. War mein erster Ansatz, da es natürlich einfacher aussah als mit null Wissen was mit VBA zu programmieren. Allerdings habe ich gerade mit der Zielwertfunktion nicht annähernd die Genauigkeiten bekommen, die ich benötige.

    Der vorschlag mit dem halbieren der Schritte klingt einleuchtend und ist es auch. So langsam zweifel ich allerdings an meinen mathematischen Fähigkeiten :P
    Ich will doch diese Gleichung durch Iteration lösen, da sie einfach nicht zu lambda umstellbar ist. Also muss ich einen Schätzwert vorschlagen, der bei mir die 0,0001 in Zeile 3 darstellt und als z deklariert ist. Nun muss ich beide Seiten der gleichung auf den gleichen Wert bringen, wobei nur das z variabel ist. Also muss ich immer wieder beide Seiten vergleichen, um im folgenden Schritt entweder das z zu erhöhen oder zu vermindern.
    Die 500000 beziehen sich ja einzig und allein auf die maximalen Schleifendurchläufe. Aber da kann ich doch nicht bei 250000 anfangen? Bzw. bringt mir das nichts. Steh ich auf dem Schlauch oder versteh ich dich einfach nicht? :)



    Ich will hier aber auch keine mathematische Diskussion starten, da solche Sachen hier bestimmt nicht hingehören. Also Vielen Dank für die Vorschläge! Ich werde mir mal weiter den Kopf zerbrechen und eure Vorschläge dabei beherzigen :)

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

    rentier schrieb:


    Die 500000 beziehen sich ja einzig und allein auf die maximalen Schleifendurchläufe. Aber da kann ich doch nicht bei 250000 anfangen? Bzw. bringt mir das nichts. Steh ich auf dem Schlauch oder versteh ich dich einfach nicht? :)


    Bei Durchlauf 1 hast Du einen anderen Rechenwert als bei Durchlauf 500.000 richtig? Du erhöhst ja bei jedem Durchlauf den Rechenwert (habe mir Deine Formel nicht angesehen, da das Problem unabhängig von der Formel ist ;)).

    Was würde passieren, wenn Du einmal die Rechnung mit den Werte aus Durchlauf 1 machst und dann danach die Rechnung mit den Werten aus Durchlauf 500.000? Richtig, Du hast die Range in der sich das Ergebnis bewegt.

    Hast Du die Range innerhalb derer sich das Ergebnis bewegt, dann hast du auch gleich den Bereich innerhalb dessen Du die Schrittweiten bestimmen kannst. Logisch, oder? ;) Du musst halt nur sicher sein das die Min-Max-Range das auch wirklich ist und der Wert nicht letztendlich doch außerhalb dieser Range liegt.


    Ich will doch diese Gleichung durch Iteration lösen ...


    Das ist klassisches Vorgehen bei Iteration, per Rechnung dem gesuchten Wert annähern und nach jeder Rechnung feststellen ob zu hoch oder zu niedrig um die nächste Rechnung entsprechend nach oben oder nach unten zu korrigieren. ;)

    Hier nur in Deinem Fall kombiniert mit der klassischen Datenbank-Suchmethodik für indexierte Felder, also nicht beim ersten Rechenschritt anfangen und solange nach oben arbeiten bis Du zu hoch bist, sondern gleich in der Mitte der ermittelten Min-/Max-Range anfangen.

    Gruß

    Rainer

    raist10 schrieb:

    habe mir Deine Formel nicht angesehen, da das Problem unabhängig von der Formel ist

    Es ist hier nicht unabhängig, weil hier jeweils der vorherige Wert mit dem delta von 0,00001 verändert wird. Zwar hast du schon den Nagel auf den Kopf getroffen, was die Iteration betrifft, allerdings geht es nicht mit diesem Datentyp und der gewünschten Genauigkeit. Die Genauigkeit wird nur vorgegaukelt, im Einzelfall läuft die Routine die komplette halbe Million mal durch die Schleife, weil der Datentyp Double (vermute ich) in einigen Ergebnisfällen nur noch zwischen + und - 0,000001 hin und herspringt, da x und y selten identisch sind. Daher die unterschiedliche Laufzeit.
    Was mir hier beim ersten Überblicken auffällt sind folgende Punkte.

    Niemals Berechungen von Konstanten innerhalb einer Schleife durchführen.
    Log(10) ist und bleibt Log(10), das muss man nicht 500000 mal machen.

    Weiterhin, aber das habe ich jetzt nicht auf die Ausführungsgeschwindigkeit hin
    getestet: Round würde ich mal ersetzen. Das würde ich einfach bei der
    If x<>y Then Abfrage anders prüfen.


    Du kannst z.B auch deinen z Wert dynamisch anpassen, statt immer nur die gleiche
    Konstante zu addieren.

    Dann kannst du auch den Max-Wert von 500000 weg lassen, weil deine
    Abbruchbedingung dann das Delta zwischen x und y sein sollte.

    Und, kannst du mir mal ein paar Parameterwerte und Ergebnisse geben,
    ich bekomme immer nur 0.0501 als Ergebnis.
    Dein z passt nämlich nicht zu den 500000 Durchläufen.
    Also beim berechnen selber setze ich ungefähr solche Werte ein: Rauhigkeit= 0,0015mm R_i=35mm und Reynoldszahl=10^5...10^6
    Das z habe ich mit dem Startwert 0,0001 besetzt, da die Reibungszahl, welche hier fälschlicherweise als "Druckverlust" ausgegeben werden soll, meist bei sehr kleinen Werten liegt. Sie kann aber auch Werte größer 1 annehmen.

    Das mit dem log(10) wollte ich eigentlich auch vermeiden, allerdings weiß ich nicht, wie der 10er logarithmus anders zu schreiben ist als log(x)/log(10) in vba. Klingt aber logisch was du sagst mit dem Berechnen von Konstanten in der Schleife.

    Wie kann ich denn dem Programm sagen, dass er aufhören soll, sobald 5 oder 6 Nachkommastellen der zu vergleichenden Werte übereinstimmen? Dann springt er ja frühzeitig aus der Schleife und würde die Anzahl ziemlich verringern richtig?


    An Rainer noch: Danke für deine Bemühung aber ich glaube dein vorschlag funktioniert bei mir wirklich nicht. Zumindest nicht wenn ich mein Rechenprinzip weiter behalte. Sonst wäre es nett, wenn du mal einen Code posten würdest, da ich sonst einfach nicht dahinter komme wie du dir das mit meiner Formel und Rechnung vorstellst. Das Prinzip ist klar, aber ich verzweifle an der durchführung in VBA.
    Schön, wenn man ein paar Beispielzahlen plus gewünschtem Ergebnis hätte ... ;)

    In VB.Net (VBA würde analog gehen) sähe das zb so aus:

    Visual Basic-Quellcode

    1. Public Function Druckverlust(ByVal Rauhigkeit, ByVal R_i, ByVal Reynoldszahl) As Double
    2. Dim Mittelwert As Double = Double.MaxValue / 2
    3. Dim UntereSchranke As Double = 0
    4. Dim ObereSchranke As Double = Double.MaxValue
    5. Dim y, x As Double
    6. Dim Genauigkeit As Double = 0.00001
    7. Dim SanityCheck As Integer = 1
    8. Do
    9. x = Round(1 / Sqrt(Mittelwert), 6)
    10. y = Round(2 * Log(Reynoldszahl * Sqrt(Mittelwert) / 2.51) / Log(10), 6)
    11. If Abs(x - y) < Genauigkeit Then
    12. Return Mittelwert
    13. End If
    14. SanityCheck += 1
    15. If SanityCheck > 10000 Then
    16. Throw New Exception("Error in reality.sys! Restart universe.exe?")
    17. End If
    18. If x < y Then
    19. ' damit x größer wird, muss z kleiner werden
    20. ObereSchranke = Mittelwert
    21. Else
    22. ' damit x kleiner wird, muss z größer werden
    23. UntereSchranke = Mittelwert
    24. End If
    25. Mittelwert = (ObereSchranke + UntereSchranke) / 2
    26. Loop
    27. End Function


    Beschleunigen kann man das ganze natürlich noch durch besseres Wählen einer oberen und unteren Grenze ! Dazu muss man aber wissen, wovon man redet und ich bin Programmierer und kein Physiker ;)
    @ rentier

    Gut, habe Dir das ganze mal sehr einfach und sehr nahe an Deiner Vorgehensweise eingebaut:

    Visual Basic-Quellcode

    1. Public Function Druckverlust(Rauhigkeit, R_i, Reynoldszahl)
    2. Dim y As Double
    3. Dim x As Double
    4. Dim a As Double
    5. Dim z As Double
    6. Dim i As Double
    7. Dim c As Double
    8. Dim j As Double
    9. Dim blnHit As Boolean
    10. Dim zMin As Double: zMin = 0.0000001
    11. Dim zMax As Double: zMax = zMin * 500000
    12. Dim zStep As Double: zStep = zMax / 2
    13. '// for Loop-Counter
    14. Dim intCounter As Long
    15. z = zStep
    16. a = 100000
    17. c = a
    18. If Rauhigkeit = 0 Then
    19. Do Until blnHit
    20. intCounter = intCounter + 1
    21. x = Round(1 / Sqr(z), 6)
    22. y = Round(2 * Log(Reynoldszahl * Sqr(z) / 2.51) / Log(10), 6)
    23. If x <> y Then
    24. If x < y Then
    25. zMax = z
    26. zStep = (zMax - zMin) / 2
    27. z = z - zStep
    28. ElseIf x > y Then
    29. zMin = z
    30. zStep = (zMax - zMin) / 2
    31. z = z + zStep
    32. Else
    33. blnHit = True
    34. End If
    35. End If
    36. If intCounter > 500000 Then
    37. MsgBox "Es konnte kein gültiges Ergebnis ermittelt werden!"
    38. Exit Do
    39. End If
    40. Loop
    41. Else
    42. Do Until blnHit
    43. '// Loop Counter
    44. intCounter = intCounter + 1
    45. x = Round(1 / Sqr(z), 6)
    46. y = Round(-2 * Log((Rauhigkeit / R_i) / 3.71 + 2.51 / (Reynoldszahl * Sqr(z))) / Log(10), 6)
    47. If x < y Then
    48. zMax = z
    49. zStep = (zMax - zMin) / 2
    50. z = z - zStep
    51. ElseIf x > y Then
    52. zMin = z
    53. zStep = (zMax - zMin) / 2
    54. z = z + zStep
    55. Else
    56. blnHit = True
    57. End If
    58. If intCounter > 500000 Then
    59. MsgBox "Es konnte kein gültiges Ergebnis ermittelt werden!"
    60. Exit Do
    61. End If
    62. Loop
    63. End If
    64. '// show how many loops needed
    65. MsgBox "Anzahl Rechnungsdurchläufe: " & intCounter
    66. Druckverlust = z
    67. End Function


    Eine Abweichung zu Deiner Rechnung ergibt sich erst in der 7ten Nachkommastelle, was aber daran liegt das z sich nicht exakt in 0.0000001 Schritten verändert, sondern auch noch weitere Nachkommastellen möglich sind durch die Berechnung von z.

    Aber auf diese Weise benötige ich eben nur 22 Rechnungsdurchläufe um das korrekte Ergebnis zu ermitteln im Gegensatz zu Deiner Variante die dafür 500000 Durchläufe braucht. Das ist eine Ersparnis von 499.988 Berechnungen (für diesen konkreten Fall). :D

    @ DoSchwob


    Es ist hier nicht unabhängig, weil hier jeweils der vorherige Wert mit dem delta von 0,00001 verändert wird. Zwar hast du schon den Nagel auf den Kopf getroffen, was die Iteration betrifft, allerdings geht es nicht mit diesem Datentyp und der gewünschten Genauigkeit. Die Genauigkeit wird nur vorgegaukelt, im Einzelfall läuft die Routine die komplette halbe Million mal durch die Schleife, weil der Datentyp Double (vermute ich) in einigen Ergebnisfällen nur noch zwischen + und - 0,000001 hin und herspringt, da x und y selten identisch sind. Daher die unterschiedliche Laufzeit.


    Wie Du oben siehst ist es völlig unabhängig von der Formel-Berechnung. Für die Vorgehensweise bei einer Iteration ist die Formel die dahinter steht völlig latte, weil es immer eine Variable geben MUSS die sich je Durchlauf noch oben oder nach unten innerhalb der bekannten/vorgegebenen Range verändert. Anders wäre Iteration nicht möglich.

    Gruß

    Rainer

    EDIT: Ach ja, habe dabei gleiche Deine Deklaration geändert denn mit "Dim a,b,c ... As Double" wird nur die letzte Variable als Double deklariert und alle vorhergehenden Variablen werden als Variant gewertet.

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

    rentier schrieb:

    Also beim berechnen selber setze ich ungefähr solche Werte ein: Rauhigkeit= 0,0015mm R_i=35mm und Reynoldszahl=10^5...10^6
    .


    Und was wäre dann für dich ein richtiges Ergebnis?

    Kannst du bitte mal ein konkretes Beispiel nennen?

    Wenn möglich auch mit Angaben zur gewünschten Genauigkeit.
    @ Lightsource

    Mach mal einen Schritt zur Seite ... Du stehst gerade auf der Leitung. 8-)


    Und was wäre dann für dich ein richtiges Ergebnis?


    Kopiere doch einfach oben seine Rechnung und rufe die mit denen Beispielszahlen auf. Dann haste das Ergebnis. :D


    Wenn möglich auch mit Angaben zur gewünschten Genauigkeit.


    Hat er doch schon ... 5 Nachkommastellen. :whistling:

    Gruß

    Rainer
    Sorry, sehe dennoch keine Leitung.

    Ich hatte gestern mit einigen verschiedenen Genauigkeitsanforderungen gerechnet und folgende Ergebnisse erhalten:

    Genauigkeit Ergebnis
    0,1 0,03476142883
    0,01 0,03344637592
    0,001 0,09992532085
    0,0001 0,09994713398
    0,00001 0,09994858621
    0,000001 0,03331636222

    die 0.0999 haben mich etwas stutzig gemacht, darum wollte ich der Sache auf den Grund gehen.
    Ich wollte sicher gehen, dass ich nicht selbst einen Fehler eingebaut hatte.
    Mit der Wertekombination die rentier genannt hat, hast Du diese abweichenden Ergebnis aber nicht ermittelt ... da wäre ja bei Reynoldszahl 10^5 das richtige Ergebnis 0.01821.

    Wenn Du andere Wertekombinationen eingesetzt hast, könnten sich die Abweichungen daraus ergeben das für die von Dir getesteten Wertekombinationen die Iterations-Range von 0.000001 bis 0.05 für z nicht ausreicht um an ein korrektes Ergebnis zu kommen.

    Das ist der Nachteil an einer automatisierten Iterationsberechnung wenn man die Iterations-Range fixed. Wertekombinationen bei denen das richtige Ergebnis außerhalb der Range liegt ergeben völlig falsche Ergebnisse.

    Gruß

    Rainer
    Vielen vielen Dank an alle, die geholfen haben!

    Rainer dein Code funktioniert super! Ich habe ihn gerade ausprobiert und bin begeistert :)
    Jetzt werde ich mich erstmal dem Verständnis des Ganzen widmen. Also nochmal vielen Dank

    @Lightsource: Hast du noch eine Frage bezüglich der Werte oder ist alles soweit klar?

    Viele Grüße

    rudi



    PS: Die Sache mit dem "Dim a,b,c ... As Double" war mir auch neu. Habe davon leider noch ncihts gefunden deswegen auch danke für den Hinweis!

    rentier schrieb:


    Rainer dein Code funktioniert super!


    Weiss ich. *trommelt und haut auf den Putz* :D


    Jetzt werde ich mich erstmal dem Verständnis des Ganzen widmen.


    Wie gesagt, ich habe ihn wirklich absolut einfach und exakt auf die Vorgehensweise Deines bisherigen Codes abgestimmt.

    Wenn Du ihn verstanden hast, dann gucke Dir den folgenden Code an der etwas eleganter gestaltet ist und vor allem Code-Rednunanzen vermeidet und auch auskommentiert ist (EDIT: Sorry, aber habe mir irgendwann angewöhnt in Denglish zu kommentieren ^^): ;)

    Visual Basic-Quellcode

    1. Option Explicit
    2. Public Type T_Iteration
    3. X As Double
    4. Y As Double
    5. Middle As Double
    6. Top As Double
    7. Bottom As Double
    8. End Type
    9. Public Function Druckverlust(Rauhigkeit, R_i, Reynoldszahl)
    10. Const NACHKOMMASTELLEN As Integer = 8
    11. Dim Maxcount As Long
    12. Dim Log10 As Double: Log10 = Log(10)
    13. Dim intCounter As Long
    14. Dim blnRauhigkeitIsNull As Boolean: blnRauhigkeitIsNull = (Rauhigkeit = 0)
    15. Dim TypeIt As T_Iteration
    16. With TypeIt
    17. '// set start parameters
    18. .Top = 1
    19. .Bottom = 0.000000001
    20. .Middle = .Top / 2
    21. Maxcount = .Top / .Bottom
    22. Do
    23. '// calculate formular outcome
    24. If blnRauhigkeitIsNull Then
    25. .X = Round(1 / Sqr(.Middle), NACHKOMMASTELLEN)
    26. .Y = Round(2 * Log(Reynoldszahl * Sqr(.Middle) / 2.51) / Log10, NACHKOMMASTELLEN)
    27. Else
    28. .X = Round(1 / Sqr(.Middle), NACHKOMMASTELLEN)
    29. .Y = Round(-2 * Log((Rauhigkeit / R_i) / 3.71 + 2.51 / (Reynoldszahl * Sqr(.Middle))) / Log10, NACHKOMMASTELLEN)
    30. End If
    31. '// push up counter by 1
    32. intCounter = intCounter + 1
    33. '// check maximum edge
    34. If Not intCounter > Maxcount Then
    35. '// if not have reached maximum edge then iterates
    36. If HitsIteration(TypeIt) Then
    37. '// if iterates hits leave loop
    38. Exit Do
    39. End If
    40. Else
    41. '// if have reached maximum edge show user message and leave method
    42. MsgBox "Es konnte kein gültiges Ergebnis ermittelt werden!"
    43. Exit Do
    44. End If
    45. Loop
    46. End With
    47. '// return value of middle
    48. Druckverlust = Round(TypeIt.Middle, NACHKOMMASTELLEN)
    49. End Function
    50. Public Function HitsIteration(ByRef TypeIteration As T_Iteration) As Boolean
    51. With TypeIteration
    52. If .X < .Y Then
    53. '// if x less y set middle to top
    54. .Top = .Middle
    55. ElseIf .X > .Y Then
    56. '// if y less x set middle to bottom
    57. .Bottom = .Middle
    58. Else
    59. '// if x equal y then middle is the correct outcome, return true and leave method
    60. HitsIteration = True
    61. Exit Function
    62. End If
    63. '// calculate new value to middle
    64. .Middle = (.Top + .Bottom) / 2
    65. End With
    66. End Function


    Ach ja ... habe jetzt auch mal die Iterations-Range höher geschraubt. Kannst Deine Wunschwerte ja selber nach Bedarf einstellen.

    Wenn Du jetzt noch eine Möglichkeit findest die Start-Parameter für Min und Max dynamisch in Abhängigkeit der Überabe-Parameter zu gestalten dann wäre es perfekt. *g*

    Gruß

    Rainer

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „raist10“ ()

    Ui na da muss ich mich wirklich ums Verständnis kümmern :)

    Habe beim Ausprobieren aber einen Fehler in zeile 63 bekommen: "Benutzerdefinierter Typ nicht definiert."

    Beim Googlen habe ich nur etwas über nicht eingebundene Klassen gefunden. Welche Klasse benötige ich denn und wo meckert VBA denn überhaupt? Ist es das Boolean?

    rentier schrieb:


    Habe beim Ausprobieren aber einen Fehler in zeile 63 bekommen: "Benutzerdefinierter Typ nicht definiert."


    Hast Du auch den Public Type mit kopiert?

    Wenn ja und der Fehler tritt weiterhin auf, dann poste mal exakt den Code den du übernommen hast und markiere die Stelle an der der Fehler auftritt ... eigentlich dürfe der aber nicht auftreten. o_O

    Ach ja ... habe oben noch eine unelegante Passage drinnen, habe ich hier geändert (Genauigkeit wird in den Type übernommen und dann in HitsIteration verarbeitet ... macht einen schlankeren Fuß ^^):

    Spoiler anzeigen

    Visual Basic-Quellcode

    1. Option Explicit
    2. Public Type T_Iteration
    3. X As Double
    4. Y As Double
    5. Middle As Double
    6. Top As Double
    7. Bottom As Double
    8. Genauigkeit As Integer
    9. End Type
    10. Public Function Druckverlust(Rauhigkeit, R_i, Reynoldszahl)
    11. Dim Maxcount As Long
    12. Dim Log10 As Double: Log10 = Log(10)
    13. Dim intCounter As Long
    14. Dim blnRauhigkeitIsNull As Boolean: blnRauhigkeitIsNull = (Rauhigkeit = 0)
    15. Dim TypeIt As T_Iteration
    16. With TypeIt
    17. '// set start parameters
    18. .Top = 1 '// max edge of range
    19. .Bottom = 0.000000001 '// min edge of range
    20. .Middle = .Top / 2 '// start-value for calculating
    21. .Genauigkeit = 8 '// set max decimal places
    22. Maxcount = .Top / .Bottom
    23. Do
    24. '// calculate formular outcome
    25. If blnRauhigkeitIsNull Then
    26. .X = 1 / Sqr(.Middle)
    27. .Y = 2 * Log(Reynoldszahl * Sqr(.Middle) / 2.51) / Log10
    28. Else
    29. .X = 1 / Sqr(.Middle)
    30. .Y = -2 * Log((Rauhigkeit / R_i) / 3.71 + 2.51 / (Reynoldszahl * Sqr(.Middle))) / Log10
    31. End If
    32. '// push up counter by 1
    33. intCounter = intCounter + 1
    34. '// check maximum edge
    35. If Not intCounter > Maxcount Then
    36. '// if not have reached maximum edge then iterates
    37. If HitsIteration(TypeIt) Then
    38. '// if iterates hits leave loop
    39. Exit Do
    40. End If
    41. Else
    42. '// if have reached maximum edge show user message and leave method
    43. MsgBox "Es konnte kein gültiges Ergebnis ermittelt werden!"
    44. Exit Do
    45. End If
    46. Loop
    47. End With
    48. '// return value of middle
    49. Druckverlust = Round(TypeIt.Middle, TypeIt.Genauigkeit)
    50. End Function
    51. Public Function HitsIteration(ByRef TypeIteration As T_Iteration) As Boolean
    52. With TypeIteration
    53. .X = Round(.X, .Genauigkeit)
    54. .Y = Round(.Y, .Genauigkeit)
    55. If .X < .Y Then
    56. '// if x less y set middle to top
    57. .Top = .Middle
    58. ElseIf .X > .Y Then
    59. '// if y less x set middle to bottom
    60. .Bottom = .Middle
    61. Else
    62. '// if x equal y then middle is the correct outcome, return true and leave method
    63. HitsIteration = True
    64. Exit Function
    65. End If
    66. '// calculate new value to middle
    67. .Middle = (.Top + .Bottom) / 2
    68. End With
    69. End Function


    Gruß

    Rainer