Search This Blog

Title of the confirm dialog

Description of what is about to happen

Luhn Algorithm


Known as the "modulus 10" or "mod 10" algorithm, is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers, IMEI numbers, National Provider Identifier numbers in the US, and Canadian Social Insurance
Numbers. It was created by IBM scientist Hans Peter Luhn and described in U.S. Patent No. 2,950,048, filed on January 6, 1954, and granted on August 23, 1960.

(ref https://en.wikipedia.org/wiki/Luhn_algorithm)


Source Code

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105 
106
107
108 
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; // .Net Framework 4.0


namespace TechScales
{
    internal static class Luhn
    {
        /// <summary>
        /// Luhn Algoritm.
        /// </summary>
        /// <param name="numbers">numbers to check</param> 
        internal static bool IsValid(string numbers)
        {
            int len = numbers.Length;
            int dgt = 0, sum = 0;
            int pos = 0; //the current process number (to calc odd/even proc)
            for (int i = len - 1; i >= 0; i--)
            {
                //digit on right most
                string rgt = numbers.Substring(i, 1);
                //parse 
                if (!int.TryParse(rgt, out dgt)) { return false; }
                //double value of every 2nd right most
                //if value = 2digits, sum the digits by substract by 9
                if (pos % 2 != 0) { if ((dgt *= 2) > 9) { dgt -= 9; } }
                //increase the proc number
                pos++;
                //summarize the processed digits
                sum += dgt;
            }
            //if sum is divisible by 10, return valid, else notValid
            return (sum % 10 == 0);
        }

        /// <summary>
        /// Luhn Algoritm.
        /// </summary>
        /// <param name="sidNum">numbers to check</param> 
        internal static bool IsValidA(string numbers)
        {
            int sum = 0, pos = 0;
            // select numeric only
            // reverse collection, need to sumarize from right most
            var num = numbers.Where(c => "0123456789".Contains(c)).Reverse();
            foreach(var n in num)
            {
                // multiply by 2 of every even digit value.
                // if digit value > 9, substract it by 9.
                // perform addition  
                var i = n - 48;
                sum += pos % 2 != 0 ? ((i *= 2) > 9 ? (i - 9) : i) : i;
                // next digit
                pos++;
            };
            return sum % 10 == 0;
        }

        /// <summary>
        /// extension: verify string by Luhn algorithm
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        internal static bool IsLuhnVerified(this string arg)
        {
            return !string.IsNullOrWhiteSpace(arg) ? IsValidA(arg) : false;
        }

        /// <summary>
        /// extension: verify numbers by Luhn algorithm
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        internal static bool IsLuhnVerified(this long arg)
        {
            return
                !string.IsNullOrWhiteSpace(arg.ToString()) ?
                IsValidA(arg.ToString()) : false;
        }

        /// <summary>
        /// get valid check digit of complete string numbers
        /// using Luhn algorithm<para></para>
        /// string cannot be empty/null value
        /// </summary>
        /// <param name="arg"></param>
        /// <param name="numOnly">get number only</param>
        /// <returns></returns>
        internal static int ValidCheckDigit(string arg, bool numOnly = false)
        {
            int sum = 0, pos = 0;
            var num = (!numOnly ? 
                      arg : 
                      arg.Where(c => "0123456789".Contains(c)))
                      .Reverse();
            foreach (var n in num)
            {
                var i = n - 48;
                sum += pos % 2 == 0 ? ((i *= 2) > 9 ? (i - 9) : i) : i;
                pos++;
            }
            return ((int)Math.Ceiling(sum / 10d) * 10) - sum;
        }
    }
}


Test

Immediate Window
?Luhn.IsValidA("4987 6532 1012 3456")
 true
?NPWP.ValidCheckCode("12345678")
 2

var yes = Luhn.IsValidA("4987 6532 1012 3456"); // return true var dgt = Luhn.ValidCheckDigit("4987 6532 1012 345"); // return 6


TOP