XL pour MAC Durée : Dépassement de capacité.

dionys0s

XLDnaute Impliqué
Bonjour le forum,

je ne comprends rien : j'ai développé une petite fonction qui renvoie une valeur texte d'un nombre de secondes.
1 => 1 seconde
1.01 => 1 seconde 1 centième
3602.12 => 1 heure 2 secondes 12 centièmes.

Je ne comprends pas pourquoi au delà d'une certaine valeur (248 jours 13 heures 13 minutes 56 secondes 47 centièmes, soit 2 147 483 647 centièmes de secondes.), j'ai un dépassements de capacité. J'ai l'impression d'avoir déclaré mes variables correctement pourtant.

Ci-dessous le code de mes procédures, et joint le classeur qui contient la fonction. En l'état, ça fonctionne, mais en rajoutant 1 centième à la durée (56.47 => 56.48), ça plante chez moi.

C'est pareil chez vous ? Si oui, une idée du pourquoi du comment ?
D'avance merci pour votre aide :)

VB:
Option Explicit

Public Enum eSingPlur: eSing: ePlur: End Enum

Public Sub Test1()

  Dim Dur As Double

  Const SecPerCnt As Double = 0.01
  Const SecPerSec As Double = 1
  Const SecPerMin As Double = 60
  Const SecPerHour As Double = 60 * SecPerMin
  Const SecPerDay As Double = 24 * SecPerHour

  Dur = _
  Cells(2, 2).Value * SecPerDay + _
  Cells(2, 3).Value * SecPerHour + _
  Cells(2, 4).Value * SecPerMin + _
  Cells(2, 5).Value * SecPerSec + _
  Cells(2, 6).Value * SecPerCnt

  MsgBox Duration(Dur)

End Sub

Public Sub Test2()

  Dim Dur As Double

  Const SecPerCnt As Double = 0.01
  Const SecPerSec As Double = 1
  Const SecPerMin As Double = 60
  Const SecPerHour As Double = 60 * SecPerMin
  Const SecPerDay As Double = 24 * SecPerHour

  Dur = _
  Cells(3, 2).Value * SecPerDay + _
  Cells(3, 3).Value * SecPerHour + _
  Cells(3, 4).Value * SecPerMin + _
  Cells(3, 5).Value * SecPerSec + _
  Cells(3, 6).Value * SecPerCnt

  MsgBox Duration(Dur)

End Sub

Public Function Duration(Seconds As Double) As String

  Dim Unts() As Variant, Lvls() As Double, Elt As Variant
  Dim Div As Double, Arr() As Double, k As Long

  Unts = VBA.Array( _
  VBA.Array("centième", "centièmes"), _
  VBA.Array("seconde", "secondes"), _
  VBA.Array("minute", "minutes"), _
  VBA.Array("heure", "heures"), _
  VBA.Array("jour", "jours"), _
  VBA.Array("année", "années"))

  ReDim Lvls(LBound(Unts) To UBound(Unts) - 1): k = LBound(Lvls): For Each Elt In VBA.Array(100, 60, 60, 24, 365)
  Lvls(k) = Elt: k = k + 1: Next Elt: Seconds = 100 * Seconds: Div = 1

  ReDim Arr(LBound(Unts) To UBound(Unts)): k = LBound(Arr) - 1: Do: k = k + 1
  If k > LBound(Lvls) Then Div = Div * Lvls(k - 1)
  If Div > Seconds Then Exit Do
  If k < UBound(Lvls) Then Arr(k) = Seconds \ Div Mod Lvls(k) Else Arr(k) = Seconds \ Div
  Loop Until k = UBound(Unts)

  k = k + 1: Do: k = k - 1
  If Arr(k) > 0 Then
  Duration = Duration & " " & Arr(k) & " " & SingPlur(Arr(k), Unts(k)(eSingPlur.eSing) & "", Unts(k)(eSingPlur.ePlur) & "")
  ElseIf k = LBound(Arr) And Duration = "" Then
  Duration = "<1 " & SingPlur(Arr(k), Unts(eSingPlur.eSing, k) & "", Unts(eSingPlur.ePlur, k) & "")
  End If: Loop Until k = LBound(Unts): Duration = VBA.Trim(Duration) & "."

End Function

Public Function SingPlur(Value As Variant, Sing As String, Plur As String) As String
  If VBA.Abs(Value) >= 2 Then SingPlur = Plur Else SingPlur = Sing
End Function
 

Pièces jointes

  • Capacite.xlsm
    55.1 KB · Affichages: 50
Dernière édition:

dionys0s

XLDnaute Impliqué
Re,
Bonjour P.

J'aurais dû être plus précis. Tel que le classeur exemple était initialement, il était normal qu'il fonctionne. Il fallait modifier le code.
J'ai modifié la pièce jointe : la macro Test1 fonctionne, mais pas la Test2.

À vous lire,

dionys0s
 

dionys0s

XLDnaute Impliqué
Re,
Bonjour tout le monde,

j'avance un peu dans mon "investigation"... Je viens de voir que ce sont les opérateurs Mod et "\" (division entière) qui font planter.
Reste à savoir pourquoi et comment contourner ça. Je continue de creuser mais si quelqu'un a déjà un début de solution je suis preneur :)
 

Dranreb

XLDnaute Barbatruc
Bonjour.
Faite des divisions normales pour éviter la conversion en Long des opérandes en amont de la division.
Quotient = Int(Ddende / Diviseur): Reste = Ddende - Quotient * Diviseur
Peut être pourrez vous adapter cette fonction :
VB:
Function DuréeEnClair(ByVal D As Double) As String
Dim Z As String, M As Double, U As String, N As Long, NDét As Long
Z = ""
M = 365.2425:  U = "an":   GoSub 2
M = 30.436875: U = "mois": GoSub 2
M = 7:         U = "sem":  GoSub 2
M = 1:         U = "j.":   GoSub 2
M = 1 / 24:    U = "h.":   GoSub 2
M = 1 / 1440:  U = "min":  GoSub 2
1 DuréeEnClair = Mid$(Z, 2)
Exit Function
2 N = Int(D / M)
If N > 0 Then
   If N > 1 Then If U = "an" Then U = "ans"
   Z = Z & " " & N & " " & U
   D = D - M * N
   End If
If Len(Z) > 0 Then NDét = NDét + 1: If NDét >= 2 Then GoTo 1
Return
End Function
 
Dernière édition:

Paf

XLDnaute Barbatruc
Bonjour dionys0s, gosselien, Dranreb,

Dans la première ligne du classeur on obtient un nombre de secondes : 2147483647, dans la deuxième :2147483648.

2147483647 est la limite d'un Long, est ce dû à ça ?

Si dans une sub on essaie d'écrire 2147483648 on obtient 2147483648#

La division entière pose alors souci : 2147483648 \ 1 ==> dépassement de capacité

peut-être contourner la division entière en utilisant la fonction Int().

Code:
Dim Seconds As Double
Seconds = 2147483648#
Seconds = 2147483647
Seconds = Seconds + 1

MsgBox Seconds
MsgBox Int(Seconds / 1) 'ok
MsgBox Seconds \ 1 ' dépassement capacité

A+
 

Discussions similaires

Réponses
23
Affichages
1 K
Réponses
6
Affichages
294

Statistiques des forums

Discussions
312 108
Messages
2 085 366
Membres
102 874
dernier inscrit
Petro2611