【问题标题】:Division not crossing over bytes除法不跨越字节
【发布时间】:2011-05-27 02:11:46
【问题描述】:

我正在尝试对由 2 个uint64_ts 组成的uint128_t 进行除法。奇怪的是,该函数适用于 uint64_ts,只设置了下限值且上限值 = 0。我不明白为什么。

这是除法和位移的代码

class uint128_t{
   private:
      uint64_t UPPER, LOWER;
   public:
      // lots of stuff

    uint128_t operator<<(int shift){
        uint128_t out;
        if (shift >= 128)
            out = uint128_t(0, 0);
        else if ((128 > shift) && (shift >= 64))
            out = uint128_t(LOWER << (64 - shift), 0);
        else if (shift < 64)
            out = uint128_t((UPPER << shift) + (LOWER >> (64 - shift)), LOWER << shift);
        return out;
    }

    uint128_t operator<<=(int shift){
        *this = *this << shift;
        return *this;
    }

    uint128_t operator/(uint128_t rhs){
            // copy of numerator = copyn
            uint128_t copyn(*this), quotient = 0;// constructor: uint128_t(T), uint128_t(S, T), uint128_t(uint128_t), etc
            while (copyn >= rhs){
                // copy of denomiator = copyd
                // temp is the current quotient bit being worked with
                uint128_t copyd(rhs), temp(1);
                // shift the divosr to the highest bit
                while (copyn > (copyd << 1)){
                    copyd <<= 1;
                    temp <<= 1;
                }
                copyn -= copyd;
                quotient += temp;
            }
            return quotient;
        }
// more stuff
};

请忽略我对内存管理的公然无视。

【问题讨论】:

    标签: c++ math biginteger integer-division


    【解决方案1】:

    out = uint128_t(LOWER &lt;&lt; (64 - shift), 0); 错误 - 应该改为 shift - 64

    作为一种风格说明,ALL_CAPITALS 通常只为常量保留。变量和成员应大多使用小写。

    【讨论】:

    • 实际上,所有大写字母通常都是为预处理器标识符保留的。
    • 好吧,一些预处理器标识符实际上是常量,所以他仍然是对的,但是从更广泛的意义上说,所有宏都是用大写字母编写的
    • 它没有改变任何东西。 :( 除法运算符有什么问题吗?它似乎卡在while (copyn &gt; (copyd &lt;&lt; 1)) 循环中
    【解决方案2】:

    试试这个:

    // some bit operations stuff
    const unsigned char de_brujin_bit_map_64 [] = 
    {
        0,1,2,7,3,13,8,19,4,25,14,28,9,34,20,40,5,17,26,38,15,46,29,48,10,31,35,54,21,50,41,57,
        63,6,12,18,24,27,33,39,16,37,45,47,30,53,49,56,62,11,23,32,36,44,52,55,61,22,43,51,60,42,59,58
    };
    inline uint8_t trailing_zero_count(uint64_t x) { return x?de_brujin_bit_map_64[(lower_bit(x)*0x0218A392CD3D5DBFL) >> 58]:64; }
    inline uint8_t leading_zero_count(uint64_t x) { return x?(63-de_brujin_bit_map_64[(upper_bit(x)*0x0218A392CD3D5DBFL) >> 58]):64; }
    inline uint64_t lower_bit(uint64_t x) { return x & -(int64_t&)x; }
    inline uint64_t upper_bit(uint64_t x)
    {
        if(!x) return 0;
        x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16;  x |= x >> 32;
        return (x >> 1) + 1;
    }
    inline uint128_t upper_bit(const uint128_t x) 
    {
        if(x.upper()) return uint128_t(upper_bit(x.upper()), 0); 
        else return uint128_t(0, upper_bit(x.lower())); 
    }
    inline uint128_t lower_bit(const uint128_t x) 
    {
        if(x.lower()) return uint128_t(0, lower_bit(x.lower())); 
        else return uint128_t(lower_bit(x.upper()), 0); 
    }
    inline uint8_t trailing_zero_count(const uint128_t& x) { return x.lower()?trailing_zero_count(x.lower()):(64+trailing_zero_count(x.upper())); }
    inline uint8_t leading_zero_count(const uint128_t& x) { return x.upper()?leading_zero_count(x.upper()):(64+leading_zero_count(x.lower())); }
    
    // division operator
    uint128_t uint128_t::operator/(const uint128_t& rhs) const
    {
        if(rhs == 0) return uint128_t(0); // !!!! zero division
        if(rhs == rhs) return uint128_t(1);
        if(rhs > *this) return uint128_t(0);
        if(rhs == 1) return *this;
        if(!upper_ && !rhs.upper_) return uint128_t(0, lower_/rhs.lower_);
        if(lower_bit(rhs) == rhs) return *this >> trailing_zero_count(rhs);
        uint128_t result;
        uint128_t bit_mask = upper_bit();
        uint128_t denom = 1;
        do 
        {
            bit_mask >>= 1;
            denom <<= 1;
            if(*this & bit_mask) denom |= 1;
            result <<= 1;
            if(denom >= rhs) { denom -= rhs; result |= 1; }
        } 
        while (bit_mask.lower_ != 1);
        return result;
    }
    

    【讨论】:

      【解决方案3】:

      反正这个版本快一点:)

      确保针对 127 进行 4000 次迭代:

      uint128_t divident = uint128_t(0xffffffffffffffffULL, 0xffffffffffffffffULL);
      uint128_t divisor = 10;
      {
          uint32_t iter_count = 0;
          uint128_t copyn(divident), quotient = 0;
          while (copyn >= divisor)
          {
              ++iter_count;
              uint128_t copyd(divisor), temp(1);
              while ((copyn >> 1) > copyd) { ++iter_count; copyd <<= 1; temp <<= 1; }
              copyn -= copyd;
              quotient += temp;
          }
          std::cout << "iterations: " << std::dec << iter_count << std::endl;
      }
      {
          uint32_t iter_count = 0;
          uint128_t bit_pos = dtl::bits::upper_bit(divident);
          uint128_t tmp = 1, quotient = 0;
          do 
          {
              ++iter_count;
              bit_pos >>= 1;
              tmp <<= 1;
              if(divident & bit_pos) tmp |= 1;
              quotient <<= 1;
              if(tmp >= divisor) { tmp -= divisor; quotient |= 1; }
          } 
          while (bit_pos != 1);
          std::cout << "iterations: " << std::dec << iter_count << std::endl;
      }
      

      【讨论】:

        猜你喜欢
        • 2016-11-14
        • 1970-01-01
        • 1970-01-01
        • 2013-06-28
        • 1970-01-01
        • 1970-01-01
        • 2013-08-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多