Skip to main content
add alternate (but longer) version
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57

Alternate version, 29 bytes

33 DB           XOR  BX, BX             ; running sum (BL) to 0
03 F1           ADD  SI, CX             ; start at end of string
4E              DEC  SI                 ; align for WORD
FD              STD                     ; set LODSB direction to decrement
            DIGIT_LOOP:
AD              LODSW                   ; load next two digits into AH:AL, dec SI by 2
25 0F0F         AND  AX, 0F0FH          ; convert ASCII chars to binary value
02 DC           ADD  BL, AH             ; add ones digit of even index to sum
49              DEC  CX                 ; decrement counter for WORD
74 0A           JZ   DONE               ; if input is odd length, will be 0 at the end
D0 E0           SHL  AL, 1              ; double the value
D4 0A           AAM                     ; split digits (ex: 18 --> AH = 1, AL = 8)
02 DC           ADD  BL, AH             ; add tens digit to sum
02 D8           ADD  BL, AL             ; add ones digit to sum
E2 ED           LOOP DIGIT_LOOP
            DONE:
93              XCHG AX, BX             ; move sum to AL for mod 10 check
D4 0A           AAM                     ; ZF = ( AL % 10 == 0 )
C3              RET                     ; return to caller

This version loads two digits at the same time, eliminating the flip/flop branch. The issue here is having to check for an odd number of digits on the input and discard the value in memory right before the beginning of the string once it reaches the last word. Obviously not shorter, but perhaps someone clever can golf it more!

Alternate version, 29 bytes

33 DB           XOR  BX, BX             ; running sum (BL) to 0
03 F1           ADD  SI, CX             ; start at end of string
4E              DEC  SI                 ; align for WORD
FD              STD                     ; set LODSB direction to decrement
            DIGIT_LOOP:
AD              LODSW                   ; load next two digits into AH:AL, dec SI by 2
25 0F0F         AND  AX, 0F0FH          ; convert ASCII chars to binary value
02 DC           ADD  BL, AH             ; add ones digit of even index to sum
49              DEC  CX                 ; decrement counter for WORD
74 0A           JZ   DONE               ; if input is odd length, will be 0 at the end
D0 E0           SHL  AL, 1              ; double the value
D4 0A           AAM                     ; split digits (ex: 18 --> AH = 1, AL = 8)
02 DC           ADD  BL, AH             ; add tens digit to sum
02 D8           ADD  BL, AL             ; add ones digit to sum
E2 ED           LOOP DIGIT_LOOP
            DONE:
93              XCHG AX, BX             ; move sum to AL for mod 10 check
D4 0A           AAM                     ; ZF = ( AL % 10 == 0 )
C3              RET                     ; return to caller

This version loads two digits at the same time, eliminating the flip/flop branch. The issue here is having to check for an odd number of digits on the input and discard the value in memory right before the beginning of the string once it reaches the last word. Obviously not shorter, but perhaps someone clever can golf it more!

+4 bytes, rules compliance
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57

x86-16 ASMmachine code, IBM PC DOS, 2327 bytes

Binary:

00000000: bb00 0103 f1fd ac2c 30f6 df78 06d0 e0d4  .......,0..x....
00000010: 0a02 dc02 d8e2 ef93 d40a c3              ...........

Listing:

BB 0100         MOV  BX, 100H           ; running sum (BL) to 0, BH to a positive value
03 F1           ADD  SI, CX             ; start at end of input string 
FD              STD                     ; set LODSB direction to decrement 
            DIGIT_LOOP: 
AC              LODSB                   ; load next digit into AL, decrement SI
2C 30           SUB  AL, '0'            ; convert ASCII char to binary value 
F7F6 DADF           NEG  DXBH                 ; flip DXsign of BH to alternate odd/even index
78 06           JS   EVENIS_EVEN            ; if evennot odd index, do not double
D0 andE0 sum digits 
D0 E0       SHL  AL, 1              ; double the value 
D4 0A           AAM                 ; BCD convert to ; split digits (ex: 18 = 12H --> 0108HAH = 1, AL = 8) 
02 DC           ADD  BL, AH             ; add tens digit to running sum 
    EVEN        IS_EVEN:
