XL 2010 Convertir une variable dans une fonction

Magic_Doctor

XLDnaute Barbatruc
Bonjour,

J'ai bricolé une fonction toute simple qui marche bien. Elle me renvoie soit le nombre de décimales après la virgule du chiffre traité, soit l'ensemble des chiffres après la virgule.
Si je rentre dans la fonction, par exemple, 25,000587, j'obtiens bien 000587 sous forme de chaîne (qui apparaîtra, bien évidemment, à gauche de la cellule du résultat.
Maintenant, si je rentre dans la fonction 125,298, j'obtiens bien 298, mais toujours sous forme de chaîne, et je voudrais, à ce moment là, que ce soit un chiffre (qui devrait apparaître à droite de la cellule du résultat).
J'ai essayé, sans succès, par différents moyens de régler ce problème.
VB:
Function ChiffresAfterVirgule(dNum As Double, opt As Byte)
'Renvoie le nombre de chiffres après la virgule ou tous les chiffres après la virgule
'- dNum : le chiffre à traiter
'- opt : si opt = 1 --> le nombre de chiffres après la virgule
'        si opt <> 1 --> tous les chiffres après la virgule
'Ex : 125,587349 | opt = 1 --> 6
'                  opt <> 1 --> 587349

Dim SepDec$, tmp, posDec, nb As Double, cap$

  SepDec = Application.International(xlDecimalSeparator)
  tmp = CStr(dNum)
  posDec = InStr(tmp, SepDec)
  nb = Len(tmp) - Len(Right(tmp, posDec)) 'nombre de chiffres après la virgule
  cap = Right(dNum, nb) 'chiffres après la virgule
 
'*******************************************************************************************************************
  'If Left(cap, 1) <> "0" Then cap = CDbl(cap)                'ne fait strictement rien
  'If Left(cap, 1) <> "0" Then TypeName(cap) = "Double"       'ne marche pas
'*******************************************************************************************************************
 
  ChiffresAfterVirgule = IIf(opt = 1, IIf(posDec = 0, 0, nb), IIf(posDec = 0, 0, cap))
  
End Function
 

Dranreb

XLDnaute Barbatruc
Le poste #27, que vous n'aviez pas compris non plus, @Magic_Doctor, avait pour but de rappeler que le plus souvent les nombres à décimales ne sont pas enregistrés avec une parfaite exactitude en tant que valeurs numériques de cellules. Un Double n'a pas de décimales. Il a une mantisse et un exposant de puissance de 2, c'est tout.
 

mapomme

XLDnaute Barbatruc
Supporter XLD
Bonjour à tous,

Par curiosité, j'ai comparé quelques fonctions de diverses origines.
J'ai comparé celles de Dranreb, job75, dysorthographie ,Roblochon et de mapomme.
Je n'ai pas utilisé celle de @patricktoulon car 1) c'est un mauvais payeur ;) et surtout 2) sa fonction utilise un string en entrée.

Question : je me demande à quoi tout ça peut bien servir o_O.
 

Pièces jointes

  • Magic_Doctor- Partie décimale- Compar- v1.xlsm
    31.4 KB · Affichages: 13
Dernière édition:

Magic_Doctor

XLDnaute Barbatruc
Bonjour à tous,

Je viens de voir le fichier comparatif de mapomme.
Quant à la précision, je pense que 6 décimales après la virgule, c'est largement suffisant.
De toutes les fonctions testées, la seule qui réponde à tous les critères (chiffres après la virgule | nb de chiffres après la virgule | nombre décimal à partir des chiffres après la virgule) est celle de Dranreb. Malheureusement, pour la 1er critère (chiffres après la virgule), elle me renvoie un nombre décimal, alors que ce doit être un entier ou une chaîne (ex : 24,002546 --> 002546).
Personnellement, j'ai tenté ceci, mais il y a un truc qui m'échappe et je n'y parviens pas :
VB:
Function ChiffresAfterVirgule3(dNum As Double, Optional Opt As Boolean = True, Optional NbEnt As String)

'Renvoie le nombre de chiffres après la virgule ou tous les chiffres après la virgule
'- dNum : le chiffre à traiter
'- opt : si opt = True ou omis (opt est True par défaut) --> l'INTÉGRALITÉ des chiffres après la virgule (par ex : 574225 ou 000086574)
'        si opt = False --> le nombre de chiffres après la virgule
'- NbEnt : un nombre entier qui, dans le résultat de la fonction, sera suivi d'une virgule puis des décimaux après la virgule de la variable "dNum"
'Ex : 125,587349 | opt = True (ou omis) --> 587349
'                  opt = False --> 6
'     si dNum = 2045,0657 et NbEnt = 5 --> 5,0657

