验证卡信用卡号

时间:2014-06-24 03:56:01

标签: c luhn

我一直在努力创建一个程序,可以根据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;
}

2 个答案:

答案 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);
        }
    }
}