【发布时间】:2010-07-14 07:45:42
【问题描述】:
这两种算法用于检查有效的会员号 第一个是公司给我的, 第二个是我设计的,从我的测试中我看不出它们在功能上的任何区别,
在任何情况下任何人都可以看到他们会在哪里返回不同的输出?
测试输入: 6014355021355010 或者 6014355065446212 或者 6014351000254605校验位使用前15位计算如下:
- 从左到右将偶数位的数字相加
- 将奇数位置的每个数字相乘(从左到 对)按数字 2. 如果有任何结果 是 2 位数字,将数字相加为 1。 将每个数字相加 乘以最终结果。
- 添加第 1 步和第 2 步的最终结果。
- 从第 3 步中取出结果的最后一位,然后从 10 中减去 给出校验位。
- 从 16 位数字中取出最后一位数字并与校验位进行比较
- 如果相等,则有效
对
校验位使用整16位计算如下:
- 从左到右将偶数位的数字相加
- 将奇数位置的每个数字相乘(从左到 对)按数字 2. 如果有任何结果 是 2 位数字,将数字相加为 1。 将每个数字相加 乘以最终结果。
- 添加第 1 步和第 2 步的最终结果。
- 取最终结果和模数 10
- 如果结果为0,则有效
更新:
好吧。我试图在 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 = 62.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:
好的,所以我已经更正了算法,
另外,我应该提一下,还有另外两项检查 如果(数字的长度!= 16) 返回 1; 和 如果(前 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 />';
}
}
如果有人有兴趣和 cmets,我可以发布一些样本编号进行测试:)
哦,随意优化代码 8D
【问题讨论】:
-
从您添加的第一个算法的第 5 步的简介中,不应该是模数。它应该是计算的校验位和第 16 位之间的相等校验(或者如果结果为 0,则进行减法运算,然后进行校验)。随着这种变化,两种算法的思想都相同。
-
(题外话:)我觉得很有趣,你会花这么多时间在贵公司给你的(工作)算法上......这是过早优化的例子吗?
:-) -
不确定您对原始算法的描述中的第 5 步来自哪里...我认为他们宁愿检查它是否是最后一个数字,但只有你老板可以告诉你...
-
@Hailwood:我完全是出于好奇,这是一个很好的谜题。然而,在决定在实践中哪个更好时,我会选择原来的那个,主要是因为如果算法被证明是错误的,没有人可以责怪你。如果你最终使用你的算法,你必须准备好为它辩护(例如,有一个算法是等效的声音证明)。但这可能还不够:根据我的经验,一些被激怒的老板甚至不会接受可靠的论据,他们只会看到你无缘无故地改变了一些(假设是)正确的。
-
您所追求的似乎是一个基本的信用卡验证算法。 en.wikipedia.org/wiki/Luhn_algorithm
标签: algorithm