Home > Software design >  Attempting to run Luhn's Algorithm in C
Attempting to run Luhn's Algorithm in C

Time:10-19

So, I'm trying to make Luhn's algorithm in C, but it doesn't return the correct values when running it.

    //Luhn's Algorithm
    int tsum = 0;
    if (count % 2 != 0)
    {
        for (int tempcount = count; tempcount > 0; tempcount--)
        {
            if (tempcount % 2 != 0)
            {
                tsum  = (cardNum % 10);
            }
            else
            {
                tsum  = (cardNum % 10)*2;
            }
            cardNum /= 10;
        }
    }
    else
    if (count % 2 == 0)
    {
        for (int tempcount = count; tempcount > 0; tempcount--)
        {
            if (tempcount % 2 == 0)
            {
                tsum  = (cardNum % 10);
            }
            else
            {
                tsum  = (cardNum % 10)*2;
            }
            cardNum /= 10;
        }

    }
    tsum %= 10;

I have spent hours trying to troubleshoot and find the issue, count represents the number of digits in the card number, the rest define themselves.

I would appreciate somebody to tell me what I'm doing wrong, thank you.

EDIT: Apologies, cardNum is a long long. And I am expecitng a value of 0 for tsum when inputting any card number from Paypal's Standard Test Cards. I would also like to add, in my mind what this code should do is: using the checks for even and odd it will start from the rightmost digit and add it to tsum, every other digit will do the same. Then starting from the 2nd rightmost digit, the digit is multiplied by 2 then added to tsum, with every other digit doing the same. Then, the last line will check the rightmost digit of the current tsum and will tell me if the card is valid according to Luhn's Algorithm.

CodePudding user response:

Here is what I usually do if I "try to implement" something I am not sure about: I use an interactive language, such as Common Lisp, tinker and test interactively until it works. Then, I usually have some good template I can use to write it in a less powerful language such as C.

(defun luhn-method (n)
       (mod
        (loop
          for x = n then (floor x 10)
          while (> x 0)
          for double = nil then (not double)
          for digit = (mod x 10)
          for factor = (if double 2 1)
          for y = (let ((a (* digit factor)))
                    (if (> a 9) (- a 9) a))
          do (format t "~%~a" (list :x x :double double :digit digit :factor factor :y y))
          summing y)
        10))

I did this just from reading the wikipedia page about Luhn method (the german wiki page is easier to understand because it shows a simple exampple, while being less verbose than the english version). From your Paypal site, the first number produces

(luhn-method 378282246310005)

(X 378282246310005 DOUBLE NIL DIGIT 5 FACTOR 1 Y 5)
(X 37828224631000 DOUBLE T DIGIT 0 FACTOR 2 Y 0)
(X 3782822463100 DOUBLE NIL DIGIT 0 FACTOR 1 Y 0)
(X 378282246310 DOUBLE T DIGIT 0 FACTOR 2 Y 0)
(X 37828224631 DOUBLE NIL DIGIT 1 FACTOR 1 Y 1)
(X 3782822463 DOUBLE T DIGIT 3 FACTOR 2 Y 6)
(X 378282246 DOUBLE NIL DIGIT 6 FACTOR 1 Y 6)
(X 37828224 DOUBLE T DIGIT 4 FACTOR 2 Y 8)
(X 3782822 DOUBLE NIL DIGIT 2 FACTOR 1 Y 2)
(X 378282 DOUBLE T DIGIT 2 FACTOR 2 Y 4)
(X 37828 DOUBLE NIL DIGIT 8 FACTOR 1 Y 8)
(X 3782 DOUBLE T DIGIT 2 FACTOR 2 Y 4)
(X 378 DOUBLE NIL DIGIT 8 FACTOR 1 Y 8)
(X 37 DOUBLE T DIGIT 7 FACTOR 2 Y 5)
(X 3 DOUBLE NIL DIGIT 3 FACTOR 1 Y 3)
0

making it easy to see every single step of the algorithm and convincing yourself it is correct.

To port this to C, first we need to explore, if C has an integer type wide enough for those credit card numbers (lisp has large integers by default - one thing less to worry about in our prototype). Lisp again:

(log 378282246310005 2)
48.426456

So, we need a 64 bit variable and should be good. Since integers in C are implementation/platform/system specific, we should use some header file, giving us the correct type:

#include <stdint.h>

In there, the 64 bit unsigned integer is defined as uint64_t and if your compiler and your header files are correct for your system, using that makes sure, you do not get it wrong. The native "unsigned long long" etc. are just guesswork and not portable.

With that in place, we can simply port the code above to C:

uint64_t luhn(uint64_t n) {
  uint64_t x = n;
  uint64_t sum = 0;
  uint64_t factor = 1;
  while (x > 0) { 
    uint64_t y = (x % 10) * factor;
    if (y > 9) 
      y = y - 9;
    sum  = y;
    x = x / 10;
    if (1 == factor) {
      factor = 2;
    } else {
      factor = 1;
    } 
  } 
  return sum % 10;
}

Summary: A proper tool set helps getting stuff done. If you don't know yet, how to use a C debugger and step through code line by line while watching the content of variables, an interactive programming language is probably easier for you for prototyping.

CodePudding user response:

Thank you for your help, I was able to solve this issue as it seems I had missed a step in Luhn's Algorithm.

    //Luhn's Algorithm
    int tsum = 0;
    int luhn;
    if (count % 2 != 0)
    {
        for (int tempcount = count; tempcount > 0; tempcount--)
        {
            if (tempcount % 2 != 0)
            {
                luhn = (cardNum % 10);
                tsum  = luhn;
            }
            else
            {
                luhn = (cardNum % 10) * 2;
                if (luhn > 9)
                {
                    tsum  = (luhn - 9);
                }
                else
                {
                    tsum  = luhn;
                }
            }
            cardNum /= 10;
        }
    }
    else if (count % 2 == 0)
    {
        for (int tempcount = count; tempcount > 0; tempcount--)
        {
            if (tempcount % 2 == 0)
            {
                luhn = (cardNum % 10);
                tsum  = luhn;
            }
            else
            {
                luhn = (cardNum % 10) * 2;
                if (luhn > 9)
                {
                    tsum  = (luhn - 9);
                }
                else
                {
                    tsum  = luhn;
                }
            }
            cardNum /= 10;
        }

    }
    tsum %= 10;

Here, I defined luhn as the next integer to be added to the tsum, in doing this I was able to fill in the missing step by subtracting 9 before adding to tsum if luhn exceeded 9.

  • Related