XL 2019 Problème calcul % sur calculatrice

  • Initiateur de la discussion Initiateur de la discussion Nathe
  • Date de début Date de début

Boostez vos compétences Excel avec notre communauté !

Rejoignez Excel Downloads, le rendez-vous des passionnés où l'entraide fait la force. Apprenez, échangez, progressez – et tout ça gratuitement ! 👉 Inscrivez-vous maintenant !

Nathe

XLDnaute Junior
Bonjour à toutes et tous,

Je suis en train d'essayer de monter un projet calculatrice sur excel mais je peine sur l'adaptation du calcul du pourcentage,
Si une personne saurai comment effectué le code qui irai bien.

Merci à tous
Nathe

Animation.gif
 

Pièces jointes

Hello,
j'ai trouvé une nouvelle bibliothèque (MxParser) qui m'a l'air de bien calculer les étapes de calculs :
MxParser.gif


le souci c'est que c'est une bibliothèque assez volumineuse ( 1 Mo en assemblage dotnet), qu'elle n'existe pas en VBA (existe en dotnet, java, C++) qu'elle fait bien plus de choses que de calculer les étapes de calcul. J'ai réussi à l'utiliser dans ma dll qui s'appelle comme une API windows.
VB:
#If Win64 Then
   Declare PtrSafe Function CreateUtilsClass Lib "D:\Tmp\ClassesCSharpJP\ClassesCSharpJPx64.dll" () As Object
#Else
   Declare PtrSafe Function CreateUtilsClass Lib "D:\Tmp\ClassesCSharpJP\ClassesCSharpJPx86.dll" () As Object
#End If
Sub MxParser(exp)
Dim utils As Object, Resultat As String
Set utils = CreateUtilsClass()
Resultat = utils.MxParser(exp)
UsfTB.TextBox1.text = Resultat
End Sub

En ce qui concerne le % j'ai testé plusieurs calculateurs en ligne : ils ne me donnent pas tous le même résultat alors je me demande si il y a vraiment une règle qui fait fois. Et en calcul scientifique le % c'est le modulo.

Ami calmant, J.P
 
Dernière édition:
pas mal du tout mais 1 mega c'est chaud quand même

regarde avec ma petite fonction putprioritysegment et mon moteur html
je part de ça
chaine = "3*2*8*4.5+10/1.5*2-4*2"
apres la fonction putprioritysegment on arrive à ça
(((3x2)x8)x4.5)+(((10/1.5)x2))-(4x2)
et en avant gringuant le moteur html

1741021737343.png
 
Bonjour
@patricktoulon
Votre algorithme n'est pas encore stable , les parenthèses sont placés correctement mais l’ordre d’évaluation n'est pas exacte comme on voit sur la photo :
(4x2) = 8
(10/1.5) = 6.666
(3x2) = 6

@jurassic pork
le souci c'est que c'est une bibliothèque assez volumineuse ( 1 Mo en assemblage dotnet), qu'elle n'existe pas en VBA (existe en dotnet, java, C++) qu'elle fait bien plus de choses que de calculer les étapes de calcul. J'ai réussi à l'utiliser dans ma dll qui s'appelle comme une API windows.
Pour les expressions mathématique,s, les parsseur top-down récursives sont les plus utilisés et plus simple à réaliser .tu peux jeter un coup d’œil sur ce projet :

Mon interpréteur affiche le même ordre d’évaluation que le dernier exemple que tu as posté mais avec moins d’ambiguïté :
3*2*8*4,5+10/1,5*2-4*2:
6 = 3 * 2
48 = 6 * 8
216 = 48 * 4,5
6,66666666666667 = 10 / 1,5
13,3333333333333 = 6,66666666666667 * 2
229,333333333333 = 216 + 13,3333333333333
8 = 4 * 2
221,333333333333 = 229,333333333333 - 8
 
