Boucle infini (VBA)

Boucle infini (VBA) - VB/VBA/VBS - Programmation

Marsh Posté le 27-09-2013 à 18:43:10    

Bonjour,
 
Je suis débutant en  VBA et voilà déjà ma première boucle infini, il semblerait que ma boucle for se passe mal.
 
Pouvez vous m'éclairer?
 
Sub Méthode1()
    Dim epsilon As Double
    Dim r As Double
    Dim M As Integer
    Dim c As Integer
    Dim N As Integer
    Dim P As Double
    Dim j As Integer
    r = 0
    M = 5
    c = 5
    N = 100
    P = 80
    epsilon = 1
     
    While (epsilon > 0.1)
     
    S = 0
    For j = 1 To 5
        S = S + c / ((1 + r) ^ i)
        Next j
        S = S + N / ((1 + r) ^ M)
    epsilon = Abs(P - S)
    r = r + 0.01
    Wend
     
    MsgBox (r)
     
     
End Sub
 
//En tout cas je vous remercie.

Reply

Marsh Posté le 27-09-2013 à 18:43:10   

Reply

Marsh Posté le 27-09-2013 à 19:46:00    

 
           Bonjour,
 
           merci d'utiliser la prochaine fois l'icône C dédiée au code …   Une bonne indentation est aussi appréciée.
 
           En regardant donc juste la condition de la boucle, epsilon est toujours supérieur à 0.1 empêchant la sortie de la boucle …
           Prévoir peut-être un nombre maximum d'itérations, non ?
 
           Ce serait judicieux de tout mettre à plat, entre un schéma en langage courant,
           la sémantique de ce qu'est censé faire le code, et en comparant si chaque ligne de code correspond bien à ce schéma …


Message édité par Marc L le 27-09-2013 à 19:48:20
Reply

Marsh Posté le 27-09-2013 à 22:02:13    

Désolé, effectivement, c'est la première fois que je poste.
 
ça m'étonne un peu d'avoir toujours epsilon>0.1 puisque je cherche à résoudre une équation dont je connais une solution approximative r=0.11 avec les paramètres que j'ai choisi.
 
(Je ne sais pas si on peut mettre du LaTeX ici.) Mais c'est:
 
P-c/(1+r)-...-c/((1+r)^5)- N / ((1 + r) ^ M)=0
 
Et ceci tend vers P>0 quand r tend vers l'infini et ça vaut P-5c-N<0 en r=0, alors cette valeur de r je suis sûr qu'elle existe.
 
Mais il est possible que ce soit mon algo qui soit faux.
 
Du coup mettre un nombre maximum d'itérations ne m'intéresse pas trop.

Reply

Marsh Posté le 28-09-2013 à 02:20:37    

 
           Epsilon reste bloqué vers les 55, donc méthode à revoir …
 
           Pour pouvoir le vérifier, ajouter les deux lignes suivantes juste avant le  Wend :

Code :
  1.     Debug.Print epsilon
  2.     DoEvents


           La progression d'epsilon en direct dans la fenêtre Exécution ! …
 

Reply

Marsh Posté le 28-09-2013 à 11:43:48    

Bonjour,
 
Merci en fait j'ai reprogrammé ça dans un autre langage pour vérifier. Et j'ai vu que l'algo était bon.
L'erreur vient en fait parce que j'ai oublié de déclarer S.
 
J'ai un peu honte.

Reply

Marsh Posté le 28-09-2013 à 12:31:06    

 
           En double ?  Sinon pas de honte à avoir …
 
           L'instruction Option Explicit en début de module permet d'éviter ce problème en obligeant de déclarer les variables
           ou encore en cochant la case Déclaration des variables obligatoire dans les Options de l'environnement VBA.
 
           DoEvents permet de pouvoir garder la main pour interrompre la boucle …


Message édité par Marc L le 28-09-2013 à 12:34:55
Reply

Marsh Posté le 28-09-2013 à 13:59:04    

Oui c'est ça il manque un:
Dim S As Double
Et dans le code que j'ai mis ici il y a une autre erreur, j'ai oublié de modifier le i en j.
Merci pour ces conseils, je vais les utiliser, ça va m'éviter des difficultés.
 