02 D8           ADD  BL, AL             ; add ones digit to running sum 
E2 EDEF           LOOP DIGIT_LOOP 
93              XCHG BXAX, AXBX             ; sum is in BL, move to AL for conversionmod 10 check
D4 0A           AAM                     ; BCDZF convert= ( AL, set% ZF=110 if== low0 digit) is
C3 0             RET                     ; return to caller

Uses (abuses) the x86's BCD-to-binary instruction AAM to handle the individual digit splitting and modulo 10 check.

InputCallable function, input card num string pointer in SI, length in CX. Output: ZF if valid.

enter image description here

Download LUHN.COM IBM PC DOS test program.

x86-16 ASM, IBM PC DOS, 23 bytes

03 F1       ADD  SI, CX         ; start at end of input string 
FD          STD                 ; set LODSB direction to decrement 
    DIGIT_LOOP:
AC          LODSB               ; load next digit into AL, decrement SI
2C 30       SUB  AL, '0'        ; convert ASCII char to binary value 
F7 DA       NEG  DX             ; flip DX to alternate odd/even index
78 06       JS   EVEN           ; if even index, do not double and sum digits 
D0 E0       SHL  AL, 1          ; double the value 
D4 0A       AAM                 ; BCD convert to split digits (ex: 18 = 12H --> 0108H) 
02 DC       ADD  BL, AH         ; add tens digit to running sum 
    EVEN:
02 D8       ADD  BL, AL         ; add ones digit to running sum 
E2 ED       LOOP DIGIT_LOOP 
93          XCHG BX, AX         ; sum is in BL, move to AL for conversion
D4 0A       AAM                 ; BCD convert AL, set ZF=1 if low digit is 0

Uses (abuses) the x86's BCD-to-binary instruction AAM to handle the individual digit splitting and modulo 10 check.

Input card num string pointer in SI, length in CX. Output: ZF if valid.

enter image description here

Download LUHN.COM IBM PC DOS test program.

x86-16 machine code, 27 bytes

Binary:

00000000: bb00 0103 f1fd ac2c 30f6 df78 06d0 e0d4  .......,0..x....
00000010: 0a02 dc02 d8e2 ef93 d40a c3              ...........

Listing:

BB 0100         MOV  BX, 100H           ; running sum (BL) to 0, BH to a positive value
03 F1           ADD  SI, CX             ; start at end of input string
FD              STD                     ; set LODSB direction to decrement
            DIGIT_LOOP: 
AC              LODSB                   ; load next digit into AL, decrement SI
2C 30           SUB  AL, '0'            ; convert ASCII char to binary value 
F6 DF           NEG  BH                 ; flip sign of BH to alternate odd/even index
78 06           JS   IS_EVEN            ; if not odd index, do not double
D0 E0           SHL  AL, 1              ; double the value
D4 0A           AAM                     ; split digits (ex: 18 --> AH = 1, AL = 8) 
02 DC           ADD  BL, AH             ; add tens digit to running sum
            IS_EVEN:
02 D8           ADD  BL, AL             ; add ones digit to running sum 
E2 EF           LOOP DIGIT_LOOP 
93              XCHG AX, BX             ; sum is in BL, move to AL for mod 10 check
D4 0A           AAM                     ; ZF = ( AL % 10 == 0 ) 
C3              RET                     ; return to caller

Uses (abuses) x86's BCD-to-binary instruction AAM to handle the individual digit splitting and modulo 10 check.

Callable function, input card num string pointer in SI, length in CX. Output: ZF if valid.

enter image description here

Commonmark migration
Source Link

#x86-16 ASM, IBM PC DOS, 23 bytes

x86-16 ASM, IBM PC DOS, 23 bytes

03 F1       ADD  SI, CX         ; start at end of input string 
FD          STD                 ; set LODSB direction to decrement 
    DIGIT_LOOP:
AC          LODSB               ; load next digit into AL, decrement SI
2C 30       SUB  AL, '0'        ; convert ASCII char to binary value 
F7 DA       NEG  DX             ; flip DX to alternate odd/even index
78 06       JS   EVEN           ; if even index, do not double and sum digits 
D0 E0       SHL  AL, 1          ; double the value 
D4 0A       AAM                 ; BCD convert to split digits (ex: 18 = 12H --> 0108H) 
02 DC       ADD  BL, AH         ; add tens digit to running sum 
    EVEN:
02 D8       ADD  BL, AL         ; add ones digit to running sum 
E2 ED       LOOP DIGIT_LOOP 
93          XCHG BX, AX         ; sum is in BL, move to AL for conversion
D4 0A       AAM                 ; BCD convert AL, set ZF=1 if low digit is 0

Uses (abuses) the x86's BCD-to-binary instruction AAM to handle the individual digit splitting and modulo 10 check.

Input card num string pointer in SI, length in CX. Output: ZF if valid.

Example test program output:

enter image description here

Download LUHN.COM IBM PC DOS test program.

#x86-16 ASM, IBM PC DOS, 23 bytes

03 F1       ADD  SI, CX         ; start at end of input string 
FD          STD                 ; set LODSB direction to decrement 
    DIGIT_LOOP:
AC          LODSB               ; load next digit into AL, decrement SI
2C 30       SUB  AL, '0'        ; convert ASCII char to binary value 
F7 DA       NEG  DX             ; flip DX to alternate odd/even index
78 06       JS   EVEN           ; if even index, do not double and sum digits 
D0 E0       SHL  AL, 1          ; double the value 
D4 0A       AAM                 ; BCD convert to split digits (ex: 18 = 12H --> 0108H) 
02 DC       ADD  BL, AH         ; add tens digit to running sum 
    EVEN:
02 D8       ADD  BL, AL         ; add ones digit to running sum 
E2 ED       LOOP DIGIT_LOOP 
93          XCHG BX, AX         ; sum is in BL, move to AL for conversion
D4 0A       AAM                 ; BCD convert AL, set ZF=1 if low digit is 0

Uses (abuses) the x86's BCD-to-binary instruction AAM to handle the individual digit splitting and modulo 10 check.

Input card num string pointer in SI, length in CX. Output: ZF if valid.

Example test program output:

enter image description here

Download LUHN.COM IBM PC DOS test program.

x86-16 ASM, IBM PC DOS, 23 bytes

03 F1       ADD  SI, CX         ; start at end of input string 
FD          STD                 ; set LODSB direction to decrement 
    DIGIT_LOOP:
AC          LODSB               ; load next digit into AL, decrement SI
2C 30       SUB  AL, '0'        ; convert ASCII char to binary value 
F7 DA       NEG  DX             ; flip DX to alternate odd/even index
78 06       JS   EVEN           ; if even index, do not double and sum digits 
D0 E0       SHL  AL, 1          ; double the value 
D4 0A       AAM                 ; BCD convert to split digits (ex: 18 = 12H --> 0108H) 
02 DC       ADD  BL, AH         ; add tens digit to running sum 
    EVEN:
02 D8       ADD  BL, AL         ; add ones digit to running sum 
E2 ED       LOOP DIGIT_LOOP 
93          XCHG BX, AX         ; sum is in BL, move to AL for conversion
D4 0A       AAM                 ; BCD convert AL, set ZF=1 if low digit is 0

Uses (abuses) the x86's BCD-to-binary instruction AAM to handle the individual digit splitting and modulo 10 check.

Input card num string pointer in SI, length in CX. Output: ZF if valid.

Example test program output:

enter image description here

Download LUHN.COM IBM PC DOS test program.

remove unnecesary MACRO syntax, cleanup unnecssary explanation
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading
clarify program comments and formatting
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading
added 2 characters in body
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading
-2 bytes, don't need to worry about 8 bit overflow since we're doing mod 10... duh
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading
add explanation for register state
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading
edited body
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading
add link to platform referebce
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading
-3 bytes, use DX register for flip/flop (DOS init's DX to CS - a positive, non-zero value)
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading
-1 byte
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading
-1 byte
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading
deleted 3 characters in body
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading
deleted 6 characters in body
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading
deleted 6 characters in body
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading
edited body
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading
-6 bytes, use AAM for mod 10 test
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading