How to resolve the algorithm Luhn test of credit card numbers step by step in the C++ programming language

Published on 7 June 2024 03:52 AM

How to resolve the algorithm Luhn test of credit card numbers step by step in the C++ programming language

Table of Contents

Problem Statement

The Luhn test is used by some credit card companies to distinguish valid credit card numbers from what could be a random selection of digits. Those companies using credit card numbers that can be validated by the Luhn test have numbers that pass the following test:

For example, if the trial number is 49927398716:

Write a function/method/procedure/subroutine that will validate a number with the Luhn test, and use it to validate the following numbers:

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Luhn test of credit card numbers step by step in the C++ programming language

Code Overview

The provided code in C++ demonstrates various implementations of the Luhn algorithm, which is commonly used to validate identification numbers such as credit card numbers. Different techniques and syntax are employed in each implementation, showcasing the flexibility and expressiveness of the C++ programming language.

Implementation 1: Procedural Approach

int toInt(const char c)
{
   return c-'0';
}

int confirm( const char *id)
{
   bool is_odd_dgt = true;
   int s = 0;
   const char *cp;

   for(cp=id; *cp; cp++);
   while(cp > id) {
       --cp;
       int k = toInt(*cp);
       if (is_odd_dgt) {
           s += k;
       }
       else {
           s += (k!=9)? (2*k)%9 : 9;
       }
   is_odd_dgt = !is_odd_dgt;
   }
   return 0 == s%10;
}
  • toInt function: Converts a numerical character to an integer.
  • confirm function: Performs the Luhn algorithm's validation based on the supplied identification number id.

Implementation 2: Using Lambda and STL

bool luhn( const string& id)
{
 static const int m[10]  = {0,2,4,6,8,1,3,5,7,9}; // mapping for rule 3
 bool is_odd_dgt = false;
 auto lambda = [&](int a, char c) {return a + ((is_odd_dgt = !is_odd_dgt) ? c-'0' : m[c-'0']);};
 int s = std::accumulate(id.rbegin(), id.rend(), 0, lambda);
 return 0 == s%10;
}

This implementation leverages the Standard Template Library (STL) and lambda expressions:

  • m array: Contains the mapping for rule 3 of the Luhn algorithm.
  • luhn function: Performs the validation using STL's std::accumulate function and lambda expression to calculate the sum of transformed digits.

Implementation 3: Metaprogramming Approach

template<size_t I>
using rule3 = typename find_impl<I, 0, 2, 4, 6, 8, 1, 3, 5, 7, 9>::type;

// implementation of luhn and operator ""_luhn omitted for brevity

This advanced implementation employs metaprogramming techniques to implement the Luhn algorithm:

  • rule3 metafunction: Computes the value of the Luhn algorithm's rule 3 for a given index I.
  • luhn metafunction: Calculates the checksum and determines the validity of the identification number.
  • **operator ""_luhn: Overloads the user-defined literal operator to create a custom literal syntax for luhn validation.

Usage and Output

The code includes test cases and prints the results of the Luhn validation for each case. The output will resemble the following:

49927398716: true
49927398717: false
1234567812345678: true
1234567812345670: false

Source code in the cpp programming language

#include <iostream>
using namespace std;

int toInt(const char c)
{
    return c-'0';
}

int confirm( const char *id)
{
    bool is_odd_dgt = true;
    int s = 0;
    const char *cp;

    for(cp=id; *cp; cp++);
    while(cp > id) {
        --cp;
        int k = toInt(*cp);
        if (is_odd_dgt) {
            s += k;
        }
        else {
            s += (k!=9)? (2*k)%9 : 9;
        }
	is_odd_dgt = !is_odd_dgt;
    }
    return 0 == s%10;
}

