这两种算法的结果有区别吗?

时间:2010-07-14 07:45:43

标签: algorithm

这两种算法用于检查有效的成员编号 第一个是我公司给的, 第二个是我设计的,从我的测试中我看不出它们在功能上有什么区别,

有没有人能看到他们会在哪里返回不同的输出?

test input: 
6014355021355010
or
6014355065446212
or
6014351000254605

校验位使用前15位数字计算如下:

  
      
  1. 从左到右对偶数位置的数字求和
  2.   
  3. 将奇数位置的每个数字相乘(从左到右)   右)由数字2.如果有任何结果   是2位数,将数字加总为1。   对每个数字求和   乘以最终结果。
  4.   
  5. 添加步骤1和2的最终结果。
  6.   
  7. 从步骤3中取结果的最后一位数,然后从10减去   给出校验位。
  8.   
  9. 从16位数字中取最后一位数字并与校验位
  10. 进行比较   
  11. 如果相等,则有效
  12.   

VS

校验位使用整数16位数进行计算,如下所示:

  
      
  1. 从左到右对偶数位置的数字求和
  2.   
  3. 将奇数位置的每个数字相乘(从左到右)   右)由数字2.如果有任何结果   是2位数,将数字加总为1。   对每个数字求和   乘以最终结果。
  4.   
  5. 添加步骤1和2的最终结果。
  6.   
  7. 取最终结果和模数10
  8.   
  9. 如果结果为0,则有效
  10.   

<小时/> 更新:
好的。我试图在php中创建这两种算法, 第二个,我已成功创建, 然而,第一个,我似乎无法开始工作。

可能我读过这个错误,但是,这是我给第一个算法的原始简介:

  

16位数模数10校验位计算

     

校验位使用前15位数字计算如下:
   1. 从左到右对偶数位置的数字求和   
2. 将奇数位置(从左到右)的每个数字乘以数字2   如果任何结果是2位数,则将数字加总为1   将每次乘法的数字相加到最终结果中   
3. 添加步骤1和2的最终结果   
4. 取第3步结果的最后一位数,并从10减去得到校验位。
  如果步骤3的结果是10的倍数,则校验位将为零   


示例 6014 3590 0000 0928
   1.0 0 + 4 + 5 + 0 + 0 + 0 + 9 = 18
   2.0 6 * 2 = 12 所以 1 + 2 = 3
   2.1 1 * 2 = 2
   2.2 3 * 2 = 6
   2.3 9 * 2 = 18 所以 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 校验位为10 - 2 = 8
   5.0 8 =第16位(601435900000092 [8])

<小时/> 更新2:
好的,所以我更正了算法,

另外,我应该提一下,还有另外两项检查 if(数量的长度!= 16)  返回1; 和 if(前5个字符!= 601435) 返回1;

那么有什么反击吗?

欢呼声, 马特


算法测试[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 />';
    }
}

如果有人有兴趣和评论我可以张贴一些样本数来测试:) 哦,随意优化代码8D

4 个答案:

答案 0 :(得分:6)

编辑:此证明仅在第一算法的步骤5和6是相等检查而不是模数计算时才有效。平等检查似乎是评论中提到的原始简报。

EDIT2:我认为第一个算法应该是这样的。但你应该更好地验证这一点,也许应该是给你原始简报的人。

  
      
  1. 从左到右对偶数位置的数字求和
  2.   
  3. 将奇数位置(从左到右)中的每个数字乘以数字2.如果任何结果是2位数,则将数字相加为1。将每次乘法的数字加总成最终结果。
  4.   
  5. 添加步骤1和2的最终结果。
  6.   
  7. 取第3步结果的最后一位数,并从10减去得到校验位。
  8.   
  9. 取16位数的最后一位数,如果它与计算的校验位相同,则该数字有效
  10.   

为了在数学上验证两种算法是相等的,您可以使用congruency

假设a是第一个算法第3步的总和,b是第二个算法的第3步的总和,c是第16个数字(校验位) )。

ab之间的差异是c已添加到b但未添加到a,这意味着:

a ≡ b - c mod 10

来自第一个算法的检查是通过从10中减去a来执行的,并检查模数10是否为全等c。对于加法和减法,当执行模数时无关紧要)

10 - a ≡ c mod 10

这等于:

-a ≡ c mod 10

现在,您可以将a替换为第一个,结果为

-(b - c) ≡ c mod 10

这等于:

c - b ≡ c mod 10

这等于:

-b ≡ 0 mod 10
b ≡ 0 mod 10

,这是检查,在第二个算法中执行。因此两种算法都返回相同的结果。

答案 1 :(得分:2)

Edit2:请使用正确算法的计数器示例查看我的其他答案。

编辑:我在第二种算法中使用了15个而不是16个数字。

它们不等同。

取383838383838383-6这对第一个算法有效,但第二个算法给出4作为校验位!= 0。

编辑:偶数部分为56,奇数为48,总和为104。

答案 2 :(得分:0)

算法不同

选择0000000000000257

原始算法表明它无效:偶数数字的总和为2,赔率总和为1 =&gt;总计3. 10-3 = 7. 257 MOD 7 = 5!= 0 =&gt;无效

你的算法总和甚至为9,赔率为1 =&gt;总计10. 10 MOD 10 == 0 =&gt;有效的。

所以他们不等同

QED。 : - )

答案 3 :(得分:0)

您的PHP代码存在一些问题。

$check = 10 - $total[1];仅在总和为2位数时有效。由于您的号码始终以601435开头,因此总金额不少于2位数。但在V2中至少会验证60143599999999906014359999999999错误。

return $check;可以返回0.这样60143550213550126014355021355017被验证为有效,而不是。

我会替换这些行:

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

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

因此V1V2会返回相同的值。