Esempio n. 1
0
inline void ObNumber::div_uint32(const ObNumber &dividend, uint32_t divisor, ObNumber &quotient, ObNumber &remainder)
{
    OB_ASSERT(0 < dividend.nwords_);
    OB_ASSERT(MAX_NWORDS >= dividend.nwords_);
    OB_ASSERT(0 < divisor);
    int64_t carry = 0;
    for (int i = dividend.nwords_ - 1; i >= 0; --i)
    {
        carry = carry * BASE + dividend.words_[i];
        quotient.words_[i] = static_cast<uint32_t> (carry / divisor);
        carry = carry % divisor;
    }
    quotient.nwords_ = dividend.nwords_;
    quotient.remove_leading_zeroes();

    if (0 == carry)
    {
        remainder.set_zero(); // remainder is zero
    }
    else
    {
        remainder.words_[0] = static_cast<uint32_t> (carry);
        remainder.nwords_ = 1;
    }
}
Esempio n. 2
0
int ObNumber::div(const ObNumber &other, ObNumber &res) const
{
    int ret = OB_SUCCESS;
    res.set_zero();
    if (other.is_zero())
    {
        jlog(WARNING, "divisor is zero");
        ret = JD_DIVISION_BY_ZERO;
    }
    else if (!this->is_zero())
    {
        res.vscale_ = QUOTIENT_SCALE;
        ObNumber dividend = *this;
        ObNumber divisor = other;
        ObNumber remainder;
        bool res_is_neg = false;
        if (dividend.is_negative())
        {
            negate(dividend, dividend);
            res_is_neg = true;
        }
        if (dividend.vscale_ > DOUBLE_PRECISION_NDIGITS)
        {
            dividend.round_fraction_part(DOUBLE_PRECISION_NDIGITS);
        }
        if (divisor.vscale_ > SINGLE_PRECISION_NDIGITS)
        {
            divisor.round_fraction_part(SINGLE_PRECISION_NDIGITS);
        }
        if (dividend.vscale_ < divisor.vscale_
                || res.vscale_ > dividend.vscale_ - divisor.vscale_)
        {
            if (OB_SUCCESS != (ret = dividend.left_shift(static_cast<int8_t> (res.vscale_ + divisor.vscale_ - dividend.vscale_), true)))
            {
                jlog(WARNING, "left shift overflow, err=%d res_vscale=%hhd other_vscale=%hhd this_vscale=%hhd",
                        ret, res.vscale_, divisor.vscale_, dividend.vscale_);
            }
        }
        if (OB_LIKELY(OB_SUCCESS == ret))
        {
            if (divisor.is_negative())
            {
                negate(divisor, divisor);
                res_is_neg = !res_is_neg;
            }
            divisor.remove_leading_zeroes_unsigned();
            div_words(dividend, divisor, res, remainder);
            if (OB_UNLIKELY(res_is_neg))
            {
                negate(res, res);
            }
            res.remove_leading_zeroes();
        }
    }
    return ret;
}
Esempio n. 3
0
int ObNumber::add(const ObNumber &other, ObNumber &res) const
{
    int ret = OB_SUCCESS;
    res.set_zero();
    ObNumber n1 = *this;
    ObNumber n2 = other;
    if (n1.vscale_ > SINGLE_PRECISION_NDIGITS)
    {
        n1.round_fraction_part(SINGLE_PRECISION_NDIGITS);
    }
    if (n2.vscale_ > SINGLE_PRECISION_NDIGITS)
    {
        n2.round_fraction_part(SINGLE_PRECISION_NDIGITS);
    }
    int8_t res_nwords = static_cast<int8_t> (std::max(n1.nwords_, n2.nwords_) + 1);
    if (res_nwords > MAX_NWORDS)
    {
        jlog(WARNING, "number out of range");
        ret = JD_VALUE_OUT_OF_RANGE;
    }
    else
    {
        n1.extend_words(res_nwords);
        n2.extend_words(res_nwords);
    }
    if (n1.vscale_ > n2.vscale_)
    {
        ret = n2.left_shift(static_cast<int8_t> (n1.vscale_ - n2.vscale_), false);
    }
    else if (n1.vscale_ < n2.vscale_)
    {
        ret = n1.left_shift(static_cast<int8_t> (n2.vscale_ - n1.vscale_), false);
    }
    if (OB_SUCCESS == ret)
    {
        add_words(n1, n2, res);
        res.remove_leading_zeroes();
    }
    return ret;
}
Esempio n. 4
0
int ObNumber::mul(const ObNumber &other, ObNumber &res) const
{
    int ret = OB_SUCCESS;
    res.set_zero();
    if (!this->is_zero() && !other.is_zero())
    {
        ObNumber multiplicand = *this;
        ObNumber multiplier = other;
        bool res_is_neg = false;
        if (multiplicand.is_negative())
        {
            negate(multiplicand, multiplicand);
            res_is_neg = true;
        }
        if (multiplier.is_negative())
        {
            negate(multiplier, multiplier);
            res_is_neg = !res_is_neg;
        }
        if (multiplicand.vscale_ > SINGLE_PRECISION_NDIGITS)
        {
            multiplicand.round_fraction_part(SINGLE_PRECISION_NDIGITS);
        }
        if (multiplier.vscale_ > SINGLE_PRECISION_NDIGITS)
        {
            multiplier.round_fraction_part(SINGLE_PRECISION_NDIGITS);
        }
        res.vscale_ = static_cast<int8_t> (multiplicand.vscale_ + multiplier.vscale_);
        ret = mul_words(multiplicand, multiplier, res);
        res.remove_leading_zeroes();
        if (res_is_neg)
        {
            negate(res, res);
        }
    }
    return ret;
}
Esempio n. 5
0
inline void ObNumber::div_words(const ObNumber &dividend, const ObNumber &divisor, ObNumber &quotient, ObNumber &remainder)
{
    OB_ASSERT(!dividend.is_zero());
    OB_ASSERT(!divisor.is_zero());
    OB_ASSERT(0 < dividend.nwords_ && dividend.nwords_ <= MAX_NWORDS);
    OB_ASSERT(0 < divisor.nwords_ && divisor.nwords_ <= MAX_NWORDS);

    if (1 == divisor.nwords_)
    {
        // fast algorithm
        div_uint32(dividend, divisor.words_[0], quotient, remainder);
    }
    else
    {
        // Knuth's algorithm, Volumn 2, Section 4.3, Page 235
        ObNumber cdivisor;
        ObNumber cdividend;
        if (divisor.words_[divisor.nwords_ - 1] < HALF_BASE)
        {
            // make sure (BASE ^ n)/2 <= divisor
            uint32_t factor = static_cast<uint32_t> (BASE / (divisor.words_[divisor.nwords_ - 1] + 1));
            mul_uint32(divisor, factor, cdivisor, true);
            mul_uint32(dividend, factor, cdividend, true);
            OB_ASSERT(cdivisor.words_[cdivisor.nwords_ - 1] >= HALF_BASE);
        }
        else
        {
            cdividend = dividend;
            cdivisor = divisor;
        }

        if (cdividend.nwords_ < cdivisor.nwords_) // include the case when dividend is zero
        {
            quotient.set_zero();
            remainder = dividend;
        }
        else if (cdividend.nwords_ == cdivisor.nwords_)
        {
            int cmp = compare_words_unsigned(cdividend, cdivisor);
            if (cmp < 0)
            {
                quotient.set_zero();
                remainder = dividend;
            }
            else
            {
                quotient.nwords_ = 1;
                quotient.words_[0] = 1;
                sub_words_unsigned(cdividend, cdivisor, remainder);
            }
        }
        else // dividend.nwords_ >= 1 + divosor.nwords_
        {
            quotient.nwords_ = static_cast<int8_t> (cdividend.nwords_ - cdivisor.nwords_ + 1);
            memset(quotient.words_, 0, sizeof (quotient.words_));
            for (int8_t i = static_cast<int8_t> (cdividend.nwords_ - cdivisor.nwords_ - 1); i >= 0; --i)
            {
                knuth_div_unsigned(&cdividend.words_[i], cdivisor, quotient, i, remainder);
                for (int8_t j = 0; j < cdivisor.nwords_; ++j)
                {
                    cdividend.words_[i + j] = remainder.words_[j];
                }
            }
        }
    }
    if (quotient.nwords_ > 0
            && static_cast<int64_t> (quotient.words_[quotient.nwords_ - 1]) >= HALF_BASE)
    {
        quotient.words_[quotient.nwords_++] = 0; // quotient is always positive
    }
    if (remainder.nwords_ > 0
            && static_cast<int64_t> (remainder.words_[remainder.nwords_ - 1]) >= HALF_BASE)
    {
        remainder.words_[remainder.nwords_++] = 0; // remainder is always positive
    }
}