Luhn 算法数字验证与生成工具
使用 Luhn 算法验证和生成数字,该算法通常用于信用卡号码、加拿大社会保险号码和其他身份证明号码。测试一个数字是否通过 Luhn 检查,或生成符合该算法的有效数字。
Luhn算法计算器
文档
Luhn 算法计算器
介绍
Luhn 算法,也称为“模 10”或“模 10”算法,是一种简单的校验和公式,用于验证各种识别号码,例如信用卡号码、加拿大社会保险号码、IMEI号码和美国国家提供者标识符号码。此计算器允许您使用 Luhn 算法验证号码并生成通过 Luhn 检查的有效号码。
Luhn 算法的工作原理
Luhn 算法的工作原理如下:
- 从右侧的数字开始(不包括校验位),向左移动,双倍每个第二位数字的值。
- 如果此双倍操作的结果大于 9,则从结果中减去 9。
- 将结果序列中的所有数字相加。
- 如果总和模 10 等于 0(如果总和以零结尾),则该号码根据 Luhn 公式是有效的;否则,它是无效的。
以下是 Luhn 算法的可视化表示:
公式
Luhn 算法可以用数学公式表示如下:
设 为第 位数字,从右侧数字开始(不包括校验位)并向左移动。然后选择校验位 使得:
其中 是模运算。
用例
Luhn 算法在不同领域有多种应用:
- 信用卡验证:大多数信用卡号码使用 Luhn 算法进行验证。
- 加拿大社会保险号码:Luhn 算法用于验证这些识别号码的有效性。
- IMEI号码:手机 IMEI号码包含一个由 Luhn 算法验证的校验位。
- 国家提供者标识符 (NPI)号码:在美国医疗系统中使用,这些号码通过 Luhn 算法进行验证。
- ISBN:一些 ISBN-10号码使用 Luhn 算法的变体进行验证。
替代方案
虽然 Luhn 算法被广泛使用,但还有其他校验和算法用于不同的目的:
- Damm 算法:另一种校验位算法,可以检测所有单个数字错误和所有相邻交换错误。
- Verhoeff 算法:一种更复杂的校验和算法,可以捕获所有单个数字错误和大多数交换错误。
- ISBN-13 校验位:使用与 ISBN-10 不同的算法,该算法基于 Luhn 算法。
历史
Luhn 算法由 IBM 计算机科学家汉斯·彼得·吕恩于 1954 年创建。吕恩是信息科学领域的先驱,因多项创新而闻名,包括 KWIC(上下文中的关键字)索引系统。
该算法最初旨在防止意外错误,而非恶意攻击。重要的是要注意,虽然 Luhn 算法可以检测许多常见错误,但它不是一种安全的加密形式,不应依赖于数据安全目的。
尽管年代久远,Luhn 算法仍因其简单性和有效性而广泛使用,能够捕获常见的抄写错误。
实现示例
以下是用不同编程语言实现 Luhn 算法的一些代码示例:
1import random
2
3def luhn_validate(number):
4 digits = [int(d) for d in str(number)]
5 checksum = 0
6 for i in range(len(digits) - 1, -1, -1):
7 d = digits[i]
8 if (len(digits) - i) % 2 == 0:
9 d = d * 2
10 if d > 9:
11 d -= 9
12 checksum += d
13 return checksum % 10 == 0
14
15def generate_valid_number(length):
16 digits = [random.randint(0, 9) for _ in range(length - 1)]
17 checksum = sum(digits[::2]) + sum(sum(divmod(d * 2, 10)) for d in digits[-2::-2])
18 check_digit = (10 - (checksum % 10)) % 10
19 return int(''.join(map(str, digits + [check_digit])))
20
21## 示例用法:
22print(luhn_validate(4532015112830366)) # True
23print(luhn_validate(4532015112830367)) # False
24print(generate_valid_number(16)) # 生成一个有效的 16 位数字
25
1function luhnValidate(number) {
2 const digits = number.toString().split('').map(Number);
3 let checksum = 0;
4 for (let i = digits.length - 1; i >= 0; i--) {
5 let d = digits[i];
6 if ((digits.length - i) % 2 === 0) {
7 d *= 2;
8 if (d > 9) d -= 9;
9 }
10 checksum += d;
11 }
12 return checksum % 10 === 0;
13}
14
15function generateValidNumber(length) {
16 const digits = Array.from({length: length - 1}, () => Math.floor(Math.random() * 10));
17 const checksum = digits.reduce((sum, digit, index) => {
18 if ((length - 1 - index) % 2 === 0) {
19 digit *= 2;
20 if (digit > 9) digit -= 9;
21 }
22 return sum + digit;
23 }, 0);
24 const checkDigit = (10 - (checksum % 10)) % 10;
25 return parseInt(digits.join('') + checkDigit);
26}
27
28// 示例用法:
29console.log(luhnValidate(4532015112830366)); // true
30console.log(luhnValidate(4532015112830367)); // false
31console.log(generateValidNumber(16)); // 生成一个有效的 16 位数字
32
1import java.util.Random;
2
3public class LuhnValidator {
4 public static boolean luhnValidate(long number) {
5 String digits = String.valueOf(number);
6 int checksum = 0;
7 boolean isEven = true;
8 for (int i = digits.length() - 1; i >= 0; i--) {
9 int digit = Character.getNumericValue(digits.charAt(i));
10 if (isEven) {
11 digit *= 2;
12 if (digit > 9) digit -= 9;
13 }
14 checksum += digit;
15 isEven = !isEven;
16 }
17 return checksum % 10 == 0;
18 }
19
20 public static long generateValidNumber(int length) {
21 Random random = new Random();
22 long[] digits = new long[length - 1];
23 for (int i = 0; i < length - 1; i++) {
24 digits[i] = random.nextInt(10);
25 }
26 long checksum = 0;
27 for (int i = digits.length - 1; i >= 0; i--) {
28 long digit = digits[i];
29 if ((length - 1 - i) % 2 == 0) {
30 digit *= 2;
31 if (digit > 9) digit -= 9;
32 }
33 checksum += digit;
34 }
35 long checkDigit = (10 - (checksum % 10)) % 10;
36 long result = 0;
37 for (long digit : digits) {
38 result = result * 10 + digit;
39 }
40 return result * 10 + checkDigit;
41 }
42
43 public static void main(String[] args) {
44 System.out.println(luhnValidate(4532015112830366L)); // true
45 System.out.println(luhnValidate(4532015112830367L)); // false
46 System.out.println(generateValidNumber(16)); // 生成一个有效的 16 位数字
47 }
48}
49
边缘案例和特殊考虑
在实现 Luhn 算法时,请考虑以下边缘案例和特殊考虑:
-
输入验证:确保输入是有效的数字字符串。应适当处理非数字字符(可以删除或视为无效输入)。
-
前导零:算法应能正确处理具有前导零的数字。
-
大数字:准备处理可能超出某些编程语言标准整数类型容量的非常长的数字。
-
空输入:定义您的实现应如何处理空字符串或 null 输入。
-
非标准字符集:在某些应用中,您可能会遇到以标准 0-9 范围之外的字符表示的数字。定义这些应如何处理。
-
性能考虑:对于需要快速验证大量输入的应用,请考虑优化算法实现。
数值示例
-
有效的信用卡号码:
- 号码:4532015112830366
- Luhn 检查:有效
-
无效的信用卡号码:
- 号码:4532015112830367
- Luhn 检查:无效
-
有效的加拿大社会保险号码:
- 号码:046 454 286
- Luhn 检查:有效
-
无效的 IMEI号码:
- 号码:490154203237518
- Luhn 检查:无效
测试用例
为了验证 Luhn 算法的实现,您可以使用以下测试用例:
1def test_luhn_algorithm():
2 assert luhn_validate(4532015112830366) == True
3 assert luhn_validate(4532015112830367) == False
4 assert luhn_validate(79927398713) == True
5 assert luhn_validate(79927398714) == False
6
7 # 测试生成的数字
8 for _ in range(10):
9 assert luhn_validate(generate_valid_number(16)) == True
10
11 print("所有测试通过!")
12
13test_luhn_algorithm()
14
参考文献
- Luhn, H. P. (1960). "计算机验证号码". 美国专利 2,950,048.
- Gallian, Joseph. "识别号码的数学". 《大学数学杂志》,第 22 卷,第 3 期,1991 年,第 194–202 页。JSTOR,www.jstor.org/stable/2686878.
- "ISO/IEC 7812-1:2017". 国际标准化组织。检索于 2024 年 8 月 2 日。
- Knuth, Donald. "计算机程序设计的艺术,第二卷:半数值算法". Addison-Wesley, 1997.
反馈
点击反馈提示开始对该工具进行反馈