我一直在努力创建一个程序,可以根据Hans Peter Luhn's algorithm检查信用卡号是否有效。但是,我只能让它为某些输入工作。
// Loop through every digit in the card number
for ( int i = 0; i < intlen (num); ++i )
{
nextDigit = getDigit (num, i);
// If every other number...
if ( i % 2 )
{
nextDigit *= 2;
// ...times by two and add the individual digits to the total
for ( int j = 0; j < intlen (nextDigit); ++j )
{
total += getDigit (nextDigit, j);
}
}
else
{
total += nextDigit;
}
}
当我使用AMEX
卡号378282246310005
时,它可以正常工作并告诉用户它有效。但是,一旦我尝试VISA
卡号4012888888881881
,它就会说它无效。我试图进行健全性检查并手动完成以查看我的程序是否错误,但我推断出相同的结果。这些卡号取自Paypal测试信用卡号page,因此我知道它们有效。
那么我做错了什么?
要澄清程序的详细信息,如果total modulo 10 == 0
,则卡号有效。
调用的函数:
// Function to return length (number of digits) of an int
int intlen (long long n)
{
int len = 1;
// While there is more than 1 digit...
while ( abs (n) > 9 )
{
// ...discard leading digits and add 1 to len
n /= 10;
++len;
}
return len;
}
// Function to return a digit in an integer at a specified index
short getDigit (long long num, int index)
{
// Calculating position of digit in integer
int pos = intlen (num) - index;
// Discard numbers after selected digit
while ( pos > 1 )
{
num /= 10;
--pos;
}
// Return right-most digit i.e. selected digit
return num % 10;
}
答案 0 :(得分:3)
您希望将i % 2
更改为i % 2 == intlen (num) % 2
或类似内容;你应该每隔一位数加倍,但是starting from the right;即排除最后的校验位:
从最右边的数字,即校验位,向左移动,每隔一位数的值加倍; ...
您尝试验证的AMEX号码的原因是因为它是一个奇数位数;无论你是从前面还是后面跳过,相同的数字都会加倍。
答案 1 :(得分:0)
当我看到这个以找到错误时,我重新编写了程序以使其更简单。作为副作用,这将更快。
我们还需要从右边抓取数字。我们甚至不需要计算数字;只需继续拉出最右边的数字,直到数字变为0.如果数字从0开始,校验和通常为0,代码仍然正确。
我抓住了测试页面上的所有数字。这似乎是正确的,除了一个数字:76009244561
(在测试页中列为&#34; Dankort(PBS)&#34;)。我使用维基百科页面中的Python代码尝试了这个数字,这个数字再次被拒绝。我不知道为什么这个号码与其他号码不同。
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
bool check_one(long long num)
{
int checksum = 0;
int i = 1;
for (int i = 1; num; num /= 10, ++i)
{
int d = num % 10;
if (i % 2 == 0)
{
// even digit: double and add digits of doubled value
d *= 2;
if (d < 10)
{
// only one digit: we doubled a 0-4 so number is 0-8
checksum += d;
}
else
{
// two digits: we doubled a 5-9 so number is 10-18
checksum += (d % 10);
checksum += (d / 10);
}
}
else
{
// odd digit: just add
checksum += d;
}
}
return (checksum % 10) == 0;
}
static long long const valid_nums[] =
{
378282246310005,
371449635398431,
378734493671000,
5610591081018250,
30569309025904,
38520000023237,
6011111111111117,
6011000990139424,
3530111333300000,
3566002020360505,
5555555555554444,
5105105105105100,
4111111111111111,
4012888888881881,
4222222222222,
76009244561,
5019717010103742,
6331101999990016,
};
static size_t len_valid_nums = sizeof(valid_nums) / sizeof(valid_nums[0]);
static long long const non_valid_nums[] =
{
378282246310006, // add 1 to valid
371449635398432,
378734493671001,
5610591081018205, // swap last two digits
30569309025940,
38520000023273,
601111111111111, // delete last digit
601100099013942,
353011133330000,
};
static size_t len_non_valid_nums =
(sizeof(non_valid_nums) / sizeof(non_valid_nums[0]));
main()
{
bool f;
for (int i = 0; i < len_valid_nums; ++i)
{
long long num = valid_nums[i];
f = check_one(num);
if (!f)
{
printf("Number %lld considered invalid but should be valid\n", num);
}
}
for (int i = 0; i < len_non_valid_nums; ++i)
{
long long num = non_valid_nums[i];
f = check_one(num);
if (f)
{
printf("Number %lld considered valid but should be invalid\n", num);
}
}
}