Double existence and
checking the payload
Weekly challenge 290 — 7 October 2024
Week 290: 7 Oct 2024
You are given a string $str
containing digits
(and possibly other characters which can be ignored). The
last digit is the payload; consider it separately.
Counting from the right, double the value of the first, third, etc of the remaining digits. For each value now greater than 9, sum its digits.
The correct check digit is that which, added to the sum of all values, would bring the total mod 10 to zero. Return true if and only if the payload is equal to the correct check digit.
Example 1 Input: "17893729974" Output: true Payload is 4. Digits from the right: 7 * 2 = 14, sum = 5 9 = 9 9 * 2 = 18, sum = 9 2 = 2 7 * 2 = 14, sum = 5 3 = 3 9 * 2 = 18, sum = 9 8 = 8 7 * 2 = 14, sum = 5 1 = 1 Sum of all values = 56, so 4 must be added to bring the total mod 10 to zero. The payload is indeed 4. Example 2 Input: "4137 8947 1175 5904" Output: true Example 3 Input: "4137 8974 1175 5904" Output: false
The Luhn algorithm is widely used as a simple check that a string of digits has been entered correctly, It will catch many, though not all, missing or transposed digits.
The implementation is easy, essentially following the steps in the definition above, ie:
Credit card numbers use the Luhn algorithm for an initial check, I suggest that you don't type your own credit card number below, but here are some dummy numbers that the issuers offer for testing purposes:
Visa: 4111 1111 1111 1111 or 4242 4242 4242 4242
MasterCard: 5431 1111 1111 1111
Amex: 3711 1111 1111 114
Diners: 3600 0000 0000 08
#!/usr/bin/perl # Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge use v5.26; # The Weekly Challenge - 2024-10-07 use utf8; # Week 290 - task 2 - Luhn’s algorithm use warnings; # Peter Campbell Smith binmode STDOUT, ':utf8'; luhns_algorithm('17893729974'); luhns_algorithm('4137 8947 1175 5904'); luhns_algorithm('4137 8974 1175 5904'); luhns_algorithm('3141 5926 5358 9796'); sub luhns_algorithm { my ($str, $data, $payload, $check_sum, $digit, $check_digit, $odd, $j); # get rid of non-digits $str = $_[0]; $str =~ s|[^\d]||g; # strip payload ($data, $payload) = $str =~ m|(\d+)(\d)|; # loop over digits from right to left $check_sum = 0; $odd = 1; for ($j = length($data) - 1; $j >= 0; $j --) { $digit = substr($data, $j, 1); # if an odd digit double and mod 10 if ($odd) { $digit *= 2; $digit -= 9 if $digit >= 10; } $check_sum += $digit; $odd = 1 - $odd; } # get check digit $check_digit = 10 - (($check_sum - 1) % 10 + 1); say qq[\nInput: \@str = '$_[0]']; say qq[Output: ] . ($check_digit == $payload ? 'true' : 'false') . qq[ (payload = $payload, check_digit = $check_digit)]; }
Input: @str = '17893729974' Output: true (payload = 4, check_digit = 4) Input: @str = '4137 8947 1175 5904' Output: true (payload = 4, check_digit = 4) Input: @str = '4137 8974 1175 5904' Output: false (payload = 4, check_digit = 0) Input: @str = '3141 5926 5358 9796' Output: true (payload = 6, check_digit = 6)
Any content of this website which has been created by Peter Campbell Smith is in the public domain