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
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.
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 .
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
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 ?
Ce sera bien tard alors pour constater qu'on n'en aura pas besoin pour ça !
Édition: Mais à la réflexion, ce que je crains c'est que ce que vous voulez en faire soit encore bien plus absurde que ça !
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.
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é :
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
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
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.