int main( )
{
    const char * t_cases[] = {
        "49927398716",
        "49927398717",
        "1234567812345678",
        "1234567812345670",
        NULL,
    };
    for ( const char **cp = t_cases; *cp; cp++) {
        cout << *cp << ": " << confirm(*cp) << endl;
    }
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

bool luhn( const string& id)
{
  static const int m[10]  = {0,2,4,6,8,1,3,5,7,9}; // mapping for rule 3
  bool is_odd_dgt = false;
  auto lambda = [&](int a, char c) {return a + ((is_odd_dgt = !is_odd_dgt) ? c-'0' : m[c-'0']);};
  int s = std::accumulate(id.rbegin(), id.rend(), 0, lambda);
  return 0 == s%10;
}

int main( )
{
  auto t_cases = {"49927398716", "49927398717", "1234567812345678", "1234567812345670"};
  auto print = [](const string & s) {cout << s << ": " << luhn(s) << endl;};
  for_each(t_cases.begin(), t_cases.end(), print);
  return 0;
}


#include <iostream>
#include <type_traits>

template<size_t I, int... Args>
struct find_impl;

template<int A, int... Args>
struct find_impl<0, A, Args...> {
    using type = std::integral_constant<int, A>;
};

template<int A, int B, int... Args>
struct find_impl<0, A, B, Args...> {
    using type = std::integral_constant<int, A>;
};

template<size_t I, int A, int B, int... Args>
struct find_impl<I, A, B, Args...> {
    using type = typename find_impl<I-1, B, Args...>::type;
};

namespace detail {
template<typename, typename>
struct append_sequence
{};

template<typename T, typename... Ts>
struct append_sequence<T, std::tuple<Ts...>> {
    using type = std::tuple<Ts..., T>;
};

template<typename... Ts>
struct reverse_sequence {
    using type = std::tuple<>;
};

template<typename T, typename... Ts>
struct reverse_sequence<T, Ts...> {
    using type = typename append_sequence<
                            T,
                            typename reverse_sequence<Ts...>::type
                        >::type;
};
}

template<size_t I>
using rule3 = typename find_impl<I, 0, 2, 4, 6, 8, 1, 3, 5, 7, 9>::type;

template<int A, char C, bool dgt>
struct calc
    : std::integral_constant<int, A + C - '0'>
{};

template<int A, char C>
struct calc<A, C, false>
    : std::integral_constant<int, A + rule3<C - '0'>::type::value>
{};

template<typename Acc, bool Dgt, char...>
struct luhn_impl;

template<typename Acc, bool Dgt, char A, char... Args>
struct luhn_impl<Acc, Dgt, A, Args...> {
    using type = typename calc<Acc::value, A, Dgt>::type;
};

template<typename Acc, bool Dgt, char A, char B, char... Args>
struct luhn_impl<Acc, Dgt, A, B, Args...> {
    using type =
        typename luhn_impl<typename calc<Acc::value, A, Dgt>::type, !Dgt, B, Args...>::type;
};

template<typename>
struct luhn;

template<typename... Args>
struct luhn<std::tuple<Args...>> {
    using type = typename luhn_impl<std::integral_constant<int, 0>, true, Args::value...>::type;
    constexpr static bool result = (type::value % 10) == 0;
};

template<char... Args>
bool operator "" _luhn() {
    return luhn<typename detail::reverse_sequence<std::integral_constant<char, Args>...>::type>::result;
}

int main() {
    std::cout << std::boolalpha;
    std::cout << 49927398716_luhn << std::endl;
    std::cout << 49927398717_luhn << std::endl;
    std::cout << 1234567812345678_luhn << std::endl;
    std::cout << 1234567812345670_luhn << std::endl;
    return 0;
}


  

You may also check:How to resolve the algorithm Sorting algorithms/Permutation sort step by step in the ActionScript programming language
You may also check:How to resolve the algorithm Sutherland-Hodgman polygon clipping step by step in the C# programming language
You may also check:How to resolve the algorithm Babbage problem step by step in the AWK programming language
You may also check:How to resolve the algorithm Shortest common supersequence step by step in the Phix programming language
You may also check:How to resolve the algorithm Loops/Do-while step by step in the Fantom programming language