Bonsoir @Rheeem
l'ordre des (segments solo )n'a que peu d'importance selon moi l’essentiel c'est que le priorités des opérandes soient respectées
d’ailleurs un développer d’opération n'est normalement pas linéaire mais plutôt comme un organigramme
du moins j'ai appris comme ça à l’école pour autant que je me souvienne
 
et si tu tiens absolument a traité dans l'ordre ben c'est simple on va en avant a l'inverse de mon moteur html (1)
mais on a y va par pas de 1 segment solo avec autant de rebond que nécessaire

un exemple comme ça vite fait a main levée j'ai pas déclaré les variables mais bon
pour le reste de l'operation après c'est simple même si je ne le fait pas
tu replace les "+" et "-") par des "|+" & "|-"
tu split par les "|"
et dans une dernière boucle tu fait un dernier tour de danse en evaluant(evaluate item(x) avec item(x+1)
terminé

VB:
Function PutPrioritySegment(chaine)
    Dim elem, i&, t
    For Each elem In Array("+", "-", "*", "/"): chaine = Replace(chaine, elem, "|" & elem): Next
    chaine = Replace(chaine, "/", "*/")
    Do While InStr(chaine, "*") > 0
        t = Split(chaine, "|")
        For i = 1 To UBound(t)
            If InStr(t(i), "*") Then t(i - 1) = "(" & t(i - 1): t(i - 1) = t(i - 1) & Replace(t(i), "*", "x") & ")": t(i) = "": Exit For
        Next
        chaine = Replace(Replace(Replace(Replace(Join(t, ""), "*", "|*"), "+", "|+"), "-", "|-"), ":", "|:")
        'Debug.Print chaine
    Loop
    chaine = Replace(Replace(Replace(chaine, "(|+", "+("), "(|-", "-("), "(|:", "/(")
    chaine = Replace(chaine, "(+", "+(")
    chaine = Replace(chaine, "x/", "/")
    chaine = Replace(chaine, "|", "")
    PutPrioritySegment = chaine
End Function

Sub testu()
    chaine = "3*2*8*4.5+10/1.5*2-4*2"
    Debug.Print "original:" & chaine
    chaine = PutPrioritySegment(chaine)
    Debug.Print "priority:" & chaine
    With CreateObject("htmlfile")
        .body.innerhtml = Replace(Replace(chaine, "(", "<div>"), ")", "</div>")
        Debug.Print Replace(.body.innerhtml, vbCrLf, "")
        Debug.Print "-"
        For e = 1 To 100
            Set elem = .body.getelementsbytagname("div")
            If elem.Length = 0 Then Exit For
            For i = 0 To elem.Length - 1
                If elem(i).Children.Length = 0 Then
                    oldSegment = elem(i).innertext
                    x = Evaluate(Replace(elem(i).innertext, "x", "*"))
                    MsgBox elem(i).innerhtml
                    If Not IsError(x) Then elem(i).outerhtml = x
                    Exit For
                End If

            Next
            Debug.Print "priorité:" & oldSegment & "=" & x
            Debug.Print Replace(Replace(Replace(.body.innertext, "<div>", ""), "</div>", ""), vbCrLf, "")
        Next
    End With
End Sub
la console
original:3*2*8*4.5+10/1.5*2-4*2
priority : (((3x2)x8)x4.5)+((10/1.5)x2)-(4x2)
<DIV><DIV><DIV>3x2</DIV>x8</DIV>x4.5</DIV>+<DIV><DIV>10/1.5</DIV>x2</DIV>-<DIV>4x2</DIV>
-
priorité:3x2=6
6x8x4.5+10/1.5x2-4x2
priorité:6x8=48
48x4.5+10/1.5x2-4x2
priorité:48x4.5=216
216+10/1.5x2-4x2
priorité:10/1.5=6,66666666666667
216+6.66666666666667x2-4x2
priorité:6.66666666666667x2=13,3333333333333
216+13.3333333333333-4x2
priorité:4x2=8
216+13.3333333333333-8
imparable le principe du html
et le principe est simple
l'object htmlelement=sa valeur(evaluer avec evaluate)
 
Pour les expressions mathématique,s, les parsseur top-down récursives sont les plus utilisés et plus simple à réaliser .tu peux jeter un coup d’œil sur ce projet :
Hello,
merci du renseignement Jigsaw est aussi disponible sous gitbhub ici.
Finalement, j'ai arrêté de prospecter les bibliothèques de lexer parser car il y en a plein mais jamais en VBA, ce qui entraînerait une surcouche
pour pouvoir l'utiliser en VBA.
J'ai trouvé une classe VBA qui m'a l'air pas mal pour ce qui nous intéresse dans cette discussion.
clsMathParser 4 est un parseur-évaluateur pour les expressions mathématiques et physiques de chaîne.
Voici ce que j'arrive à faire avec :
clsMathParser.gif

avec ce code :
VB:
Sub TestMathParser()
Dim Fonct As New clsMathParser, EtTable(), i As Integer
Dim OK As Boolean
OK = Fonct.StoreExpression(Me.TextBox2.text)
TextBox1 = "Le résultat est " + CStr(Fonct.Eval) + vbCrLf
Fonct.ET_Dump EtTable
For i = LBound(EtTable, 1) To UBound(EtTable, 1)
   TextBox1 = TextBox1 + CStr(EtTable(i, 5)) + vbTab + CStr(EtTable(i, 1)) + vbTab + _
                 CStr(EtTable(i, 8)) + vbTab + CStr(EtTable(i, 11)) + vbCrLf
Next i
End Sub
Les étapes paraissent parfois être dans le désordre mais il faut comprendre comment la table EtTable est générée. D'ailleurs dans cette table, il y a d'autres variables que je n'ai pas affiché.
Ami calmant, J.P
 
Dernière édition:
re
a regarder svp
Pour afficher ce contenu, nous aurons besoin de votre consentement pour définir des cookies tiers.
Pour plus d'informations, consultez notre page sur les cookies.
VB:
Sub test()
    chaine = "3*2*8*4.5+10/(1.5*2)-4*2"
    If chaine Like "*(*)*" Then chaine = HTMLparser(chaine)
    chaine = PutPrioritySegment(chaine)
    chaine = HTMLparser(chaine)

End Sub
Function PutPrioritySegment(chaine)
    Dim elem, i&, t
    For Each elem In Array("+", "-", "*", "/"): chaine = Replace(chaine, elem, "|" & elem): Next
    chaine = Replace(chaine, "/", "*/")
    Do While InStr(chaine, "*") > 0
        t = Split(chaine, "|")
        For i = 1 To UBound(t)
            If InStr(t(i), "*") Then t(i - 1) = "(" & t(i - 1): t(i - 1) = t(i - 1) & Replace(t(i), "*", "x") & ")": t(i) = "": Exit For
        Next
        chaine = Replace(Replace(Replace(Replace(Join(t, ""), "*", "|*"), "+", "|+"), "-", "|-"), ":", "|:")
        'Debug.Print chaine
    Loop
    chaine = Replace(Replace(Replace(chaine, "(|+", "+("), "(|-", "-("), "(|:", "/(")
    chaine = Replace(chaine, "(+", "+(")
    chaine = Replace(chaine, "x/", "/")
    chaine = Replace(chaine, "|", "")
    PutPrioritySegment = chaine
End Function

Function HTMLparser(chaine)
    Debug.Print "original:" & chaine
    'chaine = PutPrioritySegment(chaine)
    Debug.Print "priority:" & chaine
    With CreateObject("htmlfile")
        .body.innerhtml = Replace(Replace(chaine, "(", "<DIV>"), ")", "</DIV>")
        Debug.Print Replace(.body.innerhtml, vbCrLf, "")
        Debug.Print "-"
        For e = 1 To 10
            Set elem = .getelementsbytagname("DIV")
            If elem.Length = 0 Then Exit For
            For i = 0 To elem.Length - 1
                If elem(i).Children.Length = 0 Then
                    'If elem(i).innerhtml Like "*x*" Then
                    oldSegment = elem(i).innertext
                    x = Evaluate(Replace(elem(i).innertext, "x", "*"))
                    MsgBox elem(i).innerhtml & vbCrLf & elem(i).NodeType
                    If Not IsError(x) Then elem(i).outerhtml = x
                    Exit For
                    'End If
                End If
            Next
            Debug.Print "priorité:" & oldSegment & "=" & x
            Debug.Print Replace(Replace(Replace(.body.innertext, "<div>", ""), "</div>", ""), vbCrLf, "")
        Next
        HTMLparser = Replace(Replace(Replace(.body.innertext, "<div>", ""), "</div>", ""), vbCrLf, "")
    End With
End Function
 
Hello patricktoulon,
A mon avis la touche % comme elle est utilisée sur une calculette est "out of control" , j'ai testé plusieurs calculatrices en ligne avec une expression avec des pourcents et cela ne me donne pas toujours le même résultat . La logique serait que le pourcent s'applique à ce que l'on lui multiplie .
donc il faudrait toujours un opérateur multiplie devant. Mais pour une calculette on peut très bien se fixer une règle mais dans ce cas il faut l'indiquer aux utilisateurs.
Ami calmant, J.P
 
Bonjour @jurassic pork
ma règle est simple
si c'est -y% c'est "*" & evaluate(yx%)
si c'est "+y%" c'est "*" & 1+ & evaluate(y%)

je me suis basé sur la calculette windows
après c'est vrai j'ai essayé plusieur calculette sur le web et elles ne donne pas toutes la même réponse
tout simplement par ce que le parseur n'est pas forcement juste

d'ailleurs je n'en ai trouvé aucun de 100% juste
donc
par défaut une (addition ou soustraction de pourcentage) c'est une multiplication par (la règle de 3 sur 100) et (+1 pour le positif )
parti de là on applique la règle de priorité classique de la multiplication
a savoir " le segment qui précède X le multiple de 100(+1 pour le positif)"
en l'occurence ici
original:3x2x8+10%x4.5+10/1.5x2-4x2
3x2x8x1,1x4.5+10/1.5x2-4x2
6x8x1,1x4.5+10/1.5x2-4x2
48x1,1x4.5+10/1.5x2-4x2
et si on met les parenthèse de priorité ça donne
((((3x2)x8)x1,1)x4.5)+((10/1.5)x2)-(4x2)

en tout cas moi j'applique cette règle
sinon c'est pas possible on peut pas envisager 36 règles
 
re
en vba pas besoins de se casser la tête
evaluate("+10%") va te donner 0.1
evaluate("-10%") va te donner -0.1

si c'est"+" tu ajoute 1 donc 1.1
si c'est "-" tu laisse comme tel mais le reste soit 0.9
et tu replace l'operateur par "x"
et comme "+-" ça fait moins le code est réduit a ceci
VB:
Function convertPercent(chaine)
    chaine = Replace(chaine, "x", "*")
    For Each elem In Array("+", "-", "*", "/"): chaine = Replace(chaine, elem, "|" & elem): Next
    'Debug.Print chaine
    t = Split(chaine, "|")
    For i = 0 To UBound(t)
        If InStr(t(i), "%") Then t(i) = "*" & 1 + Evaluate(t(i))
    Next
    convertPercent = Join(t, "")
End Function
 
Dernière édition:
- Navigue sans publicité
- Accède à Cléa, notre assistante IA experte Excel... et pas que...
- Profite de fonctionnalités exclusives
Ton soutien permet à Excel Downloads de rester 100% gratuit et de continuer à rassembler les passionnés d'Excel.
Je deviens Supporter XLD

Discussions similaires

Réponses
17
Affichages
782
Réponses
9
Affichages
275
Réponses
3
Affichages
77
Retour