【问题标题】:Decimal to binary without arrays and binary-operators (like "&")没有数组和二进制运算符的十进制到二进制(如“&”)
【发布时间】:2020-10-07 03:43:29
【问题描述】:

我必须为大学做一个任务,编写一个将十进制数转换为二进制数的程序。由于我只是在计算机科学的初级课程中,还没有引入数组或按位运算符(如“&”)。该程序只需要使用基本运算符 (+,-,*,%) 和 (if-else,for) 编写。我的方法如下,但我总是得到倒置的值。所以不是 1100, 0011。

#include <iostream>
int main()
{
   int n,a;
   std::cin >> n;
   
   for (int i=n; n>0; --i) {
       
     a = n%2;
     std::cout << a;
     n = n/2;
   
   }

   return 0;
}

有没有办法解决这个问题?

【问题讨论】:

  • 您需要从数字的最重要的一端开始,然后按自己的方式从头开始。你最近在课堂上讲过递归的概念吗?
  • 另见 - 其他一些显然正在从事相同任务的人 - *.com/questions/64162230/…
  • 堆栈是反转数字的好方法。在函数递归的情况下,事物隐式存储在调用堆栈中。但是可以使用循环和std::stack 而无需递归。
  • 所以你知道n%2n /= 2 会去掉最低位。您是否知道(n&gt;=x)n %= xx /= 2 会去掉最高位(假设您正确设置了x 以启动)。因此,使用一个循环正确设置x,然后使用另一个循环剥离并打印每个高位。

标签: c++


【解决方案1】:

您当前的代码检查从 LSB 到 MSB 的二进制值是否存在,并按该顺序打印。解决此问题的一种方法是改为检查从 MSB 到 LSB。

#include <iostream>
int main(){
  int n, a=1;
  std::cin >> n;

  while(2*a <= n)
    a *= 2;                                                                                                               
  while(a > 0){
    if (n >= a){
      std::cout << 1;
      n -= a;
    } else {
      std::cout << 0;
    }
    a /= 2;
  }
  std::cout << std::endl;
  return 0;
}

这不是一个很好的方法,我建议改进它或寻找替代方法作为练习。

