Shop OBEX P1 Docs P2 Docs Learn Events
Has anyone worked with the LUHN algorithm? — Parallax Forums

Has anyone worked with the LUHN algorithm?

Don MDon M Posts: 1,652
edited 2014-02-27 00:23 in Propeller 1
Here's a link for a description- http://en.wikipedia.org/wiki/Luhn_algorithm

Looking to see if anyone has written any methods using it. A forum search only turned up someone with the last name of Luhn.

Thanks.
Don

Comments

  • Heater.Heater. Posts: 21,230
    edited 2014-02-25 20:49
    I guess not many off us here are into processing bank account numbers with Propeller chips.

    More likely we would use a simple checksum or Cyclic Redundancy Check for verifying binary data in storage devices or communications protocols.

    http://en.wikipedia.org/wiki/Cyclic_redundancy_check
  • AribaAriba Posts: 2,690
    edited 2014-02-25 21:05
    This is a fairly simple algorithm so I had to try it.
    The following code seems to work. It validated correct the example number in the Wiki and also my own CreditCard number.
    CON
      _clkmode  = xtal1 + pll16x
      _xinfreq  = 5_000_000
    
    OBJ
      ser :  "FullDuplexSerial"
          
    VAR
      byte  digits[20]
       
    PUB Main : i | ch
      ser.start(31,30,0,115200)     'Terminal communication
      waitcnt(clkfreq*3+cnt)
      repeat
        ser.str(string(13,"Enter number: "))
        i := 0
        repeat
          ch := ser.rx
          case ch
            "0".."9": digits[i++] := ch
                      ser.tx(ch)
            8,$C8: ser.tx(8)
                   ser.tx(32)
                   ser.tx(8)
                   i := i-1 #> 0
            other: digits[i] := 0
                   quit
    
    '    bytemove(@digits,string("79927398713"),12)  'Test number
        ser.str(string(13,"Number: "))
        ser.str(@digits)
        if LuhnValidation(@digits) == 0
           ser.str(string(" is Okay"))
        else
           ser.str(string(" is Wrong"))
    
    PUB LuhnValidation(strp) : sum | n, d
    
    '' expects number as characters in a string
    '' returns 0 if okay or 1..9 otherwise
    
      n := strsize(strp)-1
      repeat
        sum += byte[strp+n]-"0"
        n--
        if n => 0
          d := byte[strp+n]-"0"
          if d*2 > 9
            sum += 1
            sum += d*2-10
          else
            sum += d*2
          n--
      until n < 0
      sum //= 10
    

    Andy
  • JonnyMacJonnyMac Posts: 9,107
    edited 2014-02-25 21:32
    I did an ISO card reader project for my Nuts & Volts column -- this is one of the methods from the demo.
    pub check_luhn(p_str) | sum, ndigits, parity, idx, n
    
    '' Validates credit card # (at p_str) using the Luhn check algorithm
    '' -- http://www.codeproject.com/Articles/10720/How-To-Validate-Credit-Card-Numbers
    
      sum     := 0                                                  ' clear Luhn sum
      ndigits := strsize(p_str)                                     ' get # of digits in CC #
      parity  := ndigits & 1                                        ' calc parity position
    
      repeat idx from 0 to ndigits-1                                ' loop through string
        n := byte[p_str+idx] - "0"                                  ' convert char to digit
        if ((idx & 1) == parity)                                    ' parity position?
          n <<= 1                                                   '  double it
        if (n > 9)                                                  ' if > 9
          n -= 9                                                    '  reduce to single digit
        sum += n                                                    ' update sum
        
      return ((sum // 10) == 0)                                     ' return true if divisible by 10
    
  • Don MDon M Posts: 1,652
    edited 2014-02-26 04:39
    JonnyMac wrote: »
    I did an ISO card reader project for my Nuts & Volts column -- this is one of the methods from the demo.
    pub check_luhn(p_str) | sum, ndigits, parity, idx, n
    
    '' Validates credit card # (at p_str) using the Luhn check algorithm
    '' -- http://www.codeproject.com/Articles/10720/How-To-Validate-Credit-Card-Numbers
    
      sum     := 0                                                  ' clear Luhn sum
      ndigits := strsize(p_str)                                     ' get # of digits in CC #
      parity  := ndigits & 1                                        ' calc parity position
    
      repeat idx from 0 to ndigits-1                                ' loop through string
        n := byte[p_str+idx] - "0"                                  ' convert char to digit
        if ((idx & 1) == parity)                                    ' parity position?
          n <<= 1                                                   '  double it
        if (n > 9)                                                  ' if > 9
          n -= 9                                                    '  reduce to single digit
        sum += n                                                    ' update sum
        
      return ((sum // 10) == 0)                                     ' return true if divisible by 10
    

    Thanks Jon. I'll look for that article as well.
  • Don MDon M Posts: 1,652
    edited 2014-02-26 04:48
    Ariba wrote: »
    This is a fairly simple algorithm so I had to try it.
    The following code seems to work. It validated correct the example number in the Wiki and also my own CreditCard number.
    CON
      _clkmode  = xtal1 + pll16x
      _xinfreq  = 5_000_000
    
    OBJ
      ser :  "FullDuplexSerial"
          
    VAR
      byte  digits[20]
       
    PUB Main : i | ch
      ser.start(31,30,0,115200)     'Terminal communication
      waitcnt(clkfreq*3+cnt)
      repeat
        ser.str(string(13,"Enter number: "))
        i := 0
        repeat
          ch := ser.rx
          case ch
            "0".."9": digits[i++] := ch
                      ser.tx(ch)
            8,$C8: ser.tx(8)
                   ser.tx(32)
                   ser.tx(8)
                   i := i-1 #> 0
            other: digits[i] := 0
                   quit
    
    '    bytemove(@digits,string("79927398713"),12)  'Test number
        ser.str(string(13,"Number: "))
        ser.str(@digits)
        if LuhnValidation(@digits) == 0
           ser.str(string(" is Okay"))
        else
           ser.str(string(" is Wrong"))
    
    PUB LuhnValidation(strp) : sum | n, d
    
    '' expects number as characters in a string
    '' returns 0 if okay or 1..9 otherwise
    
      n := strsize(strp)-1
      repeat
        sum += byte[strp+n]-"0"
        n--
        if n => 0
          d := byte[strp+n]-"0"
          if d*2 > 9
            sum += 1
            sum += d*2-10
          else
            sum += d*2
          n--
      until n < 0
      sum //= 10
    

    Andy

    Andy- Thanks for your demo. I'm trying to understand what you are looking for here:
    case ch
      8,$C8:
    
    


    I like your simple code that uses backspace to correct mistakes typed but I'm trying to figure out what you are looking for. I know the "8" is the backspace character but what does the $C8 ("200") represent?
  • AribaAriba Posts: 2,690
    edited 2014-02-27 00:23
    Don M wrote: »
    ...
    I like your simple code that uses backspace to correct mistakes typed but I'm trying to figure out what you are looking for. I know the "8" is the backspace character but what does the $C8 ("200") represent?

    $C8 is the code that the PS2 Keyboard driver returns for the Backspace key. I normally use PropTerminal on the PC to test such Spin code and PropTerminal sends key codes compatible to the PS2 keyboard driver. If I test for $C8 and 8 then the same code works with standard Terminals and PropTerminal (and PS2 keybords when you change ser.rx to kbrd.getkey).

    Andy
Sign In or Register to comment.