You are on the Home/Excel/Excel Tips/Factors and prime numbers page

Web This Site

### Factors of a number, prime numbers, and prime factors of a number

The code below supports three functions, which can be used either from other VBA code or as User Defined Functions.

The first function getFactors(NumberToFactor) returns an array containing all the factors of the argument.

The next, getPrimeFactors(NumberToFactor) returns an array containing all the prime factors of the argument.  Note that it returns each factor only once so that the prime factors of 12 are 1, 2, and 3 (and not 1, 2, 2, and 3).

The third function IsPrime(aNumber) returns True or False indicating whther the number is a prime number.

The function getFactors uses the Dictionary object that is supported by the Windows Scripting library.

The code has been tested but not exhaustively.  Exercise your discretion in using it.  The code goes in a standard VBA module.

```Option Explicit
Option Base 0
#Const EarlyBind = False
Function GetFactors(ByVal NumToFactor As Long)
'Returns all the factors of the argument NumToFactor. _
No factor is repeated and the factors are in no particular _
order.
'Usage: Select an appropriate number of cells in a single row _
and enter the formula as an array formula.  If insufficient _
cells are selected, the function returns a negative value _
indicating how many cells are actually needed. _
Hence, if one array-enters =GetFactors(12) in a range of 2 _
cells, the function will return -6 indicating it should be _
array entered in 6 cells in a row. _
To use the function in a single column use it at _
=TRANSPOSE(GetFactors(A1)), where A1 contains the number whose _
factors are desired.
```
```    'Implementation: The function uses the GetPrimeFactors to get _
all the prime factors of NumToFactor.  It then checks to see _
which of the powers of each of the prime factors greater than 1 _
is a factor of NumToFactor.  For each it finds, it returns two _
items, the power itself and the 'complement,' i.e., _
NumToFactor/Power-of-prime-factor.
```
```    'Example 1: In computing the factors of 12, the PrimeFactors _
returned are 1, 2, and 3.  Hence, the factors are calculated _
as: _
By default, the routine includes 1 and 12. _
Then, for the prime factor 2, it checks for the powers of 2 _
starting with 1.  For 2^1. it includes the factors 2 and 12/2^1 _
or 6.  It does the same for 2^2 and thus includes 4 and 3. _
The next power 2^3 is too large and the code moves on to the next _
prime factor. _
For the prime factor 3, it does the same thing as above.  3^1 and _
12/3^1 would both be included as factors except that they have _
already been included.  Since the code uses a Scripting.Dictionary _
object to store the factors, each duplicate  raises an error that _
is ignored.  Hence, the result is 1, 12, 2, 6, 4, and 3.
```
```    'Example 2: In computing the factors of 39, the PrimeFactors _
returned are 1, 3, and 13.  Hence, the factors are calculated _
as: _
By default, the routine includes 1 and 39. _
Then, for the prime factor 3, it includes the factors 3^1 and _
39/3^1 or 13.  The next power of 3, 3^2 is not a factor and is _
ignored.  The next power 27 is too large and the code moves to the _
next prime factor, which happens to be 13.  The code would have _
added 13 and 39/13 or 3 but they are already included.  Since the _
code uses a Scripting.Dictionary object to store the factors, each _
duplicate factor raises an error that is ignored.
```
```    'Example 3: For 64, the prime factors returned are 1 and 2. _
The code automatically includes the factors 1 and 64. _
Then, for the prime factor 2, it goes through the powers of 2 (2, 4, _
8, 16, and 32) and adds each of them to the list of factors since _
each divides 64 exactly, as well as their complementary values, _
i.e., 32, 16, 8, 4, and 2, again relying on the scripting _
dictionary to filter out duplicates.  Hence, the code returns the final _
result of 1, 64, 2, 32, 4, 16, and 8.
```
```    Dim PrimeFactors() As Long, I As Long, J As Long
#If EarlyBind Then
Dim Factors As Dictionary
#Else
Dim Factors As Object
#End If
If NumToFactor = 0 Then
Exit Function
ElseIf NumToFactor < 1 Then
GetFactors = "Argument must be an integer greater than zero."
Exit Function
End If
#If EarlyBind Then
Set Factors = New Dictionary
#Else
Set Factors = CreateObject("Scripting.Dictionary")
#End If
PrimeFactors = GetPrimeFactors(NumToFactor)
For I = LBound(PrimeFactors) To UBound(PrimeFactors)
If PrimeFactors(I) > 1 Then
'1st prime factor will be 1 or in the event the selected range _
isn't large enough a negative number.
J = 1
Do
Dim OneFactor As Long
On Error Resume Next
OneFactor = PrimeFactors(I) ^ J
Factors.Add CStr(NumToFactor / OneFactor), _
NumToFactor / OneFactor
On Error GoTo 0
J = J + 1
Loop Until NumToFactor <= PrimeFactors(I) ^ J _
Or NumToFactor Mod (PrimeFactors(I) ^ J) <> 0
End If
Next I
If Not TypeOf Application.Caller Is Range Then
GetFactors = Factors.Items
ElseIf Application.Caller.Cells.Count < Factors.Count Then
GetFactors = -Factors.Count
Else
GetFactors = Factors.Items
End If
End Function```
```Function GetPrimeFactors(ByVal NumToFactor As Long)
'Returns the unique prime factors of NumToFactor.  So, for _
the number 12 it returns 1, 2, and 3 and *not* 1, 2, 2, 3.
```
```    'For usage notes see the GetFactors function above.
```
```    Dim PrimeIdx As Long, PrimeFactors() As Long, _
I As Long
If NumToFactor = 0 Then
GetPrimeFactors = 0
Exit Function
ElseIf NumToFactor < 0 Then
GetPrimeFactors = "The argument must be an integer greater than zero."
Exit Function
End If
ReDim PrimeFactors(9)
PrimeFactors(0) = 1: PrimeIdx = 1
If IsPrime(NumToFactor) Then
PrimeFactors(1) = NumToFactor
ReDim Preserve PrimeFactors(1)
GetPrimeFactors = PrimeFactors
Exit Function
End If
If NumToFactor Mod 2 = 0 Then
PrimeFactors(PrimeIdx) = 2: PrimeIdx = PrimeIdx + 1
Do: NumToFactor = NumToFactor / 2: Loop Until NumToFactor Mod 2 <> 0
End If
I = 3
Do
If NumToFactor Mod I = 0 Then
If IsPrime(I) Then
PrimeFactors(PrimeIdx) = I: PrimeIdx = PrimeIdx + 1
If PrimeIdx = UBound(PrimeFactors) Then _
ReDim Preserve PrimeFactors(UBound(PrimeFactors) + 10)
Do: NumToFactor = NumToFactor / I: Loop Until NumToFactor Mod I <> 0
End If
End If
I = I + 2
Loop While NumToFactor > 1
ReDim Preserve PrimeFactors(PrimeIdx - 1)
If Not TypeOf Application.Caller Is Range Then
ElseIf Application.Caller.Cells.Count < PrimeIdx Then
PrimeFactors(0) = -PrimeIdx
End If
GetPrimeFactors = PrimeFactors
End Function
Function IsPrime(aNumber As Long) As Boolean
Dim I As Long
If aNumber = 0 Then
IsPrime = False
ElseIf aNumber < 0 Then
IsPrime = False
ElseIf aNumber = 2 Then
IsPrime = True
ElseIf aNumber Mod 2 = 0 Then
IsPrime = False
Else
IsPrime = True
For I = 3 To Fix(Sqr(aNumber) + 0.5) Step 2
If aNumber Mod I = 0 Then
IsPrime = False
Exit For
End If
Next I
End If
End Function```