1
\$\begingroup\$

My implementation in Progress 4GL of the Luhn Algorithm. Any suggestions on improving it?

FUNCTION fnLuhnAlgorithm RETURNS LOGICAL
 (INPUT pcNumber AS CHARACTER):
/*------------------------------------------------------------------------------
 Purpose: Applies Luhn Algorithm to check a Number 
 Notes: Returns True/False Validation based on check digit
 From the rightmost digit, which is the check digit, moving left, double the value
 of every second digit; 
 if product of this doubling operation is greater than 9 (e.g., 7 * 2 = 14).
 Sum the digits of the products (e.g., 10: 1 + 0 = 1, 14: 1 + 4 = 5) together 
 Compute the sum of the digits.
 Multiply by 9.
 The last digit, is the check digit.
------------------------------------------------------------------------------*/
 DEFINE VARIABLE cNum AS CHARACTER NO-UNDO.
 DEFINE VARIABLE iCheck AS INTEGER NO-UNDO.
 DEFINE VARIABLE iLength AS INTEGER NO-UNDO.
 DEFINE VARIABLE iLoopCnt AS INTEGER NO-UNDO.
 DEFINE VARIABLE iNum AS INTEGER NO-UNDO.
 DEFINE VARIABLE iNum1 AS INTEGER NO-UNDO.
 DEFINE VARIABLE iNum2 AS INTEGER NO-UNDO.
 DEFINE VARIABLE iTestLength AS INTEGER NO-UNDO.
 ASSIGN 
 iLength = LENGTH(pcNumber)
 iTestLength = iLength - 1
 iCheck = 1. /* 1 for the check digit we skip */
 DO iLoopCnt = iTestLength TO 1 BY -1:
 ASSIGN 
 iNum = INTEGER(SUBSTR(pcNumber,iLoopCnt,1))
 iCheck = iCheck + 1.
 IF iCheck MODULO 2 = 1 THEN
 ASSIGN iNum1 = iNum1 + iNum.
 ELSE
 DO:
 ASSIGN iNum2 = iNum * 2.
 IF iNum2 < 10 THEN
 ASSIGN iNum1 = iNum1 + iNum2.
 ELSE
 ASSIGN
 cNum = STRING(iNum2)
 iNum1 = iNum1 + INTEGER(SUBSTR(cNum,1,1)) + INTEGER(SUBSTR(cNum,2,1)). 
 END.
 END.
 ASSIGN 
 iNum2 = iNum1 * 9
 iNum = iNum2 MODULO 10.
 IF iNum = INTEGER(SUBSTR(pcNumber,iLength,1)) THEN
 RETURN TRUE.
 ELSE
 RETURN FALSE.
END FUNCTION. /* fnLuhnAlgorithm */
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Jun 19, 2013 at 8:38
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

You are kind of overdoing it a little in my opinion, there are too many variables that don't really add much value, also I would change the parameter to be DECIMAL, to avoid calls using not numbers that would cause run time errors.

My implementation would look like this:

FUNCTION fnLuhnAlgorithm RETURNS LOGICAL
 (INPUT pcNumber AS DECIMAL):
/*------------------------------------------------------------------------------
 Purpose: Applies Luhn Algorithm to check a Number 
 Notes: Returns True/False Validation based on check digit
 From the rightmost digit, which is the check digit, moving left, double the value
 of every second digit; 
 if product of this doubling operation is greater than 9 (e.g., 7 * 2 = 14).
 Sum the digits of the products (e.g., 10: 1 + 0 = 1, 14: 1 + 4 = 5) together 
 Compute the sum of the digits.
 Multiply by 9.
 The last digit, is the check digit.
------------------------------------------------------------------------------*/
 DEFINE VARIABLE cNumber AS CHARACTER NO-UNDO INITIAL "".
 DEFINE VARIABLE iDigit AS INTEGER NO-UNDO INITIAL 0.
 DEFINE VARIABLE iSum AS INTEGER NO-UNDO INITIAL 0.
 DEFINE VARIABLE iLoopCnt AS INTEGER NO-UNDO INITIAL 0.
 cNumber = STRING(pcNumber).
 DO iLoopCnt = LENGTH(cNumber) - 1 TO 1 BY -1:
 iDigit = INTEGER(SUBSTR(cNumber,iLoopCnt,1)).
 IF iLoopCnt MODULO 2 = LENGTH(cNumber) MODULO 2 THEN
 iSum = iSum + iDigit.
 ELSE
 iSum = iSum + INTEGER(SUBSTR(STRING(iDigit * 2,"99"),1,1)) 
 + INTEGER(SUBSTR(STRING(iDigit * 2,"99"),2,1)). 
 END.
 IF ((iSum * 9) MODULO 10) = INTEGER(SUBSTR(cNumber,LENGTH(cNumber),1)) THEN
 RETURN TRUE.
 ELSE
 RETURN FALSE.
END FUNCTION. /* fnLuhnAlgorithm */
answered Jun 20, 2013 at 14:05
\$\endgroup\$
4
  • \$\begingroup\$ Looks good, I would just either keep the input parm as character or make it integer instead of decimal. \$\endgroup\$ Commented Jun 21, 2013 at 11:23
  • \$\begingroup\$ if input parm is character you can also get rid of the variable cNumber \$\endgroup\$ Commented Jun 21, 2013 at 11:52
  • \$\begingroup\$ I have defined as DECIMAL because it would be able to hold a much higher maximum value than an INTEGER, and if you are dealing with account numbers or similar you'll reach it easily. About the CHARACTER input parameter, if that is the case then you'll need to first check the value is a valid number to be able to check it, also, seems much more clear if the function is to validate numbers that the parameter you pass is a number itself to me. \$\endgroup\$ Commented Jun 21, 2013 at 20:46
  • \$\begingroup\$ Agree will need a check to make sure it is number, but same if input is decimal you still need to check to make sure it is not a decimal value. I use the LUHN Algorithm to test ID number, but before I call the algorithm i first do a lot of tests to make sure the ID number is a number and contains valid values in certain positions, etc. So by the time I call the function I know I have a valid number I just need to make sure the check digit is correct, so the Luhn Algorithm does not have to worry if value is a number. \$\endgroup\$ Commented Jun 26, 2013 at 10:40

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.