【讨论】:

    【解决方案2】:

    如果您知道您只能反向获得正确的输出,请考虑您可以采取哪些措施来解决该问题。只需反转位。这是一种仅使用基本功能的方法。

    #include <iostream>
    int main()
    {
       int n,a;
       int bitCount = 0;
       std::string reversedBits;
       std::cin >> n;
       
       for (int i=n; n>0; --i) {
         a = n % 2;
         reversedBits += a + '0';
         ++bitCount;
         n = n / 2;
       }
    
       for (int i = bitCount - 1; i >= 0; --i) {
           std::cout << reversedBits[i];
       }
    
       return 0;
    }
    

    这并不是说这是最好的方法。找出解决此问题的一些方法对您来说是一个很好的练习。

    【讨论】:

    • 如果不允许使用数组,那么std::string(本质上是一个字符数组,具有额外功能)也很有可能被淘汰。
    • 啊,完全错过了那部分。
    【解决方案3】:

    我将提出一个非常简单的解决方案,该解决方案本质上是纯粹的算术运算,不涉及任何你可以用来解决这个问题的位级黑客,也不涉及你的课程中没有涉及的数组。正如您所观察到的,您的方法为您提供了相反的二进制数。不要直接打印您获得的数字,而是使用整数将计算的数字放置在正确的位置,以正确的顺序保存计算的数字。

    考虑一下这个sn-p:

    #include <iostream>
    
    int main()
    {
       int n,a;
       int result = 0;
       int position = 1;
    
       std::cin >> n;
       
       for (int i=n; n>0; --i) {
         a = n%2;
         n = n/2;
         
         result += position * a;
         position *= 10;
       }
       
       std::cout << result << std::endl;    
       return 0;
    }
    

    跟踪输入 12 的示例:

    1. 第一次迭代:a 为零,所以 Result = 0,位置从 1 更新为 10
    2. 第二次迭代:a又为零,所以Result = 0,位置从10更新到100
    3. 第三次迭代:a 不为零,因此 Result 现在为 100(位置 * 1),位置从 100 更新为 1000
    4. 第四次迭代:a 非零,Result 变为 100 + 1000 = 1100,位置从 1000 更新为 10000

    【讨论】:

    • 正确的方法,但您需要在此处使用string 或类似名称。将整个 32 位 int 转换为二进制数,他们按照您的方式完成它需要一个能够保存 32 位数字的整数类型。一个 32 位的int 只能容纳 10 个。
    • 完全同意你的看法。我只使用 int 而不是功能更强大的数据类型的原因只是因为问题的作者只是在做初步课程,我不确定他们是否接触过其他数据类型。只是想传达这种方法。 :)
    【解决方案4】:

    这里我提供一个递归解决方案。

    我还使用 argv 允许在命令行上进行多个输入,每个输入可以是十进制文本或十六进制文本。

    我使用 stringstream,而不是 cin。请注意,它们都继承了相同的流输入操作。

    #include <iostream>
    using std::cout, std::cerr, std::endl, std::hex, std::dec;
    
    #include <string>
    using std::string;
    
    #include <sstream>
    using std::stringstream, std::istringstream;
    
    #include <cstdint>
    
    
    //  typical output    vvvvv      v   v   v   v   v
    //  n:   7340032   0x700000   11100000000000000000000
    
    //  commands -- both the same input value
    //  ./dumy899d 7340032
    //  ./dumy899d 0x700000
    //
    //  which can be mixed in the same argv list:
    //  ./dumy899d  7340032  0x700000
    
    
    
    // recursion max depth: bit width of n (32 on my system)
    void to_binary_R (string& retVal, int n)
    {
      if (0 == n)  return;        // recursion termination clause
      to_binary_R (retVal, n/2);  // (n / 2) shifts all bits of n to right 
    
      // n is on the stack and will be unchanged when the PC returns,
      // thus, during 'decurse':
      int a = (n % 2)   +  '0';  // do computation, a is 0x30 or 0x31
      //  int (0 or 1)    0x30 -- char is auto promoted to int
    
      retVal += static_cast<char>(a);  // append-to-retVal
      //        no-code-cast: 30, 31 become chars '0', '1' with cast
    }
    
    // i sometimes prefer to return a string 
    //    (this can enable reducing cout-pollution)
    
    string to_binary(int n) 
    {
      string s; s.reserve(64); // declare & reserve space
      to_binary_R(s, n);       // fill
      return s;
    }    
    
    // forward declartions
    // returns true when user input has '0x' 
    bool hexUI(const string& s);
    
    void usage(); 
    
    
    int main(int argc, char* argv[])
    {
      if (argc < 2) { usage(); return -1; }
    
      for (int indx = 1; indx < argc; ++indx)
      {
        char* arg = argv[indx];  // instead of std::cin >> n;
    
        stringstream ss(arg);
    
        int nOrig = 0;
    
        if (hexUI(arg)) { ss >> hex >> nOrig; } 
        else            { ss >> dec >> nOrig; } 
    
        if (!ss.good() && !ss.eof()) // when not good state that is not
        {                            // caused by eof()
          // notify user:
          cerr << "\n\n ERR: ss is not good() (and not eof) "
               << "Maybe a hex parameter prefix is missing '0x'?\n" 
               << endl;
          return -2;
        }
    
        cout << "\n  n:   " << dec << nOrig
             << "   0x"     << hex << nOrig
             << "   "       << to_binary(nOrig)
             << endl;
    
      } // for (int indx = 1; indx < argc; ++indx)
    
      return 0;
    } // int main()
    
    
    // returns true when user input specifies hex with '0x' prefix
    bool hexUI(const string& s) { return (s.find("0x") != string::npos); }
    
    void usage()
    {
      cerr << "\n  err:  expecting 1 or more command line arguments, each argument is "
           << "\n        either decimal-text or hex-text (marked with '0x' prefix) "
           << "\n        values are displayed in decimal, binary, and hex"
           << endl;
    
      cout << "\n  The following info might be different on your system:"
           << "\n  My development system: Linux 20.04, using g++ v9.3.0";
    
      cout << "\n             sizeof(int) : "
           << sizeof(int) << " bytes    "         // 4  bytes
           << (sizeof(int) * 8) << " bits";       // 32 bits
    
      cout << "\n        sizeof(long int) : "
           << sizeof(long int) << " bytes    "    // 8 bytes
           << (sizeof(long int) * 8) << " bits";  // 64 bits
    
      // consider specifying the size, such as
      cout << "\n         sizeof(int64_t) : "
           << sizeof(int64_t) << " bytes    "     // 8 bytes
           << (sizeof(int64_t) * 8) << " bits"    // 64 bits
           << endl;
    }
    

    【讨论】:

    • 注意这个递归非常小。在我的系统上,int 是 32 位,设置了一个非常小的最大递归深度。它从最低有效数字开始工作(如发布代码),因此它在 n == 0 时立即退出。
    【解决方案5】:

    有没有办法解决这个问题?

    我想到了另一种方法,分三个步骤。

    string toHex_ToBin(int n, bool slz)
    {
      // STEP 1: create hex encoding using stringstream and hex
      stringstream ss;
      ss << hex << n;
    
      string s = ss.str();
    
      // STEP 2: use these hex chars to append corresponding binary codes
      //         to empty return string
      string m_s; 
      for (uint i = 0; i < s.size(); ++i)
      {
        switch (toupper(s[i]))
        {
        case '0': { m_s += "0000"; break; }
        case '1': { m_s += "0001"; break; }
        case '2': { m_s += "0010"; break; }
        case '3': { m_s += "0011"; break; }
        case '4': { m_s += "0100"; break; }
        case '5': { m_s += "0101"; break; }
        case '6': { m_s += "0110"; break; }
        case '7': { m_s += "0111"; break; }
        case '8': { m_s += "1000"; break; }
        case '9': { m_s += "1001"; break; }
        case 'A': { m_s += "1010"; break; }
        case 'B': { m_s += "1011"; break; }
        case 'C': { m_s += "1100"; break; }
        case 'D': { m_s += "1101"; break; }
        case 'E': { m_s += "1110"; break; }
        case 'F': { m_s += "1111"; break; }
        // default: assert(0); break; 
        }  
        // I leave this question to the reader, "would a 
        // vector<string> hex2bin = {"0000", "0001", .. "1111"};
        // simplify this effort? "
      } // for loop
    
      // STEP 3 - if requested by user (via bool slz)
      if(slz) // suppress leading zero's
      {
        size_t pos = m_s.find('1'); // find left most one
        if (pos != std::string::npos)
          m_s.erase(0, pos);
      }
      return m_s;
    }
    

    【讨论】: