【问题标题】:The particular digit in the number of total总数中的特定数字
【发布时间】:2013-12-16 15:37:37
【问题描述】:

当你有这样的定义时:

int variable = 253243243;

我可以以某种方式引用这个数字中的第三个数字吗?类似于向量或数组的东西?我需要这个来比较数字中的某个数字是否对应于用户给出的不同数字。有可能吗?

【问题讨论】:

  • 这个问题没有错。为什么投反对票?
  • 业力平衡恢复:)
  • 从左数第三位还是从右数?下面的几个答案从右边数起。除非您只是将值打印到字符串并索引该字符串,否则从左侧执行此操作有点棘手。
  • @Ali:因为它没有显示研究工作(这是拒绝投票按钮描述的一部分)。它没有提到尝试的解决方案以及出了什么问题。这些不是 StackOverflow 上问题的可选功能。

标签: c++ int digit


【解决方案1】:

variable % 1000 / 100 取第三位

【讨论】:

    【解决方案2】:

    一个通用公式是:

    (number % pow(base, the_digit_you_want)) / pow(base, the_digit_you_want - 1) 
    

    您还必须注意将 trunc/cast 转换为 int。

    【讨论】:

      【解决方案3】:

      您可以结合使用%/ 操作来提取数字。

      或者,您可以使用stringstream 将数字打印到string 并从字符串中提取数字作为字符:

      std::stringstream ss;
      ss << variable;
      std::string s = ss.str();
      unsigned char first = s[0] - '0'; // this is the first digit (from left)
      unsigned char second = s[1] - '0'; // this is the second digit (from left)
      

      或者,如果您有幸使用符合 C++11 的编译器,您可以使用 std::string::to_string 函数而不是 std::stringstream

      【讨论】:

      • 我要指出的是,使用这种方法时,数字会不直观地颠倒。 ss.c_str()[0] 是最左边的数字。
      • 或者直接使用std::to_string
      • @Casey 你怎么知道 OP 通过说“第一位”来表示“最低有效位”?另一种直觉是“你写这个数字的第一个数字......”
      • @Blastfurnace 没错,我改进了答案中的示例。
      【解决方案4】:

      如果你使用的是 C++11,你也可以这样做:

      int variable = 253243243;
      std::string s = std::to_string(variable);
      int x = 3; // the position you want
      char digit = s[s.size() - 1 - x]; // x position from the right
      char otherDigit = s[x - 1]; // x position from the left (1-based)
      

      模除模式将更有效(在 CPU 时间和内存方面)。

      【讨论】:

      • 我认为显示从左侧提取xth 字符的行不太正确,我的意思是它从右侧提取xth 字符。下一行的类似问题 - 我认为您只需将 'left' 与 'right' 交换 :-)
      • @piokuc 哎呀。固定的。 :)
      【解决方案5】:

      这个问题让我为数字创建了一个小的“STLish”容器……更多的是为了好玩而不是在现实生活中使用。但是,这里是:

      #ifndef __DIGITS_H__
      # define __DIGITS_H__
      
      # include <type_traits>
      # include <cmath>
      # include <cassert>
      # include <iterator>
      # include <sstream>
      # include <algorithm>
      
      namespace digits
      {   
          // Default base type traits, infer base size from the number of character
          template <char... Chars>
          struct base_char_traits
          {
              // Mandatory for the digits container, maybe someone want to make
              // another traits with  wchar ?
              typedef char value_type;
      
              // Size of the base, computed from the number of characters passed
              static constexpr size_t size = sizeof...(Chars);
      
              // Array of characters use to print the output
              static constexpr value_type characters[sizeof...(Chars)]  = { Chars... };
          };
      
          // **sigh**
          // Instantiation of the array of character; otherwise there will be a link
          // error
          template <char... Chars>
          constexpr typename base_char_traits<Chars...>::value_type base_char_traits<Chars...>::characters[sizeof...(Chars)];
      
          // All your bases are belong to us !
          struct base2_traits : public base_char_traits<'0', '1'> { };
          struct base8_traits : public base_char_traits<'0', '1', '2', '3', '4', '5', '6', '7'> { };
          struct base10_traits : public base_char_traits<'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'> { };
          struct base12_traits : public base_char_traits<'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b'> { };
          struct base16_traits : public base_char_traits<'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'> { };
      
      
          // The digit container with the base traits and the type as template
          // parameter.
          //     
          // It is a read only container that allows you to iterate on the digit in 
          // the base given as template parameter.
          template <typename BaseTraits, typename T = unsigned long>
          class digits
          {
          public:
      
              // Assert that T fullfil our criteria
              static_assert(std::is_integral<T>(), "T must be integral");
              static_assert(std::is_unsigned<T>(), "T must be unsigned");        
      
              // Value type is defined by the base traits to allow the use of more
              // complicated digit type (here we only handle char)
              typedef typename BaseTraits::value_type value_type;
      
              // Reference type is defined to be the same as value type because this is an immutable container
              typedef typename BaseTraits::value_type reference;
      
              // The size type of the container, i.e. the type that will be used to
              // express a digit position
              typedef size_t size_type;
      
              // Iterator class allowing one to walk through the number's digit from 
              // the lowest to the highest 
              class iterator 
              { 
              public:
      
                  // Type used to return iterator substraction result
                  typedef size_t difference_type;
      
                  // type used by algorithms (e.g. find)
                  typedef typename digits::reference reference;
      
                  // type used by algorithms (e.g. find)
                  typedef typename digits::reference pointer;
      
                  // type returned by operator*
                  typedef typename digits::value_type value_type;
      
                  // Iterator category, here we can randomly walk in the digit
                  typedef std::random_access_iterator_tag iterator_category;
      
                  // Mandatory default constructor, initialize to an invalid iterator
                  iterator()
                  {
                      _current_digit = 0;
                      _digits = nullptr;
                  }
      
                  // Build an iterator other a digits container starting at digit
                  iterator(const digits* digits, size_type digit)
                  {
                      _current_digit = digit;
                      _digits = digits;
                  }
      
                  iterator(const iterator& it) :
                  iterator(it._digits, it._current_digit)
                  {
      
                  }
      
                  // Move using swap idiom
                  iterator(iterator&& it) :
                  iterator()
                  {
                      swap(*this, it);
                  }
      
                  ~iterator()
                  {
                      _digits = nullptr;
                  }
      
                  // assignment iterator using swap idiom
                  iterator& operator=(iterator it)
                  {
                      swap(*this, it);
                      return *this;
                  }
      
                  // Comparison operators
                  bool operator==(const iterator& it) const
                  {
                      assert(_digits == it._digits);
                      return (_current_digit == it._current_digit);
                  }
      
                  bool operator!=(const iterator& it) const
                  {
                      return !(operator==(it));
                  }
      
                  bool operator<(const iterator& it) const
                  {
                      assert(_digits == it._digits);
                      return (_current_digit < it._current_digit);
                  }
      
                  bool operator>(const iterator& it) const
                  {
                      assert(_digits == it._digits);
                      return (_current_digit > it._current_digit);
                  }
      
                  bool operator<=(const iterator& it) const
                  {
                      assert(_digits == it._digits);
                      return (_current_digit <= it._current_digit);
                  }
      
                  bool operator>=(const iterator& it) const
                  {
                      assert(_digits == it._digits);
                      return (_current_digit >= it._current_digit);
                  }
      
                  // Moving the iterator
                  iterator& operator++()
                  {
                      ++_current_digit;
                      return *this;
                  }
      
                  iterator operator++(int)
                  {
                      iterator it(*this);
                      operator++();
                      return it;
                  }
      
                  iterator& operator--()
                  {
                      --_current_digit;
                      return  *this;
                  }
      
                  iterator operator--(int)
                  {
                      iterator it(*this);
                      operator--();
                      return it;
                  }
      
                  iterator& operator+=(size_type increment)
                  {
                      _current_digit += increment;
                      return *this;
                  }
      
                  iterator operator+(size_type increment) const
                  {
                      iterator it(*this);
                      return (it += increment);
                  }
      
                  friend iterator operator+(size_type increment, const iterator& it)
                  {
                      return (it + increment);
                  }
      
                  iterator& operator-=(size_type decrement)
                  {
                      _current_digit -= decrement;
                      return *this;
                  }
      
                  iterator operator-(size_type decrement) const
                  {
                      iterator it(*this);
                      return (it - decrement);
                  }
      
                  difference_type operator-(const iterator& it) const
                  {
                      assert(_digits == it._digits);
                      return (_current_digit - it._current_digit);
                  }
      
                  value_type operator*() const
                  {
                      assert(nullptr != _digits);
      
                      return _digits->digit(_current_digit);
                  }           
      
                  friend void swap(iterator& first, iterator& second)
                  {
                      std::swap(first._digits, second._digits); 
                      std::swap(first._current_digit, second._current_digit);
                  }
      
              private:
      
                  // The current digit we will be printing when calling operator*().
                  // From 0 to (digits.size() - 1)
                  size_t _current_digit;
      
                  // The digit container we're working on.
                  const digits* _digits;
              };      
      
              // Define the reverse iterator, that will allow to iterator from the
              // highest digit to the lowest (more printing friendly)
              typedef std::reverse_iterator<iterator> reverse_iterator;
      
              // Default constructor use 0 as a number
              digits() 
              {
                  _number = 0;
              }
      
              // Build a container over a number given as parameter
              digits(T number) 
              {
                  _number = number;
              }
      
              digits(const digits& copy) :
              digits(copy._number)
              {            
              }
      
              // Move constructor using swap idiom
              digits(digits&& move) :
              digits()
              {
                  swap(*this, move);
              }
      
              ~digits()
              {
              }
      
              // Retrieve the digit character
              value_type digit(size_t digit) const
              {
                  assert(digit < size());
                  constexpr size_t base = BaseTraits::size;
      
                  // @warning
                  // llround is mandatory because of a double to unsigned long problem
                  T modul = static_cast<T>(llround(std::pow(base, digit + 1)));
                  T div =  static_cast<T>(llround(std::pow(base, digit)));
                  T digit_index = (_number % modul) / div;         
      
                  return BaseTraits::characters[digit_index];
              }
      
              // Assignment using swap idiom
              digits& operator=(digits assign)
              {
                  swap(_number, assign._number);
              }
      
              // Comparison operator
              bool operator==(const digits& comp) const
              {
                  return (_number == comp._number);
              }
      
              bool operator!=(const digits& comp) const
              {
                  return !(operator==(comp));
              }       
      
              // Iterators creation
              iterator begin() const
              {
                  return iterator(this, static_cast<size_type>(0));
              }
      
              iterator cbegin() const
              {
                  return begin();
              }
      
              iterator end() const
              {
                  return iterator(this, size());
              }
      
              iterator cend() const
              {
                  return end();
              }
      
              reverse_iterator rbegin() const
              {
                  return reverse_iterator(end());
              }
      
              reverse_iterator crbegin() const
              {
                  return reverse_iterator(cend());
              }
      
              reverse_iterator rend() const
              {
                  return reverse_iterator(begin());
              }
      
              reverse_iterator crend() const
              {
                  return reverse_iterator(cbegin());
              }
      
              // swap function
              friend void swap(digits& first, digits& second)
              {
                  std::swap(first._number, second._number);
              }
      
              // cast to string
              operator std::string () const
              {
                  std::ostringstream stream;
      
                  // print from high to low
                  std::copy(rbegin(), rend(), 
                            std::ostream_iterator<value_type>(stream, ""));
                  return stream.str();
              }
      
              // The number of digits of this _number
              size_type size() const
              {            
                  const double log_number = std::log(_number);
                  constexpr double log_base = std::log(BaseTraits::size);
                  return  std::ceil(log_number / log_base);
              }
      
              // The maximum nulber of digits this type can have
              size_type max_size() const
              {
                  constexpr double max_number = std::pow(2, sizeof(T) * 8);
                  constexpr double log_max_number = std::log(max_number);
                  constexpr double log_base = std::log(BaseTraits::size);
                  return  log_max_number / log_base;
              }
      
          private:
      
              // The number we will iterate over the digits
              T _number;
          };
      }
      
      #endif // __DIGITS_H__
      

      基本用法如下:

      digits::digits<digits::base10_traits> dig(123456);
      
      for (auto digit: dig)
      {
          std::cout << "Digit: " << digit << std::endl;
      }
      

      我认为不可变容器(for_eachfindcopy 等)上的大多数 STD 算法都适用于该容器。

      这里有一个小测试(标题+测试在同一个文件中):http://ideone.com/BoMX5Q

      好吧,这没什么用,但这样做真的很有趣。 :)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-10-12
        • 2018-10-22
        • 2023-01-07
        • 2017-12-07
        • 1970-01-01
        • 2021-03-10
        相关资源
        最近更新 更多