2017-07-08 3 views
0

MISE À JOUR Je nettoie ce post après sa résolution. Pour résumer, je faisais une formule définie par l'utilisateur pour Excel qui a calculé le nombre premier le plus élevé suivant (=NextHighestPrimeNumber(100) renvoie 101). Comme je commence à expérimenter, j'ai remarqué que la formule serait erreur sur environ 2,1 milliards. J'ai supposé qu'il pourrait avoir été connecté à ma variable alors j'ai essayé DOUBLE, mais j'ai toujours reçu des erreurs.Fonction MOD utilise exclusivement des variables longues dans Excel VBA

Voici la fonction:

Function NextHighestPrimeNumber(StartingNumber As Double) As Variant 
Dim CeilingTest As Long 
Dim i As Long 

If StartingNumber < 11 Then 
      If StartingNumber > 6 Then 
       NextHighestPrimeNumber = 11 

      ElseIf StartingNumber > 4 Then 
       NextHighestPrimeNumber = 7 

      ElseIf StartingNumber > 2 Then 
       NextHighestPrimeNumber = 5 

      ElseIf StartingNumber > 0 Then 
       NextHighestPrimeNumber = 3 

      ElseIf StartingNumber = 0 Then 
       NextHighestPrimeNumber = 1 

      Else 
       NextHighestPrimeNumber = "Pick A Positive Integer" 

      End If 

     Exit Function 

Else 

    'Create Array 
    ReDim Prime_Array(0 To 4) As Double 
    GoTo StartArrayPopulate 
DoneWithStartingArray: 

    If StartingNumber Mod 2 = 0 Then 
     StartingNumber = StartingNumber - 1 
    End If 

NewNumber: 
     StartingNumber = StartingNumber + 2 
     CeilingTest = Int(VBA.Sqr(StartingNumber)) 


    'Array loop 
    For i = LBound(Prime_Array) To UBound(Prime_Array) 
     If Prime_Array(i) > CeilingTest Then 
      NextHighestPrimeNumber = StartingNumber 
      Exit Function 
     ElseIf StartingNumber Mod Prime_Array(i) = 0 Then GoTo NewNumber 

     End If 
    Next i 


    'Add new Array Value 
ExpandDim: 
    ReDim Preserve Prime_Array(UBound(Prime_Array) + 1) 
    Prime_Array(UBound(Prime_Array)) = NextHighestPrimeNumber(Prime_Array(UBound(Prime_Array) - 1)) 

    'test if bigger than cieling 
    If Prime_Array(UBound(Prime_Array)) > CeilingTest Then 
     NextHighestPrimeNumber = StartingNumber 
     Exit Function 

    ElseIf StartingNumber Mod Prime_Array(UBound(Prime_Array)) = 0 Then GoTo NewNumber 


    Else 
     GoTo ExpandDim 
    End If 

End If 


Exit Function 

StartArrayPopulate: 


Prime_Array(0) = 3 
Prime_Array(1) = 5 
Prime_Array(2) = 7 
Prime_Array(3) = 11 
Prime_Array(4) = 13 


GoTo DoneWithStartingArray 

End Function 
+2

* "variable LONG qui devrait avoir une portée de 9.223.372.036.854.775.807" * C'est en ** VB.net ** ** pas ** VBA. Dans ce dernier type 'long' est de 4 octets. –

+1

