簡體   English   中英

通過BCD創建大數字-C ++

[英]Create big numbers by BCD - C++

我想創建代碼來幫助我獲得比MAXINT大的數字。 我聽說我可以使用二進制代碼十進制執行此操作,然后將較大數字的每兩個十進制數字(轉換為BCD)保留在char中。 但是該怎么做呢? 我應該將字符串作為輸入,然后以某種方式將每個十進制數字轉換為BCD? 以及如何將兩個轉換后的十進制數字轉換為一個字符? 我是C ++的新手,不知道該怎么辦。

PS我不想使用針對此類問題的“特殊”庫。

事實證明,這實際上很簡單。 我們如何將其提升到一個新的水平呢?

下面是一個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用戶不必處理向量位置以及所有龐然大物。 我們想要編寫行為類似的代碼:

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;
}

結語

在這里,我們有它。 當然,如果沒有加,乘等運算符,它不是很有用。 我把它們留作練習。 代碼,代碼和更多代碼,很快對您來說就像小菜一碟。

請隨時提出任何問題。 好的編碼!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM