VBA - Boucle FOR / Comparaison / EMT

Bonjour à toutes, à tous et au forum.

Je me permet de poster un nouveau sujet concernant un problème que je rencontre sur ma macro. Je vais vous expliquer le but de ma macro et quels sont les différents problèmes que je rencontre. Je tiens à m'excuser particulièrement pour les éventuelles fautes d'orthographes, ainsi que les éventuelles infractions, si il y en a, par rapport à votre charte informatique. En effet, étant en entreprise j'ai des difficultés pour visualiser tous les sujets de ce forum mais c'est l'un des seuls auquel j'ai pu accéder. Trêve de bavardage, voici mon sujet.

I - Notions métrologique liées à ma macro

L'EMT est l'Erreur Maximale Tolérée.

L'échelon de vérification "e" est égale à k * d

Le taux de confiance "k" est un nombre entier allant de 1 à 10

La résolution numérique de la balance "d" peut prendre les valeurs de 0.01 à 1 par pas de 0.01

La masse maximale de la balance est appelé "C", pour notre cas C = 3 000g

Le nombre d'échelon est définie par "a" grâce à la formule a = C / e

II - Présentation macro

La norme NF EN 45501 détermine pour chaque balance une classe, il y en a 4. Chaque classe de balance à un intervalle de nombre d'échelons (appelé "a" dans ma macro) différents et donc d'EMT différentes.

Durant mon stage je dois réaliser une macro qui doit me donner tous les "k" et "d" possibles pour obtenir une EMT = 3.

Je dois réaliser ce cas pour les 4 Classes de balances, mais sachant que seul les intervalles changent, je m'intéresse seulement à la Classe I des balances et je n'aurais qu'à changer les intervalles.

Le but de ma macro est de faire tourner les valeurs de "k" et de "d" pour obtenir chaque "e" possible (e = k * d). Le "e" me permet de déterminer le nombre d'échelon avec la formule a = C / e. Pour une balance de Classe I nous savons ceci :

Pour un "a" inférieur à 50 000 l'EMT de la balance est de x = 1 * e. Mais moi je cherche un EMT de 3 soit 3 = 1 * e il me faut donc un e = 3 pour des valeurs de a <= 50 000

Pour un "a" compris entre 50 000 et 200 000 l'EMT de la balance est de x = 2 * e. Mais moi je cherche un EMT de 3 soit 3 = 2 * e il me faut donc un e = 1.5 pour des valeurs de 50 000 < a <= 200 000

Pour un "a" supérieur à 200 000 l'EMT de la balance est de x = 3 * e. Mais moi je cherche un EMT de 3 soit 3 = 3 * e il me faut donc un e = 1 pour des valeurs de 200 000 < a.

