我想创建能帮助我获得大于MAXINT的数字的代码。我听说我可以使用二进制代码十进制来执行此操作,然后更大数字的每两个十进制数字(转换为BCD)保留在char中。但是怎么做呢?我应该给字符串作为输入,然后以某种方式将每个十进制数转换为BCD?如何将两个转换后的十进制数放入一个char?我是C ++新手,不知道我该怎么做。
P.S。我不想使用特殊的#34;对于那种问题。
答案 0 :(得分:1)
事实证明,这实际上非常简单。我们试着把它提升到一个新的水平怎么样?
以下是具有无限(或内存可容纳)大小的BCD编号的实现。它只支持正整数。我将继续扩展这个以支持负数(或实数)作为练习。
首先要做的事情是:是的,我们希望将我们的数字作为字符串,然后从中构建它。因为它只是一个整数,所以这实际上很容易做到。我们主要创建一个辅助函数来帮助我们识别所有数字。
int char_to_int(const char c) {
int ret = c - '0';
if(ret > 9 || ret < 0) throw 1; // for simplicity. Use a class derived from std::exception instead.
return ret;
}
我们现在可以尝试为我们的大号码实现输入和输出。
有了那个助手,将字符串转换为BCD编码的缓冲区很容易。常见的实现可能如下所示:
int main() {
unsigned char bignum[10]; // stores at most 20 BCD digits.
std::memset(bignum, 0, sizeof(bignum));
std::string input;
std::cin >> input;
try {
if (input.size() > 20) throw 1; // Avoid problems with buffer overflow.
for (int i=1;i<=input.size();i++) {
int n = char_to_int(input[input.size()-i]);
bignum[sizeof(bignum) - (i+1)/2] |= n << (i%2)*4; // These are bitwise operations. Google them!
}
}
catch(int) {
std::cout << "ERROR: Invalid input.\n";
return 0; // Exit cleanly.
}
// bignum is now filled. Let's print it to prove.
for (int i=0;i<sizeof(bignum);i++) {
int first_digit = bignum[i] & '\x0F'; // Right side, doesn't need to shift.
int second_digit = (bignum[i] & '\xF0')>>4; // Left side, shifted.
std::cout << first_digit << second_digit;
}
}
然而,这不是很节省空间。请注意,我们必须存储所有20位数字,即使我们的数字很小!如果我们需要1000位数怎么办?如果我们需要1000个可能有或没有这1000个数字的数字怎么办?它也容易出错:看看我们必须重新构造初始化数组,并在转换之前进行边界检查以避免缓冲区溢出。
我们可以使用std :: vector改进我们的实现:
int main() {
std::vector<unsigned char> bignum; // stores any quantity of digits.
std::string input;
std::cin >> input;
try {
// For an odd number of digits we want a trailling zero at the end.
if(input.size()%2) n.num_vec.push_back(char_to_int(input[0]));
for (unsigned i=input.size()%2;i<input.size();i+=2) {
int left = char_to_int(input[i]);
int right = char_to_int(input[i+1]);
n.num_vec.push_back(0);
n.num_vec.back() = left << 4;
n.num_vec.back() |= right;
}
}
catch(int) {
std::cout << "ERROR: Invalid input.\n";
exit(0); // Exit cleanly.
}
// bignum is now filled. Let's print it to prove.
for (unsigned i=0;i<bignum.size();++i) {
// Notice that we inverted this from the previous one! Try to think why.
int first_digit = (bignum[i] & '\xF0')>>4; // Left side, shifted.
int second_digit = bignum[i] & '\x0F'; // Right side, doesn't need to shift.
if(i || first_digit) std::cout << first_digit; // avoid printing trailling 0.
std::cout << second_digit;
}
}
看起来很好,但这太麻烦了。理想情况下,bignumber用户不应该处理向量位置和所有那些mumbo-jumbo。我们想编写行为类似的代码:
int main() {
int a;
cin >> a;
cout << a;
}
它应该有用。
原来这是可能的!只需将bignum包装成一个类,并使用一些有用的操作符:
class bignum {
std::vector<unsigned char> num_vec;
template<typename T>
friend T& operator<<(T& is, bignum& n);
template<typename T>
friend T& operator>>(T& os, bignum& n);
};
// Get input from any object that behaves like an std::istream (i.e.: std::cin)
template<typename T>
T& operator>>(T& is, bignum& n) {
std::string input;
is >> input;
n.num_vec.reserve(input.size());
if(input.size()%2) n.num_vec.push_back(char_to_int(input[0]));
for (unsigned i=input.size()%2;i<input.size();i+=2) {
int left = char_to_int(input[i]);
int right = (i+1) != input.size()?char_to_int(input[i+1]):0; // If odd number of digits, avoid getting garbage.
n.num_vec.push_back(0);
n.num_vec.back() = left << 4;
n.num_vec.back() |= right;
}
return is;
}
// Output to any object that behaves like an std::ostream (i.e.: std::cout)
template<typename T>
T& operator<<(T& os, bignum& n) {
for (unsigned i=0;i<n.num_vec.size();++i) {
int first_digit = (n.num_vec[i] & '\xF0')>>4; // Left side, shifted.
int second_digit = n.num_vec[i] & '\x0F'; // Right side, doesn't need to shift.
if(i || first_digit) os << first_digit; // avoid printing trailling 0.
os << second_digit;
}
return os;
}
然后我们的主要功能看起来更具可读性:
int main() {
bignum a;
try {
std::cin >> a;
}
catch(int) {
std::cout << "ERROR: Invalid input.\n";
return 0; // Exit cleanly.
}
std::cout << a;
}
在这里我们拥有它。当然没有添加,乘法等运算符,它不是很有用。我会把它们留作练习。代码,代码和代码更多,很快这对你来说就像是小菜一碟。
请随时提出任何问题。好编码!