Dim SepDec$, tmp$, posDec As Long, nb As Long, cap$

  SepDec = Application.International(xlDecimalSeparator)
  tmp = CStr(dNum)
  posDec = InStr(tmp, SepDec)
  nb = IIf(posDec = 0, 0, Len(tmp) - Len(Right(tmp, posDec))) 'nombre de chiffres après la virgule
  cap = Right(dNum, nb) 'chiffres après la virgule
 
'************************************************************   LES 2 FONCTIONNENT, MAIS CHAQUE FOIS AVEC 1 ERREUR   ************************************************************

  'cap = IIf(IsMissing(NbEnt), cap, NbEnt & "," & cap)
  'ou :
  'cap = IIf(Not IsMissing(NbEnt), NbEnt & "," & cap, cap) 'chiffres après virgule : Pas OK | nb de chiffres après virgule : OK | chiffre composé : OK
 
  'cap = IIf(IsMissing(NbEnt) = False, cap, NbEnt & "," & cap) 'chiffres après virgule : OK | nb de chiffres après virgule : OK | chiffre composé : Pas OK
 
  'cap = IIf(IsMissing(Opt) And Not IsMissing(NbEnt), NbEnt & "," & cap, cap) 'chiffres après virgule : OK | nb de chiffres après virgule : OK | chiffre composé : Pas OK
 
'*********************************************************************************************************************************************************************************
 
  'ChiffresAfterVirgule3 = IIf(Opt, cap, nb) 'marche mieux que la suivante, mais je ne sais pas pourquoi
 
'*************************************   CROYANT BIEN FAIRE, J'AI ÉCRIT ÇA   *************************************
 
  'ChiffresAfterVirgule3 = IIf(IsMissing(NbEnt), IIf(Not IsMissing(NbEnt), cap, nb), cap) 'ne marche pas du tout

'*****************************************************************************************************************

End Function
 

Pièces jointes

  • Magic_Doctor- Partie décimale- Compar- v1.xlsm
    28.8 KB · Affichages: 5

Dranreb

XLDnaute Barbatruc
Avec Opt:=False ou 0 ma fonction renvoie bien un entier dans un Double qui représente le nombre de décimales.
Avec Opt:=True elle renvoie l'entier spécifié en 3ème paramètre (ou assumé 0 si non spécifié) affecté de la partie fractionnaire du 1er.
N'était-ce pas ce qu'il fallait ?
 

Magic_Doctor

XLDnaute Barbatruc
La nuit portant conseil, je conserverai donc la fonction de Dranreb, même si la mienne fonctionne en fait très bien pour ce que je veux en réalité obtenir : nombre de chiffres après la virgule & composer un nombre décimal, à partir du nombre traité par la fonction. Sur un autre fil, j'ai exposé mes problèmes avec IsMissing que j'utilise dans ma fonction, et je pense avoir compris quelle en est l'origine : et oui, je suis toujours sur Excel 2007 !!! Je sais, il faut évoluer...

Donc, la question était : à quoi diable ça sert tout ça ?
En fait, récupérer, ad integrum, les chiffres après la virgule, ne me sert à rien. Donc je laisse tomber cette option.
En revanche, connaître le nombre de chiffres après la virgule, ça m'est bien utile pour, par exemple, cetains formats personnalisés. Ça fait du reste longtemps que je m'en sers.
Enfin, quel peut-être l'intérêt de récupérer les chiffres après la virgule, précédes d'une virgule, elle même précédée dun préfixe qui est un nombre entier au choix ?
Mon cher Dranreb, ne considérez pas forcément absurdes des questions que vous ne vous êtes pas posées. Et, après tout, n'est-on pas ici juste pour le fun ?
C'est après avoir rédigé une fonction, permettant de convertir des degrés décimaux en degrés sexagésimaux, que l'idée m'est venue.
La fonction est la suivante :
VB:
Function DD_DMS(cordd As Double, dms As Byte) As Double
'Convertit des coordonnées en degrés décimaux (DD) en coordonnées en degrés sexagésimaux (DMS)
'- cordd = coordonnée en degrés décimaux
'- dms = 1 ---> renvoie les degrés
'- dms = 2 ---> renvoie les minutes
'- dms = 3 ---> renvoie les secondes

Dim largo As Byte, x As Byte, zaza, cap, deg As Byte, min As Byte, sec As Double

    cordd = Abs(cordd)

    deg = Int(cordd)
      
    largo = Len(cordd) 'longueur du nombre
    x = InStr(cordd, ",") 'position de la virgule dans le nombre
    cap = Right(cordd, largo - x) 'chiffres après la virgule
    largo = Len(cap) 'longueur des chiffres après la virgule
    zaza = cap * 10 ^ -largo * 60 'calcul intermédiaire
  
    min = Int(zaza)
  
    largo = Len(zaza) 'longueur du nombre
    x = InStr(zaza, ",") 'position de la virgule dans le nombre
    cap = Right(zaza, largo - x) 'chiffres après la virgule
    largo = Len(cap) 'longueur des chiffres après la virgule
  
    sec = cap * 10 ^ -largo * 60

    DD_DMS = IIf(dms = 1, deg, IIf(dms = 2, min, sec))

End Function
Je sais, on peut trouver mieux, plus concis, plus beau, mais, peu me chaut, c'est ma fonction et elle marche !
Bon, maintenant résolvons le même problème par le biais de la fonction de Dranreb ou la mienne :
VB:
Function DD_DMS(cordd As Double, dms As Byte) As Double
'Convertit des coordonnées en degrés décimaux (DD) en coordonnées en degrés sexagésimaux (DMS)
'- cordd = coordonnée en degrés décimaux
'- dms = 1 ---> renvoie les degrés
'- dms = 2 ---> renvoie les minutes
'- dms = 3 ---> renvoie les secondes

Dim deg As Byte, min As Byte, sec As Double

    cordd = Abs(cordd)
    deg = Int(cordd)
    min = Int(ChiffresAfterVirgule(cordd, , 0) * 60)
    sec = ChiffresAfterVirgule(ChiffresAfterVirgule(cordd, , 0) * 60, , 0) * 60

    DD_DMS = IIf(dms = 1, deg, IIf(dms = 2, min, sec))

End Function
¡Caramba! C'est quand même autre chose !
Bon, maintenant est-ce d'une grande utilité ? Je ne pense pas, comme, après tout, nombre de fils sur Excel-Downloads. Mais au moins j'aurai répondu à votre question.
 
Dernière édition:

Dranreb

XLDnaute Barbatruc
Je pense que ça peut s'écrire comme ça :
VB:
Function DD_DMS(ByVal Cordd As Double, ByVal DMS As Byte) As Double
'Convertit des coordonnées en degrés décimaux (DD) en coordonnées en degrés sexagésimaux (DMS)
'- cordd = coordonnée en degrés décimaux
'- dms = 1 ---> renvoie les degrés
'- dms = 2 ---> renvoie les minutes
'- dms = 3 ---> renvoie les secondes
   Cordd = Abs(Cordd)
   Select Case DMS
      Case 1: DD_DMS = Int(Cordd)
      Case 2: DD_DMS = Int(60 * Cordd + 0.001) Mod 60
      Case 3: DD_DMS = Int(3600 * Cordd + 0.001) Mod 60
      End Select
   End Function
À vérifier

En le divisant par 24, ça peut aussi s'afficher avec un format de cellule personnalisé :
Code:
[h]° m' s\"
 
Dernière édition:

Dranreb

XLDnaute Barbatruc
Ou bien comme ça :
Code:
Function DD_DMS(ByVal Cordd As Double, ByVal DMS As Byte) As Double
'Convertit des coordonnées en degrés décimaux (DD) en coordonnées en degrés sexagésimaux (DMS)
'- cordd = coordonnée en degrés décimaux
'- dms = 1 ---> renvoie les degrés
'- dms = 2 ---> renvoie les minutes
'- dms = 3 ---> renvoie les secondes
   Cordd = Int(Abs(Cordd) * 3600 + 0.5)
   Select Case DMS
      Case 1: DD_DMS = Cordd \ 3600
      Case 2: DD_DMS = (Cordd \ 60) Mod 60
      Case 3: DD_DMS = Cordd Mod 60
      End Select
   End Function
 

Dranreb

XLDnaute Barbatruc
Alors :
VB:
Function DD_DMS(ByVal Cordd As Double, ByVal DMS As Byte) As Double
'Convertit des coordonnées en degrés décimaux (DD) en coordonnées en degrés sexagésimaux (DMS)
'- cordd = coordonnée en degrés décimaux
'- dms = 1 ---> renvoie les degrés
'- dms = 2 ---> renvoie les minutes
'- dms = 3 ---> renvoie les secondes
   Dim Deg As Long, Min As Long
   Cordd = Abs(Cordd) * 3600
   Select Case DMS
      Case 1: DD_DMS = Int(Cordd / 3600)
      Case 2: DD_DMS = Int(Cordd / 60) Mod 60
      Case 3: DD_DMS = Cordd - 60 * Int(Cordd / 60)
      End Select
   End Function
 

Dranreb

XLDnaute Barbatruc
Bonjour.
Pour moi oui, les ByVal sont obligatoires pour une procédure qui n'a pas à effectuer de modification permanente sur les arguments concernés. De plus ils éliminent complètement le risque d'erreur Type d'argument ByRef incompatible en cas de spécification d'une variable d'un type de donnée légèrement différent.
 

Discussions similaires