C'est à dire que ma macro fait varier les "d" de 0.01 à 1 par pas de 0.01 pour chaque k (de 1 à 10), c'est à dire j'obtiens 1 000 valeur différentes de "e". Chaque valeur de "e" me donne un "a" (a = C / e). J'ai donc 1 000 valeurs de "a". Chaque valeur de "a" est intégrée dans un intervalle. Et si x = e (suivant l'intervalle) alors je range les valeurs de "k" et de "d" sur mon tableau Excel.

Cela voudra que dire que ces valeurs de "k" et "d" me permettent d'obtenir un EMT de 3g sur ma balance.

J'espère avoir été assez clair sur ma description de macro...

III - Problèmes rencontrés

Actuellement ma macro fonctionnait, mais je l'ai trop modifiée maintenant je n'obtiens plus rien. Les résultats que j'avais ne me satisfaisait pas. Je n'obtenais pas toutes les valeurs de "k" et "d" voulu. J'ai vérifié à l'aide de ma calculette. J'ai donc modifié ma macro mais maintenant plus rien ne s'affiche. Voici donc mn programme et mon fichier excel en pièce jointe :

Sub Recherche_e_k_Classe1()

Dim EMT, C, e, k, d, a, b, x As Double

EMT = Range("K81")

C = Range("K82")

b = 90

For k = 1 To 10

For d = 0.01 To 1.01 Step 0.1

e = k * d

a = C / e

If a <= 50000 Then

x = 1 * e

If x = EMT Then

Cells(b, 10) = k

Cells(b, 11) = d

b = b + 1

End If

ElseIf 50000 < a <= 200000 Then

x = 2 * e

If x = EMT Then

Cells(b, 10) = k

Cells(b, 11) = d

b = b + 1

End If

ElseIf 200000 < a Then

x = 3 * e

If x = EMT Then

Cells(b, 10) = k

Cells(b, 11) = d

b = b + 1

End If

End If

Next

Next

Range(Cells(90, 10), Cells(b - 1, 11)).Select

Selection.Borders(xlDiagonalDown).LineStyle = xlNone

Selection.Borders(xlDiagonalUp).LineStyle = xlNone

With Selection.Borders(xlEdgeLeft)

.LineStyle = xlContinuous

.ColorIndex = 0

.TintAndShade = 0

.Weight = xlThin

End With

With Selection.Borders(xlEdgeTop)

.LineStyle = xlContinuous

.ColorIndex = 0

.TintAndShade = 0

.Weight = xlThin

End With

With Selection.Borders(xlEdgeBottom)

.LineStyle = xlContinuous

.ColorIndex = 0

.TintAndShade = 0

.Weight = xlThin

End With

With Selection.Borders(xlEdgeRight)

.LineStyle = xlContinuous

.ColorIndex = 0

.TintAndShade = 0

.Weight = xlThin

End With

With Selection.Borders(xlInsideVertical)

.LineStyle = xlContinuous

.ColorIndex = 0

.TintAndShade = 0

.Weight = xlThin

End With

With Selection.Borders(xlInsideHorizontal)

.LineStyle = xlContinuous

.ColorIndex = 0

.TintAndShade = 0

.Weight = xlThin

End With

With Selection

.HorizontalAlignment = xlCenter

.VerticalAlignment = xlBottom

.WrapText = False

.Orientation = 0

.AddIndent = False

.IndentLevel = 0

.ShrinkToFit = False

.ReadingOrder = xlContext

.MergeCells = False

End With

Range("J88:K88").Select

End Sub

En espérant avoir respecté votre charte informatique, je vous remercie d'avance de vos éventuelles réponses.

Cordialement

bonjour,

Ce type de construction n'est pas valide :

if 50000 < a <= 200000 then... 'renvoie toujours vrai !

Il faut écrire

If a > 50000 and a <= 200000 then...

A+

Bonjour,

Un truc m'échappe dans tes équations...

Si a = C/e et C=3000, pour e=3 on aura a=1000, pour e=1,5 on aura a=2000 et pour e=1 on aura a=3000, ce qui nous amènerait à être en permanence très largement en dessous de 50000 !?

Par ailleurs, je trouve tout à fait inopportun de mélanger de la mise en forme dans une macro de calcul...

(Je dois préciser, que j'ai vu cet aspect au survol, n'ayant pas lu la macro [pour cause d'"indigestion" de macros non indentées, et qui de plus n'est pas insérée entre des balises de codes]. Donc a-priori, je laisse la place à d'autres...)

Mais si on ne se précipite pas pour faire mécaniquement les boucles que tu indiques, ma question pourrait intéresser des intervenants éventuels.

Cordialement.

Bonjour galopin01 et MFerrand

Tout d'abord merci galopin01 cela fonctionne bien mieux.

Ensuite, MFerrand, le but de la macro n'est pas de poser e = 3. Mais de déterminer les "k" et "d" qui leurs sont liés. Comme précisé dans mon premier message nous avons e = k * d. Soit k variant de 1 à 10 et de variant de 0.01 à 1 par pas de 0.01.

Pour votre premier exemple, posons e = 3. Alors x = 1 * e = 1 * 3 = 3 donc x = 3 = EMT tout va bien. Mais vous avez obtenu e = 3 avec quelles valeurs de "k" et "d" ? Vous avez fait 10 * 0.3 ou 1.5 * 2 ou 0.6 * 5 ? Ce que je cherche c'est d'obtenir un e = EMT = 3 puis 1.5 puis 1 comme vous l'aurez remarqué, mais en indiquant dans mon fichier excel à chaque fois leurs valeurs de "k" et "d" correspondantes.

Voici le code épuré sans les formats de cellules :

Dim EMT, C, e, k, d, a, b, x As String

EMT = Range("K81")
C = Range("K82")
b = 90

For k = 1 To 10

    For d = 0.01 To 1.01 Step 0.01

    e = k * d
    a = C / e

    If a <= 5000 Then
    x = 1 * e
    If x = EMT Then
    Cells(b, 10) = k
    Cells(b, 11) = d
    b = b + 1
    End If

    ElseIf a > 50000 And a <= 200000 Then
    x = 2 * e
    If x = EMT Then
    Cells(b, 10) = k
    Cells(b, 11) = d
    b = b + 1
    End If

    ElseIf 200000 < a Then
    x = 3 * e
    If x = EMT Then
    Cells(b, 10) = k
    Cells(b, 11) = d
    b = b + 1
    End If

    End If

Next
Next
End sub

Donc maintenant... Ton problème est résolu ou pas ?

Je pense que tout fonctionne et que j'obtiens les bons résultats mais je ne suis pas sûr de mon code.

Sans doute, mais comme a ne peut jamais, et de très loin, être supérieur à 50000 [50000 ou 5000 d'ailleurs ? dans la macro il y a les 2 !], c'est faire tourner la boucle inutilement pour ces valeurs...

Et cherchant e=3, pour k variant de 1 à 10, on peut calculer la valeur de d et ne retenir que les cas où elle convient, soit pour k=3, 4, 5, 6 et 10, compte-tenu de tes définitions. Une seule boucle faisant varier k de 1 à 10 est donc suffisante pour obtenir les résultats valides.

(Ta macro est nettement plus lisible ! Mais correctement indentée, elle le serait bien plus encore !)

Cordialement.

C'est 50 000 pour le premier cas. Et si c'est possible d'avoir bien au dessus de 200 000 même. Posons k = 1 et d = 0.01, soit e = 1 * 0.01 d'où e = 0.01. Soit a = C / e = 3 000 / 0.01 = 300 000...

Tu me proposes quelque chose d'innovant, poser e = 3, k variant de 1 à 10 et déterminer "d" tel que d = e / k. Mais je vais devoir faire 3 boucles car e = 3 pour a <= 50 000 puis e = 1.5 pour 50 000 < a <= 200 000 et e = 1 pou a > 200 000. Je ne sais pas si le gain de temps sera là.

Je n'ai jamais indentée une macro, et c'est sûrement une erreur. Voici ma macro avec un essai d'indentation (si ça existe ce mot) :

Sub Recherche_e_k_Classe1()

Dim EMT, C, e, k, d, a, b, x As String

EMT = Range("K81")
C = Range("K82")
b = 90

For k = 1 To 10

    For d = 0.01 To 1.01 Step 0.01

        e = k * d
        a = C / e

        If a <= 50000 Then
        x = 1 * e
            If x = EMT Then
            Cells(b, 10) = k
            Cells(b, 11) = d
            b = b + 1
            End If

        ElseIf a > 50000 And a <= 200000 Then
        x = 2 * e
            If x = EMT Then
            Cells(b, 10) = k
            Cells(b, 11) = d
            b = b + 1
            End If

        ElseIf 200000 < a Then
        x = 3 * e
            If x = EMT Then
            Cells(b, 10) = k
            Cells(b, 11) = d
            b = b + 1
            End If

        End If

    Next
Next
End sub

C'est un petit peu mieux, on se rapproche de l'indentation totale ! Le mot existe bien. C'est cette utilisation qui est une signification acquise récemment.

Je ne nie pas que tu puisses avoir une valeur de a supérieure à 200000, mais ton énoncé stipule que tu recherche un EMT égal à 3 ! Par conséquent pas inférieur.

Ah super alors ! Je vais en devenir le Roi !

Je ne vois pas trop où tu veux en venir... Je suis un peu perdu :/


C'est comme cela qu'il faut procéder pour l'indentation ?

Dim EMT, C, e, k, d, a, b, x As String

EMT = Range("K81")
C = Range("K82")
b = 90

For k = 1 To 10

    For d = 0.01 To 1.01 Step 0.01
        e = k * d
        a = C / e

            If a <= 50000 Then
                 x = 1 * e
                    If x = EMT Then
                        Cells(b, 10) = k
                        Cells(b, 11) = d
                        b = b + 1
                    End If

            ElseIf a > 50000 And a <= 200000 Then
                x = 2 * e
                    If x = EMT Then
                        Cells(b, 10) = k
                        Cells(b, 11) = d
                        b = b + 1
                    End If

            ElseIf 200000 < a Then
                x = 3 * e
                    If x = EMT Then
                        Cells(b, 10) = k
                        Cells(b, 11) = d
                        b = b + 1
                    End If
            End If
    Next
Next

End Sub

Je viens de faire des essais et c'est par exemple pour la Classe 3 que j'ai un soucis...

La classe 3 est définie par les intervalles suivants :

Classe III EMT

0 ≤ a ≤ 500 ± 1 * e

500 < a ≤ 2 000 ± 2 * e

2 000 < a ≤ 10 000 ± 3 * e

Lorsque je lance ma macro elle me propose AUCUN résultat POUR UN EMT DE 1 (Je change par rapport à avant)... Pourtant lorsque je cherche avec ma calculette, j'obtiens ceci par exemple :

Il me faut un EMT de 1g soit je me place dans le premier intervalle et j'ai besoin d'un e = 1

Il me faut un EMT de 1g soit je me place dans le second intervalle et j'ai besoin d'un e = 0.5

Il me faut un EMT de 1g soit je me place dans le troisième intervalle et j'ai besoin d'un e = 0.33

Si e = 1 alors a = 3 000 / 1 = 3000 donc nous ne sommes pas dans le premier intervalle donc pas de résultat => Logique

Si e = 0.5 alors a = 3 000 / 0.5 = 6000 donc nous ne sommes pas dans le deuxième intervalle donc pas de résultat => Logique

Si e = 0.33 alors a = 3 000 / 0.33 = 9090.90 donc nous sommes dans le troisième intervalle donc on fait x = 3 * e = 3*0.33 = 1g

Pourtant ma macro ne me sort pas de résultats... Est-ce parce que le chiffre réel est 0.3333333333333 ?

Voici la macro pour la Classe 3 :

Dim EMT, C, e, k, d, a, b, x As String

EMT = Range("K81")
C = Range("K82")
b = 90

For k = 1 To 10
    For d = 0.01 To 1.01 Step 0.01
        e = k * d
        a = C / e

            If a <= 500 Then
                x = 1 * e
                    If x = EMT Then
                        Cells(b, 16) = k
                        Cells(b, 17) = d
                        b = b + 1
                    End If

            ElseIf a > 500 And a <= 2000 Then
                x = 2 * e
                    If x = EMT Then
                        Cells(b, 16) = k
                        Cells(b, 17) = d
                        b = b + 1
                    End If

            ElseIf a > 2000 And a <= 10000 Then
                x = 3 * e
                    If x = EMT Then
                        Cells(b, 16) = k
                        Cells(b, 17) = d
                        b = b + 1
                    End If
            End If
    Next
Next

End Sub

Bon ! indentation "classique" comme j'ai appris il y a 22 ans...

Sub recherche()
    Dim EMT, C, e, k, d, a, b, x As String
    EMT = Range("K81")
    C = Range("K82")
    b = 90
    For k = 1 To 10
        For d = 0.01 To 1.01 Step 0.01
            e = k * d
            a = C / e
            If a <= 50000 Then
                x = 1 * e
                If x = EMT Then
                    Cells(b, 10) = k
                    Cells(b, 11) = d
                    b = b + 1
                End If
            ElseIf a > 50000 And a <= 200000 Then
                x = 2 * e
                If x = EMT Then
                    Cells(b, 10) = k
                    Cells(b, 11) = d
                    b = b + 1
                End If
            ElseIf 200000 < a Then
                x = 3 * e
                If x = EMT Then
                    Cells(b, 10) = k
                    Cells(b, 11) = d
                    b = b + 1
                End If
            End If
        Next d
    Next k
End Sub

A la marge la déclaration de procédure et les étiquettes (quand il y en a)). Au premier retrait la succession d'instructions principales, et retrait pour toutes commandes incluses dans une même instruction (boucles, conditions, références à un même objet avec With...), ce qui permet de les voir dès le premier coup d'oeil. J'ai calculé qu'on pouvait passer jusqu'à 4 fois plus de temps pour lire une macro pas ou mal indentée (et que sauter des lignes ne facilite pas la lecture mais la complique encore si elle n'est pas indentée, et des commentaires abondants non plus quand on doit chercher le code au milieu...)

Cordialement.

Et en complément, l'autre aspect important que j'ai retenu, c'est de programmer autant que possible de façon modulaire, cela raccourcit les procédures, on voit mieux ce qu'elles font et on gagne au total en volume de code.

Par exemple, dans ta macro, tu répètes 3 fois la même suite de commandes : dans les cas où x=EMT tu pourrais donc renvoyer à une procédure secondaire les valeurs de k et d pour qu'elle les inscrive. Tu me diras que tu perds la ligne... mais nullement, b étant définie dans la procédure secondaire, tu peux déclarer la variable comme statique de façon qu'elle conserve la valeur entre 2 appels.

(Tu as aussi la possibilité d'utiliser des variables module.)

Et pour optimiser encore : plutôt que d'affecter le résultat à chaque fois, constituer un tableau, pour ne l'affecter qu'en une fois à la fin. Cela accélère le processus...


Est-ce parce que le chiffre réel est 0.3333333333333 ?

Oui !

Merci MFerrand pour ce modèle d'indentation que j'utiliserai le mieux possible à l'avenir. En effet cela améliore la compréhension je suis d'accord lorsque j'ai comparé votre modèle à mon tout premier code transmis dans ce sujet.

En second lieu, je comprend ce que vous m'avez dit sur les procédures secondaires pour améliorer mon code. Mais je dois l'avouer je ne vois pas du tout comment faire. Je suis novice en VBA et j'essaye au mieux de répondre aux attentes de mon maitre de stage.

C'est donc ça, il faudrait que j'ajoute des décimales sur mon "d" comme par exemple "d" allant de 0.0001 à 1 par pas de 0.0001 mais c'est inutile "d" correspond à la résolution numérique de la balance est actuellement elle n'est même pas de 0.01g mais de 1g. J'ai pris 0.01g pour des essais si le moyen de mesure (la balance) est changé.

Sur des nombres à décimales infinies, tu n'as guère de chances de satisfaire une égalité. Il vaudrait mieux arrondir à 2.

Et le problèmes des décimales infinies se pose aussi en binaire (pas pour les mêmes nombres, mais en particulier, 0,1 est dans ce cas). Le troncage par le calculateur intervient entre la 12e et la 15e décimale, mais ça suffit pour que les comparaisons soient fausses à la suite. Comme tu travaille avec 2 décimales, autant arrondir.

En effet autant arrondir à 2 décimales ! Ce que je pense faire par la suite. Nous parlons actuellement décimales et j'aimerai vous faire part d'une chose étonnante que j'ai remarqué sur Excel.

Lorsque l'on réalise une comparaison d'une valeur tel que 0.1 par rapport à cette valeur alors dès fois on obtient "Conforme" et des fois "Non Conforme".

En effet, avec Excel on apprend que 10.1 - 10 =/= 0.1 et oui c'est égale à 0,1000000000000010000000000000000

Je ne savais pas du tout cela !

Pour plus de compréhension je vous ai mit un fichier Excel expliquant cela.

Est-ce que c'est une erreur connue ? Est-ce que c'est ce que vous m'expliquez au niveau binaire ?

Pour la résoudre dans mon cas j'ai arrondi à 2 chiffres après la virgule.

Bonsoir,

C'est tout à fait ça, et ce n'est ni une anomalie ni un bogue. Cela tient à la nature des nombres et aux capacités de stockage, sachant que lors d'un calcul le processeur opère des stockages intermédiaires. Dès lors qu'un nombre ou un résultat se trouve tronqué, le résultat final s'en trouve naturellement affecté. C'est infinitésimal mais un test d'égalité renverra faux.

J'avais constaté la chose il y a longtemps dans mes comptes perso, dans lesquels j'avais mis en place un dispositif de vérification. Au bout d'un certain temps, le système de vérification me signalait des erreurs que je ne pouvais trouver et pour cause. Ayant fini par voir comment ça se passait, j'ai basculé mes vérifications en arrondis, à la 5e décimale si je me souviens bien, pour garder une marge dans les 2 sens. Les explications, je les ai trouvées plus tard...

Bonne soirée.

Bonjour,

Je pense que l'entièreté de mes questions ont été répondu.

Merci encore à galopin01 et mille merci à MFerrand pour ses nombreuses contributions.

A une prochaine fois !

Rechercher des sujets similaires à "vba boucle comparaison emt"