Exemplo n.º 1
0
Number Number::operator[](const Range &range) const
{
    int left = range.left();
    int right = range.right();

    if (left == 0 || right == 0)
        throw Exception("Number[0] operation is undefined (numbers are indexed 1..n)");

    if (left < right)
        throw Exception("Number[x..y] operation where x < y is undefined");

    int lefti;
    int righti;

    if (left > 0) {
        lefti = left + m_decimals - 1;
    } else {
        lefti = m_decimals + left;
    }

    if (right > 0) {
        righti = right + m_decimals - 1;
    } else {
        righti = m_decimals + right;
    }

    if ((lefti < 0 || righti < 0) ||
        (m_digits.size() <= static_cast<size_t>(lefti) || m_digits.size() <= static_cast<size_t>(righti)))
        throw Exception("Number[x..y] out of bounds");

    Number out;

    out.m_accuracy = m_accuracy;
    out.m_precision = m_precision;
    out.m_digits.clear();

    out.m_digits.insert(out.m_digits.begin(), m_digits.cbegin() + righti, m_digits.cbegin() + lefti + 1);

    if (left > 0 && right < 0) {
        out.m_decimals = right * (-1);
    }

    out.m_trailingZeros = out.normalize();

    return out;
}
Exemplo n.º 2
0
Number Number::inverse() const
{
    // dzielenie przez 0
    if (isNull())
        throw Exception("Divison by 0 detected");

    // wynikowa liczba
    Number result;
    result.m_digits.clear();
    result.m_precision = m_precision;
    result.m_accuracy = m_accuracy;
    result.m_negative = m_negative;

    // dzieląca liczba
    Number integer = *this;

    int shiftBy = m_decimals;

    if (m_decimals > 0) {
        if (m_digits.size() >= static_cast<size_t>(m_precision)) {
            int cut = (m_digits.size() - m_precision);

            if (cut <= m_decimals) {
                integer.m_digits.erase(integer.m_digits.begin(), integer.m_digits.begin() + cut);

                integer.m_decimals -= cut;
                shiftBy -= cut;
            }
        }

        integer.shift(shiftBy);
    }

    // szukanie odwrotności 0.(dowolna ilość zer)1, lub jedynki
    if (integer.m_digits.size() == 1 && integer.m_digits.front() == 1) {
        result.m_digits.push_back(1);
        result.shift(m_decimals);
        return result;
    }

    // tymczasowa
    Number tmp(10);

    // jako że wrzucamy odwrotnie ...
    std::deque<char> numbers;

    int digit = 0;

    do {
        int cmp = tmp.compareWith(integer, true);

        if (cmp <= 0) {
            ++digit;
            tmp.subtract(integer, true);
        } else {
            numbers.push_front(digit);
            result.m_decimals++;
            digit = 0;
            tmp.shift(1);
        }
    } while(result.m_decimals <= m_precision && !tmp.isNull());

    if (digit > 0) {
        numbers.push_front(digit);
        result.m_decimals++;
    }

    // teraz dodajemy do liczby
    result.m_digits.insert(result.m_digits.begin(), numbers.begin(), numbers.end());
    result.m_digits.push_back(0);

    // 1 / 0,321 = 1000 * (1 / 321)
    result.shift(shiftBy);

    // dokładność
    if (m_accuracy > 0) {
        // todo: sprawdzić czy nie ma ładniejszego sposobu (jakiś range iterator?)
        int zeros = result.m_digits.size() - result.m_decimals - m_accuracy;

        for (auto li = result.m_digits.begin() + result.m_decimals; zeros > 0; li++, zeros--) {
            *li = 0;
        }
    }

    // sprzątanie
    result.normalize();

    return result;
}