银行卡号码校验算法

银行卡号码校验算法

背景

最近在办卡的时候发现,两个相邻的人办卡,他们的卡号乍一看并不是连续的,但是把最后一位除掉之后却是连续的,很容易猜想最后一位应该是校验位。

银行卡号码的校验规则

银行卡号码的校验采用Luhn算法,假设有银行卡号如下:

alt text

图1

我们使用不同的颜色对奇数和偶数部分进行区分。

红色部分表示从右往左数奇数位,蓝色部分表示从右往左数偶数位。

对于偶数位(蓝色部分),我们保留原数:

\[f\left(x\right) = x \]

constexpr auto even = [](int x) {
    return x;
};

对于奇数位(红色部分),我们假设\(g\left(x\right)\)表示\(x\)的各位数之和,则有:

\[f\left(x\right) = g\left(2x\right) \]

constexpr auto odd = [](int x) {
    x *= 2;
    return x / 10 + x % 10;
};

这样我们就获得了每一位数字变化后的结果

constexpr auto check_digit = [](auto&& idx_and_digit) {
    auto [idx, digit] = idx_and_digit;
    int x = digit - '0';
    // Since C++ started with 0, we swap even and odd.
    return idx & 1 ? even(x) : odd(x);
};

最后我们将每个奇数位和偶数位对应的结果全部相加并对\(10\)取余,如果余数为\(0\)则校验位为\(0\),否则用\(10\)减去余数,即:

\[ s = Result \mod 10 \\ S(x)=\left\{ \begin{aligned} 0 & , & if\ s = 0, \\ 10 - s & , & otherwise \end{aligned} \right. \]

constexpr int Luhn(std::string_view numbers) 
{
    auto rg = numbers | std::views::reverse | std::views::enumerate | std::views::transform(check_digit);

    int digit_sum = std::ranges::fold_left(rg, 0, std::plus<>()) % 10;

    return digit_sum == 0 ? 0 : 10 - digit_sum;
}

代码

// https://en.wikipedia.org/wiki/Luhn_algorithm

#include <string_view>
#include <ranges>
#include <algorithm>
#include <cstdlib>
#include <functional>

constexpr auto odd = [](int x) {
    x *= 2;
    return x / 10 + x % 10;
};

constexpr auto even = [](int x) {
    return x;
};

constexpr auto check_digit = [](auto&& idx_and_digit) {
    auto [idx, digit] = idx_and_digit;
    int x = digit - '0';
    return idx & 1 ? even(x) : odd(x); // Since C++ started with 0, we swap even and odd.
};

constexpr int Luhn(std::string_view numbers) 
{
    auto rg = numbers | std::views::reverse | std::views::enumerate | std::views::transform(check_digit);

    int digit_sum = std::ranges::fold_left(rg, 0, std::plus<>()) % 10;

    return digit_sum == 0 ? 0 : 10 - digit_sum;
}

int main(int argc, char const *argv[])
{
    static_assert(Luhn("62122802001416649") == 7);
    return 0;
}

posted @ 2024-02-25 15:07  鸿钧三清  Views(172)  Comments(0Edit  收藏  举报