"Les longueurs sont de 4 octets (32 bits) allant de -2 147 483 648 à 2 147 483 647. Où avez-vous trouvé cette définition dans MSDN?" [Chip Pearson] (https://www.pcreview.co.uk/threads/vba-long-data-type-overflow.959041/) – pnuts

+2

Apparemment, vous avez consulté la référence VB.NET. Consultez la référence [VBA] (https://msdn.microsoft.com/en-us/library/aa263420 (VS.60) .aspx) à la place. – GSerg

Répondre

1

La question est parce que la fonction MOD VBA TOUJOURS convertit le numérateur à une variable LONG, même si elle est déjà définie comme Double ou est un numéro codé dur!

Testez-vous:

MsgBox (2147483647) mod 3 'Maximum Long Value

Vs.

MsgBox (2147483647 + 1) mod 3'Oh False!

J'utilise la fonction INT pour dupliquer le calcul mod Numerator -(INT(Numerator /Denominator)*Denominator) mais il y a beaucoup d'autres façons créatives d'éviter. Même Evaluate avec la fonction MOD Excel a fonctionné correctement.

Bottomline: Je ne vais jamais utiliser MOD pour tous les calculs qui pourraient être dépassant les 2 milliards

J'ai nettoyé mon code de manière significative depuis mon premier post et à gauche les mauvaises lignes a commenté que lançaient des erreurs signalées par `zz Code a échoué:

Function NextHighestPrimeNumber(StartingNumber As Double) As Variant 
Dim CeilingTest As Long 
Dim i As Long 


If StartingNumber < 11 Then 
      If StartingNumber > 6 Then 
       NextHighestPrimeNumber = 11 

      ElseIf StartingNumber > 4 Then 
       NextHighestPrimeNumber = 7 

      ElseIf StartingNumber > 2 Then 
       NextHighestPrimeNumber = 5 

      ElseIf StartingNumber > 0 Then 
       NextHighestPrimeNumber = 3 

      ElseIf StartingNumber = 0 Then 
       NextHighestPrimeNumber = 1 

      Else 
       NextHighestPrimeNumber = "Pick A Positive Integer" 

      End If 

     Exit Function 

Else 

    'Create Array 
    ReDim Prime_Array(0 To 4) As Double 
    GoTo StartArrayPopulate 
DoneWithStartingArray: 

    'zz failed code: If StartingNumber Mod 2 = 0 Then 
    If StartingNumber - (Int(StartingNumber/2) * 2) = 0 Then 
     StartingNumber = StartingNumber - 1 
    End If 

NewNumber: 
     StartingNumber = StartingNumber + 2 
     CeilingTest = INT(VBA.Sqr(StartingNumber)) 


    'Array loop 
    For i = LBound(Prime_Array) To UBound(Prime_Array) 
     If Prime_Array(i) > CeilingTest Then 
      NextHighestPrimeNumber = StartingNumber 
      Exit Function 
     'zz failed code: ElseIf StartingNumber Mod Prime_Array(i) = 0 Then 
GoTo NewNumber 
     ElseIf StartingNumber - (Int(StartingNumber/Prime_Array(i)) * Prime_Array(i)) = 0 Then GoTo NewNumber 
     End If 
    Next i 


    'Add new Array Value 
ExpandDim: 
    ReDim Preserve Prime_Array(UBound(Prime_Array) + 1) 
    Prime_Array(UBound(Prime_Array)) = NextHighestPrimeNumber(Prime_Array(UBound(Prime_Array) - 1)) 

    'test if bigger than ceiling 
    If Prime_Array(UBound(Prime_Array)) > CeilingTest Then 
     NextHighestPrimeNumber = StartingNumber 
     Exit Function 

    'zz failed code: ElseIf StartingNumber Mod Prime_Array(UBound(Prime_Array)) = 0 Then GoTo NewNumber 
    ElseIf StartingNumber - (Int(StartingNumber/Prime_Array(UBound(Prime_Array))) * Prime_Array(UBound(Prime_Array))) = 0 Then GoTo NewNumber 

    Else 
     GoTo ExpandDim 
    End If 

End If 


Exit Function 

StartArrayPopulate: 
Prime_Array(0) = 3 
Prime_Array(1) = 5 
Prime_Array(2) = 7 
Prime_Array(3) = 11 
Prime_Array(4) = 13 

GoTo DoneWithStartingArray 

End Function 
+1

Pour VBA7-64 cela montrera * 1 *: 'Dim i comme LongLong: i = 9123372036854775807: MsgBox i Mod 3' - [Résumé type de données - MSDN VBA] (https://msdn.microsoft.com/fr-fr/vba/language-reference-vba/articles/résumé du type de données) –