skip to Main Content

I’m currently implementing a Luhn algorithm on javascript:

const validateCred = arr => {
  let sum = 0, cardNum = [...arr]
  const lastCardNum = cardNum.pop()
  cardNum.reverse()

  cardNum.forEach((element, index)=> index % 2 === 0 ? sum+=element: element*2 > 9 ? sum+=element*2-9: sum+=element*2)
  
  return sum % 10 === lastCardNum ? true: false
}

The Luhn Formula:

  • Drop the last digit from the number. The last digit is what we want to check against
    Reverse the numbers
  • Multiply the digits in odd positions (1, 3, 5, etc.) by 2 and subtract 9 to all any result higher than 9
  • Add all the numbers together
  • The check digit (the last number of the card) is the amount that you would need to add to get a multiple of 10 (Modulo 10)

I’m trying to test the following code but it returns true instead of false:

const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8]; // actually a valid card number
console.log(validateCred(valid1)) // returns false :/

For some reason the sum of all numbers is 66 and obviously the modulo 10 of it is 6 and not 8

edit: Well I just modified the function to the way I know

  const validateCred = arr => {
  let sum = 0, cardNum = [...arr]

  cardNum.forEach((element, index)=> index % 2 !== 0 ? sum+=element: element*2 > 9 ? sum+=element*2-9: sum+=element*2)

  return sum % 10 === 0 ? true: false
}

I would appreciate if someone explains why have you to reverse the array? (For me is useless)

2

Answers


  1. your algorithm is wrong, you need to test (10 - sum) === lastCardNum (see wikipedia)
    I also think your sum calculation is wrong…

    I made a new one, according to Wikipedia !

    https://en.wikipedia.org/wiki/Luhn_algorithm

    PS: testing v<5 means (v *2) < 10

    console.log(validateCred('17893729974'));      // true -> wikipedia  testing
    console.log(validateCred('4539677908016808')); // false -> your test value
    console.log(validateCred('4539677908016804')); // true  (key should be 4, not 8)
    
    function validateCred(str)
      {
      let 
        cardNum = [...str].map(Number) 
      , key     = cardNum.pop()
      , sum     = cardNum.reduce((s,v,i) => s + (!(i%2) ? v : v<5 ? v*2 : (v*2 -9)), 0)
        ;
      return key === (10 - (sum % 10))
      }

    But according to rosettacode.org on "Luhn test of credit card numbers"

    I made this one, whose accept your card code values :

    const Luhn_Rosetta = str =>
      !([...str].map(Number).reverse().reduce((s,v,i)=>s+(!(i%2)?v:v<5?v*2:(v*2 -9)),0) %10);
    
    console.log( Luhn_Rosetta('4539677908016808'));  // your test value
    console.log( Luhn_Rosetta('49927398716') );      // rosettacode test value
    console.log( Luhn_Rosetta('17893729974'));       // wikipedia test value!! 
    Login or Signup to reply.
  2. I would appreciate if someone explains why have you to reverse the array? (For me is useless)

    Step 2 of Wikipedia’s description

    1. With the payload, start from the rightmost digit. Moving left, double the value of every second digit (including the rightmost digit).

    While we could do using a combination of array length and current index to determine whether or not to double a number, it’s easier to read and write by reversing and using index % 2 === 0.

    The reason you’re not seeing a difference whether you reverse or not is that you are testing with an even number of digits, as modern credit cards have. If there were an odd number and you didn’t reverse, you would be doubling the wrong digits. I have no idea if 16-digit CC numbers was the norm when the algorithm was created. But the algorithm is designed for an arbitrary number of digits.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search