X-Git-Url: https://git.ucc.asn.au/?p=ipdf%2Fcode.git;a=blobdiff_plain;f=src%2Farbint.cpp;h=748330fe38b55be76ded37e585dc2e224a5bdd1b;hp=ccde0dd75f54363d90c4e1a0e9ad104fbdc6402a;hb=f06cfbc2d5986de9f9489e5cd9424231f310d471;hpb=33356addacfe4296ecb613c6c4696f082e351159;ds=sidebyside diff --git a/src/arbint.cpp b/src/arbint.cpp index ccde0dd..748330f 100644 --- a/src/arbint.cpp +++ b/src/arbint.cpp @@ -1,52 +1,276 @@ +/** + * @file arbint.cpp + * @brief Arbitrary sized integer definitions + * @see arbint.h + * @see add_digits_asm.s + * @see sub_digits_asm.s + * @see mul_digits_asm.s + */ + #include "arbint.h" #include #include + + +#include +#include +#include +#include + using namespace std; -/* -static bool addc(uint32_t a, uint32_t b, uint32_t * r) +namespace IPDF +{ + +Arbint::Arbint(digit_t i) : m_digits(1), m_sign(i < 0) { - volatile uint32_t carry = false; - volatile uint32_t result = a + b; - asm volatile - ( - "jc 1f;" - "mov $0, %%eax;" - "1:" - : "=a" (carry) - ); - *r = result; - return (carry == 1); + m_digits[0] = llabs(i); } -*/ -namespace IPDF +Arbint::Arbint(unsigned n, digit_t d0, ...) : m_digits(n), m_sign(false) +{ + va_list ap; + va_start(ap, d0); + if (n > 1) + m_digits[0] = d0; + for (unsigned i = 1; i < n; ++i) + { + m_digits[i] = va_arg(ap, digit_t); + } + va_end(ap); +} + +Arbint::Arbint(const Arbint & cpy) : m_digits(cpy.m_digits), m_sign(cpy.m_sign) +{ + +} + +Arbint::Arbint(const vector & digits) : m_digits(digits), m_sign(false) +{ + +} + +Arbint & Arbint::operator=(const Arbint & cpy) +{ + memmove(m_digits.data(), cpy.m_digits.data(), + sizeof(digit_t)*min(m_digits.size(), cpy.m_digits.size())); + if (cpy.m_digits.size() > m_digits.size()) + { + unsigned old_size = m_digits.size(); + m_digits.resize(cpy.m_digits.size()); + memset(m_digits.data()+old_size, 0, sizeof(digit_t)*m_digits.size()-old_size); + } + return *this; +} + +void Arbint::Zero() +{ + memset(m_digits.data(), 0, sizeof(digit_t)*m_digits.size()); +} + +unsigned Arbint::Shrink() +{ + if (m_digits.size() <= 1) + return 0; + unsigned i; + for (i = m_digits.size()-1; (i > 0 && m_digits[i] != 0L); --i); + unsigned result = m_digits.size() - i; + m_digits.resize(i); + return result; +} + +Arbint & Arbint::operator*=(const Arbint & mul) +{ + vector new_digits(m_digits.size(), 0L); + new_digits.reserve(new_digits.size()+mul.m_digits.size()); + for (unsigned i = 0; i < mul.m_digits.size(); ++i) + { + vector step(m_digits.size()+i, 0L); + memcpy(step.data()+i, m_digits.data(), sizeof(digit_t)*m_digits.size()); + + digit_t overflow = mul_digits((digit_t*)step.data()+i, mul.m_digits[i], m_digits.size()); + if (overflow != 0L) + { + step.push_back(overflow); + } + new_digits.resize(max(new_digits.size(), step.size()), 0L); + digit_t carry = add_digits((digit_t*)new_digits.data(), step.data(), step.size()); + if (carry != 0L) + { + new_digits.push_back(carry); + } + } + + m_digits.swap(new_digits); + m_sign = !(m_sign == mul.m_sign); + return *this; +} + +void Arbint::Division(const Arbint & div, Arbint & result, Arbint & remainder) const +{ + if (div == Arbint(1L)) + { + result = *this; + remainder = 0L; + return; + } + if (div == *this) + { + result = 1L; + remainder = 0L; + return; + } + + + result = 0L; + remainder = *this; + Arbint next_rem(remainder); + while ((next_rem -= div) >= Arbint(0L)) + { + //Debug("%li - %li = %li", digit_t(remainder), digit_t(div), digit_t(next_rem)); + //Debug("Sign is %d", next_rem.m_sign); + remainder = next_rem; + result += 1L; + } + + +} + +Arbint & Arbint::operator+=(const Arbint & add) { + if (m_sign == add.m_sign) + { + // -a + -b == -(a + b) + return AddBasic(add); + } + + if (m_sign) + { + // -a + b == -(a - b) + m_sign = false; + SubBasic(add); + m_sign = !m_sign; + } + else + { + // a + -b == a - b + SubBasic(add); + } + return *this; +} -Arbint::Arbint(int64_t i) : m_words(2), m_sign(false) +Arbint & Arbint::operator-=(const Arbint & sub) { - m_sign = i < 0; - memcpy(m_words.data(), &i, sizeof(int64_t)); + if (m_sign == sub.m_sign) + return SubBasic(sub); + return AddBasic(sub); } -string Arbint::Str() const +Arbint & Arbint::AddBasic(const Arbint & add) +{ + if (add.m_digits.size() >= m_digits.size()) + { + m_digits.resize(add.m_digits.size()+1,0L); + } + + digit_t carry = add_digits((digit_t*)m_digits.data(), + (digit_t*)add.m_digits.data(), add.m_digits.size()); + if (carry != 0L) + m_digits[m_digits.size()-1] = carry; + else if (m_digits.back() == 0L) + m_digits.resize(m_digits.size()-1); + return *this; +} + +Arbint & Arbint::SubBasic(const Arbint & sub) +{ + if (sub.m_digits.size() >= m_digits.size()) + { + m_digits.resize(sub.m_digits.size(),0L); + } + digit_t borrow = sub_digits((digit_t*)m_digits.data(), + (digit_t*)sub.m_digits.data(), sub.m_digits.size()); + + + //TODO: Write ASM to do this bit? + if (borrow != 0L) + { + m_sign = !m_sign; + for (unsigned i = 0; i < m_digits.size(); ++i) + m_digits[i] = -m_digits[i]; + } + return *this; +} + + +string Arbint::Str(const string & base) const { string s(""); - for (unsigned i = 0; i < m_words.size(); ++i) + for (unsigned i = 0; i < m_digits.size(); ++i) { - uint32_t w = m_words[i]; + digit_t w = m_digits[i]; do { - uint32_t q = w % 10; + digit_t q = w % 10; w /= 10; s += ('0' + q); } while (w > 0); - if (i+1 < m_words.size()) s += ","; + if (i+1 < m_digits.size()) s += ","; } - if (m_sign) s += '-'; reverse(s.begin(), s.end()); return s; } +bool Arbint::IsZero() const +{ + for (unsigned i = m_digits.size()-1; i > 0; --i) + { + if (m_digits[i] != 0L) return false; + } + return (m_digits[0] == 0L); +} + +bool Arbint::operator==(const Arbint & equ) const +{ + if (m_sign != equ.m_sign) + return false; + unsigned min_size = m_digits.size(); + const Arbint * larger = &equ; + if (m_digits.size() > equ.m_digits.size()) + { + min_size = equ.m_digits.size(); + larger = this; + } + + if (memcmp(m_digits.data(), equ.m_digits.data(), sizeof(digit_t)*min_size) != 0) + return false; + + for (unsigned i = min_size; i < larger->m_digits.size(); ++i) + { + if (larger->m_digits[i] != 0L) + return false; + } + return true; +} + +bool Arbint::operator<(const Arbint & less) const +{ + Arbint cpy(*this); + cpy -= less; + return (cpy.m_sign && !cpy.IsZero()); +} + +string Arbint::DigitStr() const +{ + stringstream ss(""); + ss << std::hex << std::setfill('0'); + for (unsigned i = 0; i < m_digits.size(); ++i) + { + if (i != 0) ss << ','; + ss << std::setw(2*sizeof(digit_t)) << static_cast(m_digits[i]); + } + return ss.str(); +} + }