Reply

Marsh Posté le 29-09-2013 à 11:20:07    

 
           Avec seulement ces corrections, la boucle ne s'arrêtera pas plus avec le pas de r de 0.01
           vu que r doit se trouver entre 0.10 & 0.11, donc obligation d'affiner le pas …
 
           Qui plus est le résultat r de ton code est faussé de +0.01 à cause de la conception de la boucle,
           l'ajout du pas s'effectuant avant le test de sortie …
 
           J'aimerais bien voir ton code qui fonctionne.   Combien d'itérations pour trouver la solution ?
 
           De mon côté ma version avec la résolution de 0.1 n'a besoin que de 6 itérations pour la trouver, 9 pour 0.01 et 18 pour 0.001 …
 

Reply

Marsh Posté le 29-09-2013 à 14:49:19    

Oui de toute façon je voulais une solution un peu plus précise, voici mon code, je ne l'ai pas du tout optimisé car je ne cherchais qu'à comparer une approximation grossière mais qui se fait à l'aide d'un simple calcul  avec cette méthode qui me donne pratiquement la solution exact à mon équation.
Mais en tout cas, je vois que votre méthode semble très rapide, vous utilisez une dichotomie?
Mais, je me dis que dans ce cas là, il faut avoir une petite idée de ce que vaut r?
 
Sub Méthode1()
    Dim epsilon As Double
    Dim r As Double
    Dim M As Integer
    Dim c As Integer
    Dim N As Integer
    Dim P As Double
    Dim j As Integer
    Dim S As Double
     
     
    r = 0
    M = 5
    c = 5
    N = 100
    P = 80
    epsilon = 1
     
    While (epsilon > 0.001)
     
    S = 0
    For j = 1 To M
        S = S + c / ((1 + r) ^ j)
        Next j
        S = S + N / ((1 + r) ^ M)
    epsilon = Abs(P - S)
    r = r + 0.000001
    Wend
     
    MsgBox (r)
     
     
End Sub

Reply

Marsh Posté le 29-09-2013 à 17:45:47    

 
           Il y a pourtant une icône pour le code ‼
 
           Sinon avec la résolution de 0.000001 de ton dernier code, 103 189 itérations sont nécessaires pour terminer le processus.
           Pour éviter le souci de boucle sans fin, je n'autorise pas mes procédures de dépasser les 99 itérations !
 
           Ton résultat est toujours faussé par la position de l'incrémentation de la variable  r  dans la boucle …
 
           J'utilise la même méthode mais en partant d'un pas supérieur pour la variable  r  accélérant donc la procédure
           tout en détectant évidemment le moment où cette variable est trop grande afin d'affiner ce pas.
 
           Désactiver  Option Explicit  ou la Déclaration des variables obligatoire car les variables de mes procédures sont déclarées à la volée
 
           La variable  D  est la résolution de l'approximation des décimales,  A  est le pas de la variable  r  et  F  le résultat de la formule.
 
           La ligne n°12 est la détection pour l'affinage du pas.

Code :
  1. Sub Demo1()
  2.     Const D# = 0.00001, c% = 5, M% = 5, N% = 100, P% = 80
  3.    
  4.     A# = 0.1
  5.    
  6.     Do
  7.         r# = r# + A
  8.         U# = 1 + r
  9.         F# = N / U ^ M
  10.         For j% = 1 To 5:  F = F + c / U ^ j:  Next
  11.         E# = P - F
  12.         If E > D Then r = r - A: A = A / 10
  13.         I% = I% + 1
  14.     Loop While Abs(E) > D And I < 99
  15.    
  16.     MsgBox I & " itérations :" & vbLf & vbLf & "r = " & r & "     F = " & F
  17. End Sub

           En modifiant la variable  D  la valeur de  r  en sera donc plus fine …
           Cette procédure s'avère plus précise que la tienne pourtant avec une résolution moindre !
 
           Mais au lieu de manuellement varier le pas, mieux vaut le faire automatiquement jusqu'à une approximation raisonnable !
           Certes le raisonnable n'est pas toujours scientifique, mais pour des besoins courants,
           une approximation du résultat de la formule de quatre décimales semble suffisante, comme par exemple en gestion / finances ...
           La variable  E  est maintenant de type  Currency  :

Code :
  1. Sub Demo2()
  2.     Const c% = 5, M% = 5, N% = 100, P% = 80
  3.    
  4.     D# = 1
  5.    
  6.     Do
  7.         A# = 0.1
  8.          D = D / 10
  9.         I% = 0
  10.         r# = 0
  11.    
  12.         Do
  13.              r = r + A
  14.             U# = 1 + r
  15.             F# = N / U ^ M
  16.             For j% = 1 To 5:  F = F + c / U ^ j:  Next
  17.             E@ = P - F
  18.             If E > D Then r = r - A: A = A / 10
  19.             I = I + 1
  20.         Loop While Abs(E) > D And I < 99
  21.    
  22.         T$ = T$ & "D = " & D & "   r = " & r & "   (" & P - E & ";)   [" & I & "]" & vbLf & vbLf
  23.     Loop Until E = 0 Or I = 99
  24.    
  25.     MsgBox T
  26. End Sub

           Cette procédure n'a d'autre utilité avec l'augmentation de la résolution de démontrer l'affinage de  r
           jusqu'à atteindre une approximation raisonnable en comparant la progression des itérations nécessaires …
 
           En combinant les deux codes précédents, cette approximation raisonnable est directement calculée en seulement 21 itérations  !

Code :
  1. Sub Demo3()
  2.     Const c% = 5, M% = 5, N% = 100, P% = 80
  3.    
  4.     A# = 0.1
  5.     D# = 0.1
  6.    
  7.     Do
  8.         r# = r# + A
  9.         U# = 1 + r
  10.         F# = N / U ^ M
  11.         For j% = 1 To 5:  F = F + c / U ^ j:  Next
  12.         E@ = P - F
  13.         If Abs(E) <= D And E <> 0 Then D = D / 10
  14.         If E > D Then r = r - A: A = A / 10
  15.         I% = I% + 1
  16.     Loop Until E = 0 Or I = 99
  17.    
  18.     MsgBox I & " itérations :" & vbLf & vbLf & "r = " & r & "     D = " & D
  19. End Sub


           La dichotomie est efficace en l'a contrôlant quelque peu !
 
           Sinon je me demande même sans VBA si le Solveur intégré à Excel suffirait, une autre piste à explorer …

Message cité 1 fois
Message édité par Marc L le 30-09-2013 à 12:20:46
Reply

Marsh Posté le 29-09-2013 à 17:45:47   

Reply

Marsh Posté le 29-09-2013 à 21:54:17    

Marc L a écrit :

Cette procédure s'avère plus précise que la tienne pourtant avec une résolution moindre !

             J'ai confondu la résolution et le pas !   Il fallait l'entendre pourtant avec un pas supérieur
 
 
           Sinon voici une variante de la procédure Demo1 apportant une meilleure précision sur la dernière décimale vis à vis de la résolution :

Code :
  1. Sub Demo()
  2.     Const D# = 0.00001, c% = 5, M% = 5, N% = 100, P% = 80
  3.    
  4.     A# = 0.1
  5.     G# = 1
  6.    
  7.     Do
  8.         r# = r# + A
  9.         U# = 1 + r
  10.         F# = N / U ^ M
  11.         For j% = 1 To 5:  F = F + c / U ^ j:  Next
  12.         E# = P - F
  13.         B# = Abs(E)
  14.    
  15.         If B <= D Or S# > 0 Then
  16.             If B < G Then G = B: S = r: X# = F
  17.             T% = B > G Or E > 0
  18.    
  19.         ElseIf E > D Then
  20.             r = r - A
  21.             A = A / 10
  22.         End If
  23.    
  24.         I% = I% + 1
  25.     Loop Until T Or I = 99
  26.    
  27.     MsgBox I & " itérations :" & vbLf & vbLf & "r = " & S & "     F = " & X
  28. End Sub

           Une fois la résolution atteinte, cette procédure va voir si l'Epsilon n'est pas inférieur en incrémentant encore d'un pas,
           on n'est pas à deux / trois itérations près !


Message édité par Marc L le 30-09-2013 à 12:26:18
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed