将 CheckSum 与 C++ 一起用于 13 位 ISBN
Using CheckSum with C++ for 13 Digit ISBN
我正在尝试使用 C++ 使用前 12 位计算 13 位 ISBN 的最后一位。我觉得我的代码应该是正确的,但我感觉我使用的公式可能是错误的。
公式为:
10 - (d0 + d1 * 3 + d2 + d3 * 3 + d4 + d5 * 3 + d6 + d7 * 3 + d8 + d9 * 3 + d10 + d11 * 3) % 10
这是我拥有的:
#include <cstring>
#include <iostream>
int main() {
int weightedSum = 0;
int checksum = 0;
int i; //for loop decrement
int mul = 3;
const int LENGTH = 12;
char ISBNinput[LENGTH];
std::cout << "Enter first 12 digits of ISBN: "; //ask user for input
std::cin >> ISBNinput; //stores input into ISBNinput
std::cout << std::endl;
for (i = 0; i < strlen(ISBNinput); i++) {
weightedSum += (ISBNinput[i] % 12) * mul;
if (mul == 3) {
mul = 1;
} else {
mul = 3;
}
}//close for loop
checksum = weightedSum % 10; //calculates checksum from weightedSum
std::cout << checksum << std::endl; //prints checksum with new line for format
return 0;
}
例如:
978007063546 应该 return 3
和
978032133487 应该 return 9
感谢您的帮助。
您的代码中有一个明显的错误:您没有为 ISBNinput
分配足够的 space。你应该把它加长一个字符:
const int LENGTH = 13;
原因是字符数组字符串以额外的空字符结尾。你可能很幸运,内存中的下一个字节有时恰好是一个空字节,在这种情况下,程序有时仍然可以运行。
如果您 运行 使用 valgrind 或类似内存检查程序的程序,您可能会看到一个错误,因为程序访问的内存超出了堆栈上分配的内存。
另外我认为还有一个错误。我认为 mul
应该初始化为 1
.
顺便说一下,这段代码很脆弱,取决于你输入的字符不超过12个,所有字符都被假定为数字。作为概念验证的快速破解可能没问题,但不应在任何实际程序中使用。
我是这样处理的。
首先,让我们决定如何对此进行测试。我假设我们已经编写了函数,并且它给出了正确的输出。所以我从桌上拿起几本书,测试它是否适合他们:
#include <iostream>
int main()
{
std::cout << "Book 1 - expect 3, got " << checksum("978032114653") << std::endl;
std::cout << "Book 2 - expect 0, got " << checksum("978020163361") << std::endl;
}
当然,当我们尝试编译它时,我们得到了一个错误。所以在 main()
:
之前创建函数
char checksum(const char *s)
{
return '1';
}
现在可以编译了,但是结果总是1
,但是现在我们可以开始填充正文了。让我们从一些较小的例子开始,我们可以手工计算;在 main()
的开头添加这些:
std::cout << "1 digit - expect 4, got " << checksum("6") << std::endl;
现在让我们开始这个工作 - 这至少让我们从字符到数字再返回:
char checksum(const char *s)
{
int digit = *s - '0';
return '0' + 10 - digit;
}
让我们试试 2 位数:
std::cout << "1 digit - expect 6, got " << checksum("11") << std::endl;
现在我们的测试又失败了。所以添加一些更多的处理,使这个通过(而不是打破个位数测试):
char checksum(const char *s)
{
int sum = 0;
int digit = *s - '0';
sum += digit;
++s;
if (*s) {
digit = *s - '0';
sum += 3 * digit;
}
return '0' + (10 - sum)%10;
}
我们现在可能已准备好将其变成一个循环。一旦通过,我们就不再需要简短的测试了,我有:
#include <iostream>
char checksum(const char *s)
{
int sum = 0;
for (int mul = 1; *s; ++s) {
int digit = *s - '0';
sum += mul * digit;
mul = 4 - mul;
}
return '0' + (1000 - sum)%10;
}
int test(const char *name, char expected, const char *input)
{
char actual = checksum(input);
if (actual == expected) {
std::cout << "PASS: " << name << ": "
<< input << " => " << actual
<< std::endl;
return 0;
} else {
std::cout << "FAIL: " << name << ": "
<< input << " => " << actual
<< " - expected " << expected
<< std::endl;
return 1;
}
}
int main()
{
int failures = 0;
failures += test("Book 1", '3', "978032114653");
failures += test("Book 2", '0', "978020163361");
return failures > 0;
}
我在这里将实际检查分解为一个函数,因此我们可以记录失败次数,并以适当的状态退出,但其他一切都如我上面所述。
您需要添加更多测试用例 - 特别是,确保函数正确地 returns 极值 0
和 9
在它应该的时候。
我正在尝试使用 C++ 使用前 12 位计算 13 位 ISBN 的最后一位。我觉得我的代码应该是正确的,但我感觉我使用的公式可能是错误的。
公式为:
10 - (d0 + d1 * 3 + d2 + d3 * 3 + d4 + d5 * 3 + d6 + d7 * 3 + d8 + d9 * 3 + d10 + d11 * 3) % 10
这是我拥有的:
#include <cstring>
#include <iostream>
int main() {
int weightedSum = 0;
int checksum = 0;
int i; //for loop decrement
int mul = 3;
const int LENGTH = 12;
char ISBNinput[LENGTH];
std::cout << "Enter first 12 digits of ISBN: "; //ask user for input
std::cin >> ISBNinput; //stores input into ISBNinput
std::cout << std::endl;
for (i = 0; i < strlen(ISBNinput); i++) {
weightedSum += (ISBNinput[i] % 12) * mul;
if (mul == 3) {
mul = 1;
} else {
mul = 3;
}
}//close for loop
checksum = weightedSum % 10; //calculates checksum from weightedSum
std::cout << checksum << std::endl; //prints checksum with new line for format
return 0;
}
例如:
978007063546 应该 return 3
和
978032133487 应该 return 9
感谢您的帮助。
您的代码中有一个明显的错误:您没有为 ISBNinput
分配足够的 space。你应该把它加长一个字符:
const int LENGTH = 13;
原因是字符数组字符串以额外的空字符结尾。你可能很幸运,内存中的下一个字节有时恰好是一个空字节,在这种情况下,程序有时仍然可以运行。
如果您 运行 使用 valgrind 或类似内存检查程序的程序,您可能会看到一个错误,因为程序访问的内存超出了堆栈上分配的内存。
另外我认为还有一个错误。我认为 mul
应该初始化为 1
.
顺便说一下,这段代码很脆弱,取决于你输入的字符不超过12个,所有字符都被假定为数字。作为概念验证的快速破解可能没问题,但不应在任何实际程序中使用。
我是这样处理的。
首先,让我们决定如何对此进行测试。我假设我们已经编写了函数,并且它给出了正确的输出。所以我从桌上拿起几本书,测试它是否适合他们:
#include <iostream>
int main()
{
std::cout << "Book 1 - expect 3, got " << checksum("978032114653") << std::endl;
std::cout << "Book 2 - expect 0, got " << checksum("978020163361") << std::endl;
}
当然,当我们尝试编译它时,我们得到了一个错误。所以在 main()
:
char checksum(const char *s)
{
return '1';
}
现在可以编译了,但是结果总是1
,但是现在我们可以开始填充正文了。让我们从一些较小的例子开始,我们可以手工计算;在 main()
的开头添加这些:
std::cout << "1 digit - expect 4, got " << checksum("6") << std::endl;
现在让我们开始这个工作 - 这至少让我们从字符到数字再返回:
char checksum(const char *s)
{
int digit = *s - '0';
return '0' + 10 - digit;
}
让我们试试 2 位数:
std::cout << "1 digit - expect 6, got " << checksum("11") << std::endl;
现在我们的测试又失败了。所以添加一些更多的处理,使这个通过(而不是打破个位数测试):
char checksum(const char *s)
{
int sum = 0;
int digit = *s - '0';
sum += digit;
++s;
if (*s) {
digit = *s - '0';
sum += 3 * digit;
}
return '0' + (10 - sum)%10;
}
我们现在可能已准备好将其变成一个循环。一旦通过,我们就不再需要简短的测试了,我有:
#include <iostream>
char checksum(const char *s)
{
int sum = 0;
for (int mul = 1; *s; ++s) {
int digit = *s - '0';
sum += mul * digit;
mul = 4 - mul;
}
return '0' + (1000 - sum)%10;
}
int test(const char *name, char expected, const char *input)
{
char actual = checksum(input);
if (actual == expected) {
std::cout << "PASS: " << name << ": "
<< input << " => " << actual
<< std::endl;
return 0;
} else {
std::cout << "FAIL: " << name << ": "
<< input << " => " << actual
<< " - expected " << expected
<< std::endl;
return 1;
}
}
int main()
{
int failures = 0;
failures += test("Book 1", '3', "978032114653");
failures += test("Book 2", '0', "978020163361");
return failures > 0;
}
我在这里将实际检查分解为一个函数,因此我们可以记录失败次数,并以适当的状态退出,但其他一切都如我上面所述。
您需要添加更多测试用例 - 特别是,确保函数正确地 returns 极值 0
和 9
在它应该的时候。