Credit 信用额度
Problem to Solve 待解决的问题
A credit (or debit) card, of course, is a plastic card with which you can pay for goods and services. Printed on that card is a number that’s also stored in a database somewhere, so that when your card is used to buy something, the creditor knows whom to bill. There are a lot of people with credit cards in this world, so those numbers are pretty long: American Express uses 15-digit numbers, MasterCard uses 16-digit numbers, and Visa uses 13- and 16-digit numbers. And those are decimal numbers (0 through 9), not binary, which means, for instance, that American Express could print as many as 10^15 = 1,000,000,000,000,000 unique cards! (That’s, um, a quadrillion.)
信用卡(或借记卡)显然是一种塑料卡,您可以用它来支付商品和服务。卡片上印有一个数字,该数字也存储在某个数据库中,因此,当您使用卡片购买物品时,债权人就知道该向谁收费。这个世界上持有信用卡的人数众多,因此这些数字相当长:美国运通使用 15 位数字,万事达卡使用 16 位数字,而 Visa 则使用 13 位和 16 位数字。这些都是十进制数字(0 到 9),而不是二进制,这意味着,例如,美国运通最多可以发行 10^15 = 1,000,000,000,000,000 张独特的卡片!(也就是,一个千万亿。)
Actually, that’s a bit of an exaggeration, because credit card numbers actually have some structure to them. All American Express numbers start with 34 or 37; most MasterCard numbers start with 51, 52, 53, 54, or 55 (they also have some other potential starting numbers which we won’t concern ourselves with for this problem); and all Visa numbers start with 4. But credit card numbers also have a “checksum” built into them, a mathematical relationship between at least one number and others. That checksum enables computers (or humans who like math) to detect typos (e.g., transpositions), if not fraudulent numbers, without having to query a database, which can be slow. Of course, a dishonest mathematician could certainly craft a fake number that nonetheless respects the mathematical constraint, so a database lookup is still necessary for more rigorous checks.
实际上,这有些夸张,因为信用卡号码其实是有一定结构的。所有美国运通卡的号码以 34 或 37 开头;大多数万事达卡的号码以 51、52、53、54 或 55 开头(它们还有一些其他可能的开头号码,但在这里我们就不讨论了);而所有维萨卡的号码则以 4 开头。然而,信用卡号码内置了一个“校验和”,这是一个至少涉及一个数字与其他数字之间的数学关系。这个校验和能够帮助计算机(或喜欢数学的人)检测错别字(例如,字符位置调换),甚至可以在不需要查询数据库的情况下识别出可能的欺诈号码,因为数据库查询可能会比较慢。 当然,一个不诚实的数学家可以确实制造出一个虚假的数字,而这个数字仍然遵循数学限制,因此为了进行更严格的检查,仍然需要进行数据库查询。
In a file called credit.c
in a folder called credit
, implement a program in C that checks the validity of a given credit card number.
在名为 credit
的文件夹中,创建一个名为 credit.c
的文件,并在其中用 C 语言实现一个程序,用于检查给定的信用卡号码是否有效。
Luhn’s Algorithm 吕恩算法
So what’s the secret formula? Well, most cards use an algorithm invented by Hans Peter Luhn of IBM. According to Luhn’s algorithm, you can determine if a credit card number is (syntactically) valid as follows:
那么,秘诀是什么呢?大多数信用卡使用的是 IBM 的汉斯·彼得·卢恩发明的算法。根据卢恩算法,您可以通过以下步骤判断信用卡号是否(语法上)有效:
- Multiply every other digit by 2, starting with the number’s second-to-last digit, and then add those products’ digits together.
从倒数第二位数字开始,每隔一个数字乘以 2,然后将所有乘积的数字相加。 - Add the sum to the sum of the digits that weren’t multiplied by 2.
将这个和加上未乘以 2 的数字的和。 - If the total’s last digit is 0 (or, put more formally, if the total modulo 10 is congruent to 0), the number is valid!
如果总和的最后一位是 0(或者说,总和除以 10 的余数为 0),那么这个数字就是有效的!
That’s kind of confusing, so let’s try an example with David’s Visa: 4003600000000014.
这有点让人糊涂,我们用 David 的 Visa 卡号举例说明:4003600000000014。
-
For the sake of discussion, let’s first underline every other digit, starting with the number’s second-to-last digit:
为了讨论,让我们先从数字的倒数第二个数字开始,每隔一个数字划线4003600000000014
Okay, let’s multiply each of the underlined digits by 2:
好的,我们把每个带下划线的数字乘以 2:1•2 + 0•2 + 0•2 + 0•2 + 0•2 + 6•2 + 0•2 + 4•2
1 乘以 2 + 0 乘以 2 + 0 乘以 2 + 0 乘以 2 + 0 乘以 2 + 6 乘以 2 + 0 乘以 2 + 4 乘以 2That gives us: 这让我们得到了:
2 + 0 + 0 + 0 + 0 + 12 + 0 + 8
Now let’s add those products’ digits (i.e., not the products themselves) together:
现在让我们把这些产品的数字(而不是产品本身)加在一起:2 + 0 + 0 + 0 + 0 + 1 + 2 + 0 + 8 = 13
2 加 0 加 0 加 0 加 0 加 1 加 2 加 0 加 8 等于 13 -
Now let’s add that sum (13) to the sum of the digits that weren’t multiplied by 2 (starting from the end):
现在,我们将这个总和 (13) 加到从末尾开始没有乘以 2 的数字的总和上13 + 4 + 0 + 0 + 0 + 0 + 0 + 3 + 0 = 20
-
Yup, the last digit in that sum (20) is a 0, so David’s card is legit!
没错,那个总和(20)的最后一位是 0,所以大卫的卡片是真的!
So, validating credit card numbers isn’t hard, but it does get a bit tedious by hand. Let’s write a program.
因此,验证信用卡号码并不困难,但手动操作会有些繁琐。我们来写一个程序吧。
Implementation Details 实施细节说明
In the file called credit.c
in the credit
directory, write a program that prompts the user for a credit card number and then reports (via printf
) whether it is a valid American Express, MasterCard, or Visa card number, per the definitions of each’s format herein. So that we can automate some tests of your code, we ask that your program’s last line of output be AMEX\n
or MASTERCARD\n
or VISA\n
or INVALID\n
, nothing more, nothing less. For simplicity, you may assume that the user’s input will be entirely numeric (i.e., devoid of hyphens, as might be printed on an actual card) and that it won’t have leading zeroes. But do not assume that the user’s input will fit in an int
! Best to use get_long
from CS50’s library to get users’ input. (Why?)
在名为 credit.c
的文件中,在 credit
目录下编写一个程序,提示用户输入信用卡号码,然后通过 printf
报告该号码是否有效的美国运通、万事达卡或 Visa 卡。为了便于自动化测试,我们要求程序最后输出的内容仅为 AMEX\n
、 MASTERCARD\n
、 VISA\n
或 INVALID\n
,不多不少。为了简化处理,您可以假设用户的输入完全是数字(即没有连字符,就像实际卡片上可能印刷的样式),且没有前导零。但请不要假设用户输入的数字可以放入 int
中!最好使用来自 CS50 库的 get_long
来获取用户输入。(为什么?)
Consider the below representative of how your own program should behave when passed a valid credit card number (sans hyphens).
请参考以下示例,了解你的程序在输入有效信用卡号码(不带连字符)时应该如何运作。
$ ./credit
Number: 4003600000000014
VISA
Now, get_long
itself will reject hyphens (and more) anyway:
现在, get_long
本身就会拒绝连字符(以及更多):
$ ./credit
Number: 4003-6000-0000-0014
Number: foo
Number: 4003600000000014
VISA
But it’s up to you to catch inputs that are not credit card numbers (e.g., a phone number), even if numeric:
但是,即使是数字,你也需要捕获非信用卡号码的输入(例如,电话号码):
$ ./credit
Number: 6176292929
INVALID
Test out your program with a whole bunch of inputs, both valid and invalid. (We certainly will!) Here are a few card numbers that PayPal recommends for testing.
请用各种有效和无效的输入来测试您的程序。(我们当然会这样做!) 这里是一些 PayPal 推荐用于测试的卡号。
If your program behaves incorrectly on some inputs (or doesn’t compile at all), time to debug!
如果您的程序在某些输入下出现错误(或者根本无法编译),是时候进行调试了!
Walkthrough 操作指南
How to Test Your Code
如何对你的代码进行测试
You can also execute the below to evaluate the correctness of your code using check50
. But be sure to compile and test it yourself as well!
你也可以执行以下命令,使用 check50
来评估代码的正确性。但请务必自己编译并测试!
Correctness 正确性
In your terminal, execute the below to check your work’s correctness.
在您的终端里,执行以下命令来检查您的工作是否正确。
check50 cs50/problems/2024/x/credit
Style 样式
Execute the below to evaluate the style of your code using style50
.
使用 style50
以下内容评估您的代码风格。
style50 credit.c
How to Submit 提交的方法
In your terminal, execute the below to submit your work.
在终端中运行以下命令以提交你的工作。
submit50 cs50/problems/2024/x/credit