-
-
Save cimnine/7913819 to your computer and use it in GitHub Desktop.
' Version 1.0.0 | |
' You may use these functions directly in Excel: "=luhnCheck(A55)" | |
' probably only needed internally | |
Function luhnSum(InVal As String) As Integer | |
Dim evenSum As Integer | |
Dim oddSum As Integer | |
evenSum = 0 | |
oddSum = 0 | |
Dim strLen As Integer | |
strLen = Len(InVal) | |
Dim i As Integer | |
For i = strLen To 1 Step -1 | |
Dim digit As Integer | |
digit = CInt(Mid(InVal, i, 1)) | |
If ((i Mod 2) = 0) Then | |
oddSum = oddSum + digit | |
Else | |
digit = digit * 2 | |
If (digit > 9) Then | |
digit = digit - 9 | |
End If | |
evenSum = evenSum + digit | |
End If | |
Next i | |
luhnSum = (oddSum + evenSum) | |
End Function | |
' for the curious | |
Function luhnCheckSum(InVal As String) | |
luhnCheckSum = luhnSum(InVal) Mod 10 | |
End Function | |
' true/false check | |
Function luhnCheck(InVal As String) | |
luhnCheck = (luhnSum(InVal) Mod 10) = 0 | |
End Function | |
' returns a number which, appended to the InVal, turns the composed number into a valid luhn number | |
Function luhnNext(InVal As String) | |
Dim luhnCheckSumRes | |
luhnCheckSumRes = luhnCheckSum(InVal) | |
If (luhnCheckSumRes = 0) Then | |
luhnNext = 0 | |
Else | |
luhnNext = ((10 - luhnCheckSumRes)) | |
End If | |
End Function |
Glahens is right. I had a similar issue and the above suggestion resolved it. Thanks.
It works for me for ICCID validation, maybe there're varies here.
There are a few problems with this implementation, though If ((i Mod 2) = 0) Then
is not necessarily wrong.
First, when calculating the sum, we use i
going from length down to 1. This means the first position is considered odd or even based on the length of InVal
. First position should always be 1, odd.
(This would explain why If ((i Mod 2) <> 0) Then
may yield correct result for some, it depends on the length of your numbers)
My solution:
For i = 0 To strLen - 1 Step 1
Dim digit As Integer
digit = CInt(Mid(InVal, strLen - i, 1))
If ((i Mod 2) = 0) Then
is unchanged, as we start at pos 1 when i = 0.
Also when calculating the next value, first position is considered to be held by the value you are trying to calculate.
Ie, if you want to calculate the check value x of 123456, then you need to think of the number as 123456x where x is position 1.
The code does not take this in to account.
Changing luhnCheckSumRes = luhnCheckSum(InVal)
to luhnCheckSumRes = luhnCheckSum(InVal*10)
in Function luhnNext(InVal As String)
seems to work.
Hello,
Using Excel 2016, Getting #VALUE! with Function luhnNext(InVal As String)
,
after I change the code to luhnCheckSumRes = luhnCheckSum(InVal*10)
(suggested by Voidfae) and result of InVal*10
has more than 15 digits
I'm new to Excel & VBA & programming but a google search shows me that's because of floating point?
After a few try, since Function luhnNext(InVal As String)
is As String,
instead of change the line to luhnCheckSumRes = luhnCheckSum(InVal*10)
,
I'm keeping it untouched, but add a new InVal = InVal + "0"
line above that, seems working now.
Is this the right way to do it?
The doubling is alternating, so why not just use a flag to alternate. This way it doesn't matter if the length of InVal is even or odd
Dim i As Integer
Dim ToDouble As Boolean
For i = strLen To 1 Step -1
Dim digit As Integer
digit = CInt(Mid(InVal, i, 1))
ToDouble = Not ToDouble
If Not ToDouble Then
oddSum = oddSum + digit
Else
digit = digit * 2
Small bug in this algorithm.. That's why it's not matching what you see at planetcalc.
The line
If ((i Mod 2) = 0) Then
should actually be
If ((i Mod 2) <> 0) Then
for these functions to be correct.
Someone should fix this.