-
-
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) Thenshould actually be
If ((i Mod 2) <> 0) Thenfor these functions to be correct.
Someone should fix this.