Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Division not crossing over bytes

I'm trying to do division on a uint128_t that is made up of 2 uint64_ts. Weirdly enough, the function works for uint64_ts with only the lower value set and the upper value = 0. I don't understand why.

Here's the code for the division and bit shift

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

Please ignore my blatant disregard for memory management.

like image 952
calccrypto Avatar asked May 27 '11 02:05

calccrypto


2 Answers

out = uint128_t(LOWER << (64 - shift), 0); is wrong - it should be shift - 64 instead.

As a style note, ALL_CAPITALS are usually reserved for constants only. Variables and members should use mostly lowercase.

like image 169
Mark B Avatar answered Nov 06 '22 08:11

Mark B


anyway, this version is a little bit faster :)

ensure, 4000 iterations against 127:

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;
}
like image 29
bibmaster Avatar answered Nov 06 '22 10:11

bibmaster