tags:

views:

196

answers:

4

hi there, these two algorithms are used to check valid member numbers the first is the one I was given by the company, the second is one I devised, from my tests I can't see any difference between them functionally,

are there any cases anyone can see where they would return different outputs?

test input: 
6014355021355010
or
6014355065446212
or
6014351000254605

The check digit is calculated using the first 15 digits as follows:

  1. Sum the digits in the even numbered positions from left to right
  2. Multiply each digit in the odd numbered positions (from left to right) by the number 2. If any results are 2 digits, sum the digits into one. Sum the digits from each multiplication into a final result.
  3. Add the final results of steps 1 and 2.
  4. Take the last digit of the result from step 3 and subtract from 10 to give the check digit.
  5. Take the last digit from the 16 Digit number and compare to the check digit
  6. if they are equal, it is valid

vs

The check digit is calulated using the whole 16 digits as follows:

  1. Sum the digits in the even numbered positions from left to right
  2. Multiply each digit in the odd numbered positions (from left to right) by the number 2. If any results are 2 digits, sum the digits into one. Sum the digits from each multiplication into a final result.
  3. Add the final results of steps 1 and 2.
  4. Take the final result and Modulus 10
  5. If the result is 0, it is valid


Update:
ok so. I have tried to create both these algorithms in php, the second one, i have created successfully, the first however, i can not seem to get to work.

possibly i have read this wrong, but, here is the original brief i was given for the first algorithm:

16 digit number modulus 10 check digit calculation

The check digit is calculated using the first 15 digits as follows:
1. Sum the digits in the even numbered positions from left to right

2. Multiply each digit in the odd numbered positions (from left to right) by the number 2
If any results are 2 digits, sum the digits into one.
Sum the digits from each multiplication into a final result.

3. Add the final results of steps 1 and 2.

4. Take the last digit of the result from step 3 and subtract from 10 to give the check digit.
If the result of step 3 is a multiple of 10, then the check digit will be zero.


Example 6014 3590 0000 0928
1.0 0 + 4 + 5 + 0 + 0 + 0 + 9 = 18
2.0 6 * 2 = 12 so 1 + 2 = 3
2.1 1 * 2 = 2
2.2 3 * 2 = 6
2.3 9 * 2 = 18 so 1 + 8 = 9
2.4 0 * 2 = 0
2.5 0 * 2 = 0
2.6 0 * 2 = 0
2.7 2 * 2 = 4
2.8 3 + 2 + 6 + 9 + 0 + 0 + 0 + 4 = 24
3.0 18 + 24 = 42
4.0 The check digit is 10 - 2 = 8
5.0 8 = the 16th digit (601435900000092[8])


Update2:
ok, so i have corrected the algorithm,

also, i should mention, that there are two other checks if(length of number != 16) return 1; and if(first 5 characters != 601435) return 1;

so are there any counters to this?

cheers, Matt


Algorithm test [php]

<?php
$file = file_get_contents('fb.csv');
$numbers = explode("\n", $file);

function validate_flybuys($number) {
    $r = array ('o' => '0', 'i' => '1', 'l' => '1', 'e' => '3', ' ' => '');
    $flybuys = trim(strtolower($number));
    $flybuys = str_replace(array_keys($r), $r, $flybuys);
    if('601435' != substr($flybuys, 0, 6) || strlen($flybuys) != 16)
            return 1;
    $evens = 0;
    $odds = '';

    for($i = 0; $i <= 15; $i+=2) {
        $odds .= $flybuys[$i];
        $evens += $flybuys[$i+1];
    }

    $odds = str_split($odds);
    foreach($odds as &$odd) {
        $odd = $odd*2;
        if($odd >= 10) {
            $odd = str_split($odd);
            $odd = $odd[0] + $odd[1];
        }
    }
    return (array_sum($odds)+$evens) % 10;
}

function validate_flybuys2($number) {
    $r = array ('o' => '0', 'i' => '1', 'l' => '1', 'e' => '3', ' ' => '');
    $flybuys = trim(strtolower($number));
    $flybuys = str_replace(array_keys($r), $r, $flybuys);
    if('601435' != substr($flybuys, 0, 6) || strlen($flybuys) != 16)
            return 1;
    $evens = 0;
    $odds = '';

    for($i = 0; $i <= 14; $i+=2) {
        $odds .= $flybuys[$i];
        if($i != 14)
            $evens += $flybuys[$i+1];
    }

    $odds = str_split($odds);
    foreach($odds as &$odd) {
        $odd = $odd*2;
        if($odd >= 10) {
            $odd = str_split($odd);
            $odd = $odd[0] + $odd[1];
        }
    }
    $total = (array_sum($odds))+$evens;
    $total = str_split($total);
    $check = 10 - $total[1];
    $check = $check % 10;
    if($check == substr($flybuys, 15, 1))
        return 0;
    else
        return $check;
}

foreach($numbers as $number) {
    $valid = validate_flybuys($number);
    $valid2 = validate_flybuys2($number);
    if($valid != $valid2 || $valid != 0) {
        echo '<hr />';
        echo 'NUMBER: '.$number.'<br />';
        echo 'V1: '.$valid.'<br />';
        echo 'V2: '.$valid2.'<br />';
    }
}

if anyone is interested and comments i can post some sample numbers to test against :)
oh and feel free to optimize the code 8D

+2  A: 
Eiko
For this example both algorithms say the number is valid. For the second alogrithm you take the whole 16 digits! So sum for even part is 62 and for uneven is 48, which is 110 and 110%10==0.
rudi-moore
Your test number doesn't have 16 digits. How can you compare the algorithms without the complete digits? What's more, the result from step 2 (calculate sum for odd digits) should be 45, not 48: 2*3 + 2*3 + 2*3 + 2*3 + 2*3 + 2*3 + 2*3 + 3 = 45 (where the last 3 results from 2*6 = 12, whose digits are summed into 3).
stakx
@stakx i think he meant 3838 3838 3838 383 - 6
rudi-moore
Right, missed the last 3 before the check digit. But it's wrong anyway :-)
Eiko
The test number suggested by rudi-moore above works with both algorithms.
stakx
Please see my new answer with a counter example.
Eiko
+5  A: 

EDIT: This proof only works if the step 5 and 6 of the first algorithm are an equal check instead of a modulus calculation. The equal check seems to be meant by the original brief as mentioned in the comments.

EDIT2: I think the first algorithm should look like this. But you should better verify this, maybe from the one who gave you the original brief.

  1. Sum the digits in the even numbered positions from left to right
  2. Multiply each digit in the odd numbered positions (from left to right) by the number 2. If any results are 2 digits, sum the digits into one. Sum the digits from each multiplication into a final result.
  3. Add the final results of steps 1 and 2.
  4. Take the last digit of the result from step 3 and substract from 10 to give the check digit.
  5. Take the last digit of the 16digit-number and if it is the same as the computed check digit the number is valid

To verifiy mathematically that both algorithms are equal you can use congruency.

Let's say a is the sum from step 3 of the first algorithm, b is the sum of step 3 of the second algorithm and c is the 16th digit (the check digit).

Than the difference between a and b is that c is added to b but not to a, which means:

a ≡ b - c mod 10

The check from the first algorithm is performed by substracting a from 10 and check if it is congruent c for modulus 10. (for addition and substraction it doesn't matter when the modulus is performed)

10 - a ≡ c mod 10

this is equal to:

-a ≡ c mod 10

Now you can substitute a with the first one, which results in

-(b - c) ≡ c mod 10

this is equal to:

c - b ≡ c mod 10

and this is equal to:

-b ≡ 0 mod 10
b ≡ 0 mod 10

and that is the check, which is performed in the second algorithm. So both algorithms returns the same result.

rudi-moore
Then you can for sure prove my counter example of 0000000000000257 wrong?! Not sure what you proved here, but not the algorithm obviously.
Eiko
From the originaly brief added in the update, i read it that way that the calculated check digit, must be equal with the 16th digit. Thats also what makes sense for generating a 16th crc-like digit to proof correctness. So for your example the sum is 2+1=3 and the check digit is 10-3=7 which is equal to the 16th digit.
rudi-moore
Yes, the equal check makes more sense. Now, this was a refreshing flashback of maths, so +1. :-)
Eiko
A: 

The algorithms are different:

Take 0000000000000257

The original algorithm says it's not valid: Sum of even numbered digits is 2, the odds sum is 1 => total of 3. 10-3 = 7. 257 MOD 7 = 5 != 0 => Not valid

You algorithm sums even to 9, odds to 1 => total 10. 10 MOD 10 == 0 => Valid.

So they are not equivalent

qed. :-)

Eiko
It should be 7 mod 7 = 0, which is valid.But i conform with you that there are counter examples for the first posted algorithms. `0600 0000 0000 000 - 8` for example. sum for 1st algorithm is 6. 10-6=4. 8 mod 4 = 0 -> valid. sum for 2nd algorithm 14. 4 != 0 -> not valid. Thats why i added a comment. Because i think the modulus from the first algorithm should be an equal check (the originally brief says that too thought). For that example: 8 != 4 -> not valid. With that equal check instead of a modulus both are equal, which i proofed in my answer.
rudi-moore
A: 

Your php code has some problems.

$check = 10 - $total[1]; is only valid if the total sum is a 2-digit number. Because your numbers always start with 601435 the total sum has not less than 2 digits. But at least 6014359999999990 and 6014359999999999 would be validated wrong in V2.

The line return $check; can return 0. That way 6014355021355012 or 6014355021355017 are verified as being valid, while they are not.

I would replace the lines:

$total = str_split($total);
$check = 10 - $total[1];
$check = $check % 10;
if($check == substr($flybuys, 15, 1))
    return 0;
else
    return $check;

with

return (substr($flybuys, 15, 1) + $total) % 10;

So V1 and V2 returns the same value.

rudi-moore