http://git-wip-us.apache.org/repos/asf/ignite/blob/5cc1f074/modules/platforms/cpp/common/src/common/big_integer.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/common/src/common/big_integer.cpp b/modules/platforms/cpp/common/src/common/big_integer.cpp new file mode 100644 index 0000000..475ddc6 --- /dev/null +++ b/modules/platforms/cpp/common/src/common/big_integer.cpp @@ -0,0 +1,830 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ignite/ignite_error.h" +#include "ignite/common/bits.h" +#include "ignite/common/big_integer.h" + +namespace ignite +{ + namespace common + { + BigInteger::BigInteger() : + sign(1), + mag() + { + // No-op. + } + + BigInteger::BigInteger(int64_t val) : + sign(1), + mag() + { + AssignInt64(val); + } + + BigInteger::BigInteger(const char* val, int32_t len) : + sign(1), + mag() + { + AssignString(val, len); + } + + BigInteger::BigInteger(const BigInteger& other) : + sign(other.sign), + mag(other.mag) + { + // No-op. + } + + BigInteger::BigInteger(const int8_t* val, int32_t len, int32_t sign, bool bigEndian) : + sign(sign), + mag() + { + assert(val != 0); + assert(len > 0); + assert(sign == 1 || sign == 0 || sign == -1); + assert(val[0] != 0); + + if (bigEndian) + { + int32_t firstNonZero = 0; + while (firstNonZero < len && val[firstNonZero] == 0) + ++firstNonZero; + + int32_t intLength = (len - firstNonZero + 3) / 4; + + mag.Resize(intLength); + + int32_t b = len - 1; + + for (int32_t i = 0; i < intLength - 1; ++i) + { + mag[i] = (val[b] & 0xFFUL) + | ((val[b - 1] & 0xFFUL) << 8) + | ((val[b - 2] & 0xFFUL) << 16) + | ((val[b - 3] & 0xFFUL) << 24); + + b -= 4; + } + + int32_t bytesRemaining = b - firstNonZero + 1; + + assert(bytesRemaining > 0 && bytesRemaining <= 4); + + switch (bytesRemaining) + { + case 4: + mag[intLength - 1] |= (val[b - 3] & 0xFF) << 24; + + case 3: + mag[intLength - 1] |= (val[b - 2] & 0xFF) << 16; + + case 2: + mag[intLength - 1] |= (val[b - 1] & 0xFF) << 8; + + case 1: + mag[intLength - 1] |= val[b] & 0xFF; + + default: + break; + } + } + else + { + int32_t firstNonZero = len - 1; + while (firstNonZero >= 0 && val[firstNonZero] == 0) + --firstNonZero; + + int32_t intLength = (firstNonZero + 4) / 4; + + mag.Resize(intLength); + + int32_t b = 0; + + for (int32_t i = 0; i < intLength - 1; ++i) + { + mag[i] = (val[b] & 0xFFUL) + | ((val[b + 1] & 0xFFUL) << 8) + | ((val[b + 2] & 0xFFUL) << 16) + | ((val[b + 3] & 0xFFUL) << 24); + + b += 4; + } + + int32_t bytesRemaining = firstNonZero - b + 1; + + assert(bytesRemaining > 0 && bytesRemaining <= 4); + + switch (bytesRemaining) + { + case 4: + mag[intLength - 1] |= (val[b + 3] & 0xFF) << 24; + + case 3: + mag[intLength - 1] |= (val[b + 2] & 0xFF) << 16; + + case 2: + mag[intLength - 1] |= (val[b + 1] & 0xFF) << 8; + + case 1: + mag[intLength - 1] |= val[b] & 0xFF; + + default: + break; + } + } + } + + BigInteger::BigInteger(MagArray &mag, int8_t sign) : + sign(sign), + mag() + { + this->mag.Swap(mag); + } + + BigInteger& BigInteger::operator=(const BigInteger& other) + { + Assign(other); + + return *this; + } + + void BigInteger::Assign(const BigInteger& val) + { + if (this != &val) + { + sign = val.sign; + mag = val.mag; + } + } + + void BigInteger::AssignInt64(int64_t val) + { + if (val < 0) + { + AssignUint64(static_cast<uint64_t>(-val)); + + sign = -1; + } + else + AssignUint64(static_cast<uint64_t>(val)); + } + + void BigInteger::AssignString(const char* val, int32_t len) + { + std::stringstream converter; + + converter.write(val, len); + + converter >> *this; + } + + void BigInteger::AssignUint64(uint64_t val) + { + sign = 1; + + if (val == 0) + { + mag.Clear(); + + return; + } + + uint32_t highWord = static_cast<uint32_t>(val >> 32); + + if (highWord == 0) + mag.Resize(1); + else + { + mag.Resize(2); + mag[1] = highWord; + } + + mag[0] = static_cast<uint32_t>(val); + } + + int8_t BigInteger::GetSign() const + { + return sign; + } + + void BigInteger::Swap(BigInteger& other) + { + using std::swap; + + swap(sign, other.sign); + mag.Swap(other.mag); + } + + const BigInteger::MagArray& BigInteger::GetMagnitude() const + { + return mag; + } + + uint32_t BigInteger::GetBitLength() const + { + if (mag.IsEmpty()) + return 0; + + int32_t res = bits::BitLengthU32(mag[mag.GetSize() - 1]); + + if (mag.GetSize() > 1) + res += (mag.GetSize() - 1) * 32; + + return res; + } + + int32_t BigInteger::GetPrecision() const + { + // See http://graphics.stanford.edu/~seander/bithacks.html + // for the details on the algorithm. + + if (mag.GetSize() == 0) + return 1; + + int32_t r = static_cast<uint32_t>((( + static_cast<uint64_t>(GetBitLength()) + 1) * 646456993ULL) >> 31); + + BigInteger prec; + BigInteger::GetPowerOfTen(r, prec); + + return Compare(prec, true) < 0 ? r : r + 1; + } + + void BigInteger::MagnitudeToBytes(common::FixedSizeArray<int8_t>& buffer) const + { + int32_t bytesNum = static_cast<int32_t>((GetBitLength() + 7) / 8); + + buffer.Reset(bytesNum); + + int32_t i; + for (i = 0; i < mag.GetSize() - 1; ++i) + { + int32_t j = bytesNum - 1 - 4 * i; + + buffer[j] = static_cast<int8_t>(mag[i]); + buffer[j - 1] = static_cast<int8_t>(mag[i] >> 8); + buffer[j - 2] = static_cast<int8_t>(mag[i] >> 16); + buffer[j - 3] = static_cast<int8_t>(mag[i] >> 24); + } + + int32_t bytesRemaining = bytesNum - 4 * i; + + assert(bytesRemaining >= 0 && bytesRemaining <= 4); + + i = 0; + switch (bytesRemaining) + { + case 4: + buffer[i++] |= static_cast<int8_t>(mag[mag.GetSize() - 1] >> 24); + + case 3: + buffer[i++] |= static_cast<int8_t>(mag[mag.GetSize() - 1] >> 16); + + case 2: + buffer[i++] |= static_cast<int8_t>(mag[mag.GetSize() - 1] >> 8); + + case 1: + buffer[i++] |= static_cast<int8_t>(mag[mag.GetSize() - 1]); + + default: + break; + } + } + + void BigInteger::Pow(int32_t exp) + { + if (exp < 0) + { + AssignInt64(0); + + return; + } + + uint32_t bitsLen = GetBitLength(); + + if (!bitsLen) + return; + + if (bitsLen == 1) + { + if ((exp % 2 == 0) && sign < 0) + sign = -sign; + + return; + } + + BigInteger multiplicant(*this); + AssignInt64(1); + + int32_t mutExp = exp; + while (mutExp) + { + if (mutExp & 1) + Multiply(multiplicant, *this); + + mutExp >>= 1; + + if (mutExp) + multiplicant.Multiply(multiplicant, multiplicant); + } + } + + void BigInteger::Multiply(const BigInteger& other, BigInteger& res) const + { + MagArray resMag(mag.GetSize() + other.mag.GetSize()); + + resMag.Resize(mag.GetSize() + other.mag.GetSize()); + + for (int32_t i = 0; i < other.mag.GetSize(); ++i) + { + uint32_t carry = 0; + + for (int32_t j = 0; j < mag.GetSize(); ++j) + { + uint64_t product = static_cast<uint64_t>(mag[j]) * other.mag[i] + + + resMag[i + j] + carry; + + resMag[i + j] = static_cast<uint32_t>(product); + carry = static_cast<uint32_t>(product >> 32); + } + + resMag[i + mag.GetSize()] = carry; + } + + res.mag.Swap(resMag); + res.sign = sign * other.sign; + + res.Normalize(); + } + + /** + * Shift magnitude left by the specified number of bits. + * + * @param in Input magnitude. + * @param len Magnitude length. + * @param out Output magnitude. Should be not shorter than the input + * magnitude. + * @param n Number of bits to shift to. + */ + void ShiftLeft(const uint32_t* in, int32_t len, uint32_t* out, unsigned n) + { + assert(n < 32); + + if (n == 0) + { + std::copy(in, in + len, out); + + return; + } + + for (int32_t i = len - 1; i > 0; --i) + out[i] = (in[i] << n) | (in[i - 1] >> (32 - n)); + + out[0] = in[0] << n; + } + + /** + * Shift magnitude right by the specified number of bits. + * + * @param in Input magnitude. + * @param len Magnitude length. + * @param out Output magnitude. Should be not shorter than the input + * magnitude. + * @param n Number of bits to shift to. + */ + void ShiftRight(const uint32_t* in, int32_t len, uint32_t* out, unsigned n) + { + assert(n < 32); + + if (n == 0) + { + std::copy(in, in + len, out); + + return; + } + + for (int32_t i = 0; i < len - 1; ++i) + out[i] = (in[i] >> n) | (in[i + 1] << (32 - n)); + + out[len - 1] = in[len - 1] >> n; + } + + /** + * Part of the division algorithm. Computes q - (a * x). + * + * @param q Minuend. + * @param a Multipliplier of the subtrahend. + * @param alen Length of the a. + * @param x Multipliplicand of the subtrahend. + * @return Carry. + */ + uint32_t MultiplyAndSubstruct(uint32_t* q, const uint32_t* a, int32_t alen, uint32_t x) + { + uint64_t carry = 0; + + for (int32_t i = 0; i < alen; ++i) + { + uint64_t product = a[i] * static_cast<uint64_t>(x); + int64_t difference = q[i] - carry - (product & 0xFFFFFFFF); + + q[i] = static_cast<uint32_t>(difference); + + // This will add one if difference is negative. + carry = (product >> 32) - (difference >> 32); + } + + return static_cast<uint32_t>(carry); + } + + /** + * Add two magnitude arrays and return carry. + * + * @param res First addend. Result is placed here. Length of this addend + * should be equal or greater than len. + * @param addend Second addend. + * @param len Length of the second addend. + * @return Carry. + */ + uint32_t Add(uint32_t* res, const uint32_t* addend, int32_t len) + { + uint64_t carry = 0; + + for (int32_t i = 0; i < len; ++i) + { + uint64_t sum = static_cast<uint64_t>(res[i]) + addend[i] + carry; + res[i] = static_cast<uint32_t>(sum); + carry = sum >> 32; + } + + return static_cast<uint32_t>(carry); + } + + /** + * Add single number to a magnitude array and return carry. + * + * @param res First addend. Result is placed here. Length of this addend + * should be equal or greater than len. + * @param len Length of the First addend. + * @param addend Second addend. + * @return Carry. + */ + uint32_t Add(uint32_t* res, int32_t len, uint32_t addend) + { + uint64_t carry = addend; + + for (int32_t i = 0; (i < len) && carry; ++i) + { + uint64_t sum = static_cast<uint64_t>(res[i]) + carry; + res[i] = static_cast<uint32_t>(sum); + carry = sum >> 32; + } + + return static_cast<uint32_t>(carry); + } + + void BigInteger::Divide(const BigInteger& divisor, BigInteger& res) const + { + Divide(divisor, res, 0); + } + + void BigInteger::Divide(const BigInteger& divisor, BigInteger& res, BigInteger& rem) const + { + Divide(divisor, res, &rem); + } + + void BigInteger::Add(const uint32_t* addend, int32_t len) + { + if (mag.GetSize() < len) + { + mag.Reserve(len + 1); + + mag.Resize(len); + } + else + mag.Reserve(mag.GetSize() + 1); + + uint32_t carry = common::Add(mag.GetData(), addend, len); + + if (carry) + { + carry = common::Add(mag.GetData() + len, mag.GetSize() - len, carry); + + if (carry) + mag.PushBack(carry); + } + } + + void BigInteger::Add(uint64_t x) + { + if (x == 0) + return; + + if (IsZero()) + { + AssignUint64(x); + + return; + } + + uint32_t val[2]; + + val[0] = static_cast<uint32_t>(x); + val[1] = static_cast<uint32_t>(x >> 32); + + Add(val, val[1] ? 2 : 1); + } + + int32_t BigInteger::Compare(const BigInteger& other, bool ignoreSign) const + { + // What we should return if magnitude is greater. + int32_t mgt = 1; + + if (!ignoreSign) + { + if (sign != other.sign) + return sign > other.sign ? 1 : -1; + else + mgt = sign; + } + + if (mag.GetSize() != other.mag.GetSize()) + return mag.GetSize() > other.mag.GetSize() ? mgt : -mgt; + + for (int32_t i = mag.GetSize() - 1; i >= 0; --i) + { + if (mag[i] == other.mag[i]) + continue; + else if (mag[i] > other.mag[i]) + return mgt; + else + return -mgt; + } + + return 0; + } + + int64_t BigInteger::ToInt64() const + { + return (static_cast<uint64_t>(GetMagInt(1)) << 32) | GetMagInt(0); + } + + void BigInteger::GetPowerOfTen(int32_t pow, BigInteger& res) + { + using namespace common; + + assert(pow >= 0); + + if (pow < bits::UINT64_MAX_PRECISION) + { + res.AssignUint64(bits::TenPowerU64(pow)); + + return; + } + + res.AssignInt64(10); + res.Pow(pow); + } + + uint32_t BigInteger::GetMagInt(int32_t n) const + { + assert(n >= 0); + + if (n >= mag.GetSize()) + return sign > 0 ? 0 : -1; + + return sign * mag[n]; + } + + void BigInteger::Divide(const BigInteger& divisor, BigInteger& res, BigInteger* rem) const + { + // Can't divide by zero. + if (divisor.mag.IsEmpty()) + throw IgniteError(IgniteError::IGNITE_ERR_ILLEGAL_ARGUMENT, "Division by zero."); + + int32_t compRes = Compare(divisor, true); + + int8_t resSign = sign * divisor.sign; + + // The same magnitude. Result is [-]1 and remainder is zero. + if (compRes == 0) + { + res.AssignInt64(resSign); + + if (rem) + rem->AssignInt64(0); + + return; + } + + // Divisor is greater than this. Result is 0 and remainder is this. + if (compRes == -1) + { + // Order is important here! Copy to rem first to handle the case + // when &res == this. + if (rem) + rem->Assign(*this); + + res.AssignInt64(0); + + return; + } + + // If divisor is [-]1 result is [-]this and remainder is zero. + if (divisor.GetBitLength() == 1) + { + // Once again: order is important. + res.Assign(*this); + res.sign = sign * divisor.sign; + + if (rem) + rem->AssignInt64(0); + + return; + } + + // Trivial case. + if (mag.GetSize() <= 2) + { + uint64_t u = mag[0]; + uint64_t v = divisor.mag[0]; + + if (mag.GetSize() == 2) + u |= static_cast<uint64_t>(mag[1]) << 32; + + if (divisor.mag.GetSize() == 2) + v |= static_cast<uint64_t>(divisor.mag[1]) << 32; + + // Divisor can not be 1, or 0. + assert(v > 1); + + // It should also be less than dividend. + assert(v < u); + + // (u / v) is always fits into int64_t because abs(v) >= 2. + res.AssignInt64(resSign * static_cast<int64_t>(u / v)); + + // (u % v) is always fits into int64_t because (u > v) -> + // (u % v) < (u / 2). + if (rem) + rem->AssignInt64(resSign * static_cast<int64_t>(u % v)); + + return; + } + + // Using Knuth division algorithm D for common case. + + // Short aliases. + const MagArray& u = mag; + const MagArray& v = divisor.mag; + MagArray& q = res.mag; + int32_t ulen = u.GetSize(); + int32_t vlen = v.GetSize(); + + // First we need to normilize divisor. + MagArray nv; + nv.Resize(v.GetSize()); + + int32_t shift = bits::NumberOfLeadingZerosU32(v.Back()); + ShiftLeft(v.GetData(), vlen, nv.GetData(), shift); + + // Divisor is normilized. Now we need to normilize divident. + MagArray nu; + + // First find out what is the size of it. + if (bits::NumberOfLeadingZerosU32(u.Back()) >= shift) + { + // Everything is the same as with divisor. Just add leading zero. + nu.Resize(ulen + 1); + + ShiftLeft(u.GetData(), ulen, nu.GetData(), shift); + + assert((static_cast<uint64_t>(u.Back()) >> (32 - shift)) == 0); + } + else + { + // We need one more byte here. Also adding leading zero. + nu.Resize(ulen + 2); + + ShiftLeft(u.GetData(), ulen, nu.GetData(), shift); + + nu[ulen] = u[ulen - 1] >> (32 - shift); + + assert(nu[ulen] != 0); + } + + assert(nu.Back() == 0); + + // Resizing resulting array. + q.Resize(ulen - vlen + 1); + + // Main loop + for (int32_t i = ulen - vlen; i >= 0; --i) + { + uint64_t base = bits::MakeU64(nu[i + vlen], nu[i + vlen - 1]); + + uint64_t qhat = base / nv[vlen - 1]; // Estimated quotient. + uint64_t rhat = base % nv[vlen - 1]; // A remainder. + + // Adjusting result if needed. + while (qhat > UINT32_MAX || + ((qhat * nv[vlen - 2]) > ((UINT32_MAX + 1ULL) * rhat + nu[i + vlen - 2]))) + { + --qhat; + rhat += nv[vlen - 1]; + + if (rhat > UINT32_MAX) + break; + } + + uint32_t qhat32 = static_cast<uint32_t>(qhat); + + // Multiply and subtract. + uint32_t carry = MultiplyAndSubstruct(nu.GetData() + i, nv.GetData(), vlen, qhat32); + + int64_t difference = nu[i + vlen] - carry; + + nu[i + vlen] = static_cast<uint32_t>(difference); + + if (difference < 0) + { + --qhat32; + carry = common::Add(nu.GetData() + i, nv.GetData(), vlen); + + assert(carry == 0); + } + + q[i] = qhat32; + } + + res.sign = resSign; + res.Normalize(); + + // If remainder is needed unnormolize it. + if (rem) + { + rem->sign = resSign; + rem->mag.Resize(vlen); + + ShiftRight(nu.GetData(), rem->mag.GetSize(), rem->mag.GetData(), shift); + + rem->Normalize(); + } + } + + void BigInteger::Normalize() + { + int32_t lastNonZero = mag.GetSize() - 1; + while (lastNonZero >= 0 && mag[lastNonZero] == 0) + --lastNonZero; + + mag.Resize(lastNonZero + 1); + } + + bool operator==(const BigInteger& val1, const BigInteger& val2) + { + return val1.Compare(val2) == 0; + } + + bool operator!=(const BigInteger& val1, const BigInteger& val2) + { + return val1.Compare(val2) != 0; + } + + bool operator<(const BigInteger& val1, const BigInteger& val2) + { + return val1.Compare(val2) < 0; + } + + bool operator<=(const BigInteger& val1, const BigInteger& val2) + { + return val1.Compare(val2) <= 0; + } + + bool operator>(const BigInteger& val1, const BigInteger& val2) + { + return val1.Compare(val2) > 0; + } + + bool operator>=(const BigInteger& val1, const BigInteger& val2) + { + return val1.Compare(val2) >= 0; + } + } +} +
http://git-wip-us.apache.org/repos/asf/ignite/blob/5cc1f074/modules/platforms/cpp/common/src/common/bits.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/common/src/common/bits.cpp b/modules/platforms/cpp/common/src/common/bits.cpp new file mode 100644 index 0000000..93f2221 --- /dev/null +++ b/modules/platforms/cpp/common/src/common/bits.cpp @@ -0,0 +1,233 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <algorithm> +#include <cassert> + +#include "ignite/common/bits.h" + +namespace ignite +{ + namespace common + { + namespace bits + { + int32_t NumberOfTrailingZerosI32(int32_t i) + { + int32_t y; + + if (i == 0) return 32; + + int32_t n = 31; + + y = i << 16; + + if (y != 0) { + n = n - 16; + i = y; + } + + y = i << 8; + + if (y != 0) { + n = n - 8; + i = y; + } + + y = i << 4; + + if (y != 0) { + n = n - 4; + i = y; + } + + y = i << 2; + + if (y != 0) { + n = n - 2; + i = y; + } + + return n - static_cast<int32_t>(static_cast<uint32_t>(i << 1) >> 31); + } + + int32_t NumberOfLeadingZerosI32(int32_t i) + { + return NumberOfLeadingZerosU32(static_cast<uint32_t>(i)); + } + + int32_t NumberOfLeadingZerosU32(uint32_t i) + { + if (i == 0) + return 32; + + int32_t n = 1; + + if (i >> 16 == 0) { + n += 16; + i <<= 16; + } + + if (i >> 24 == 0) { + n += 8; + i <<= 8; + } + + if (i >> 28 == 0) { + n += 4; + i <<= 4; + } + + if (i >> 30 == 0) { + n += 2; + i <<= 2; + } + + return n - static_cast<int32_t>(i >> 31); + } + + int32_t NumberOfLeadingZerosI64(int64_t i) + { + return NumberOfLeadingZerosU64(static_cast<uint64_t>(i)); + } + + int32_t NumberOfLeadingZerosU64(uint64_t i) + { + if (i == 0) + return 64; + + int32_t n = 1; + + uint32_t x = static_cast<uint32_t>(i >> 32); + + if (x == 0) { + n += 32; + x = static_cast<uint32_t>(i); + } + + if (x >> 16 == 0) { + n += 16; + x <<= 16; + } + + if (x >> 24 == 0) { + n += 8; + x <<= 8; + } + + if (x >> 28 == 0) { + n += 4; + x <<= 4; + } + + if (x >> 30 == 0) { + n += 2; + x <<= 2; + } + + n -= x >> 31; + + return n; + } + + int32_t BitCountI32(int32_t i) + { + uint32_t ui = static_cast<uint32_t>(i); + + ui -= (ui >> 1) & 0x55555555; + ui = (ui & 0x33333333) + ((ui >> 2) & 0x33333333); + ui = (ui + (ui >> 4)) & 0x0f0f0f0f; + ui += ui >> 8; + ui += ui >> 16; + + return static_cast<int32_t>(ui & 0x3f); + } + + int32_t BitLengthI32(int32_t i) + { + return 32 - NumberOfLeadingZerosI32(i); + } + + int32_t BitLengthU32(uint32_t i) + { + return 32 - NumberOfLeadingZerosU32(i); + } + + int32_t GetCapasityForSize(int32_t size) + { + assert(size > 0); + + if (size <= 8) + return 8; + + int32_t bl = BitLengthI32(size); + + if (bl > 30) + return INT32_MAX; + + int32_t res = 1 << bl; + + return size > res ? res << 1 : res; + } + + int32_t DigitLength(uint64_t x) + { + // See http://graphics.stanford.edu/~seander/bithacks.html + // for the details on the algorithm. + + if (x < 10) + return 1; + + int32_t r = ((64 - NumberOfLeadingZerosU64(x) + 1) * 1233) >> 12; + + assert(r <= UINT64_MAX_PRECISION); + + return (r == UINT64_MAX_PRECISION || x < TenPowerU64(r)) ? r : r + 1; + } + + uint64_t TenPowerU64(int32_t n) + { + static const uint64_t TEN_POWERS_TABLE[UINT64_MAX_PRECISION] = { + 1ULL, // 0 / 10^0 + 10ULL, // 1 / 10^1 + 100ULL, // 2 / 10^2 + 1000ULL, // 3 / 10^3 + 10000ULL, // 4 / 10^4 + 100000ULL, // 5 / 10^5 + 1000000ULL, // 6 / 10^6 + 10000000ULL, // 7 / 10^7 + 100000000ULL, // 8 / 10^8 + 1000000000ULL, // 9 / 10^9 + 10000000000ULL, // 10 / 10^10 + 100000000000ULL, // 11 / 10^11 + 1000000000000ULL, // 12 / 10^12 + 10000000000000ULL, // 13 / 10^13 + 100000000000000ULL, // 14 / 10^14 + 1000000000000000ULL, // 15 / 10^15 + 10000000000000000ULL, // 16 / 10^16 + 100000000000000000ULL, // 17 / 10^17 + 1000000000000000000ULL, // 18 / 10^18 + 10000000000000000000ULL // 19 / 10^19 + }; + + assert(n >= 0 && n < UINT64_MAX_PRECISION); + + return TEN_POWERS_TABLE[n]; + } + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5cc1f074/modules/platforms/cpp/core-test/Makefile.am ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core-test/Makefile.am b/modules/platforms/cpp/core-test/Makefile.am index d1f4ca5..7a62e8e 100644 --- a/modules/platforms/cpp/core-test/Makefile.am +++ b/modules/platforms/cpp/core-test/Makefile.am @@ -47,6 +47,7 @@ ignite_tests_LDFLAGS = \ -static-libtool-libs ignite_tests_SOURCES = \ + src/bits_test.cpp \ src/cache_test.cpp \ src/cache_query_test.cpp \ src/concurrent_test.cpp \ @@ -58,6 +59,9 @@ ignite_tests_SOURCES = \ src/binary_reader_writer_raw_test.cpp \ src/binary_reader_writer_test.cpp \ src/binary_session_test.cpp \ + src/decimal_test.cpp \ + src/dynamic_size_array_test.cpp \ + src/fixed_size_array_test.cpp \ src/transactions_test.cpp \ src/teamcity_messages.cpp \ src/teamcity_boost.cpp http://git-wip-us.apache.org/repos/asf/ignite/blob/5cc1f074/modules/platforms/cpp/core-test/project/vs/core-test.vcxproj ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core-test/project/vs/core-test.vcxproj b/modules/platforms/cpp/core-test/project/vs/core-test.vcxproj index edf87ba..acdfee0 100644 --- a/modules/platforms/cpp/core-test/project/vs/core-test.vcxproj +++ b/modules/platforms/cpp/core-test/project/vs/core-test.vcxproj @@ -22,6 +22,9 @@ <ProjectReference Include="..\..\..\binary\project\vs\binary.vcxproj"> <Project>{4f15669b-92eb-49f0-b774-8f19bae0b960}</Project> </ProjectReference> + <ProjectReference Include="..\..\..\common\project\vs\common.vcxproj"> + <Project>{b63f2e01-5157-4719-8491-0e1c7cd3b701}</Project> + </ProjectReference> <ProjectReference Include="..\..\..\core\project\vs\core.vcxproj"> <Project>{e2dea693-f2ea-43c2-a813-053378f6e4db}</Project> </ProjectReference> @@ -36,6 +39,9 @@ <ItemGroup> <ClCompile Include="..\..\src\cache_test.cpp" /> <ClCompile Include="..\..\src\concurrent_test.cpp" /> + <ClCompile Include="..\..\src\decimal_test.cpp" /> + <ClCompile Include="..\..\src\dynamic_size_array_test.cpp" /> + <ClCompile Include="..\..\src\fixed_size_array_test.cpp" /> <ClCompile Include="..\..\src\ignite_error_test.cpp" /> <ClCompile Include="..\..\src\ignition_test.cpp" /> <ClCompile Include="..\..\src\handle_registry_test.cpp" /> @@ -45,6 +51,7 @@ <ClCompile Include="..\..\src\binary_test_defs.cpp" /> <ClCompile Include="..\..\src\cache_query_test.cpp" /> <ClCompile Include="..\..\src\interop_memory_test.cpp" /> + <ClCompile Include="..\..\src\bits_test.cpp" /> <ClCompile Include="..\..\src\teamcity_boost.cpp" /> <ClCompile Include="..\..\src\teamcity_messages.cpp" /> <ClCompile Include="..\..\src\transactions_test.cpp" /> http://git-wip-us.apache.org/repos/asf/ignite/blob/5cc1f074/modules/platforms/cpp/core-test/project/vs/core-test.vcxproj.filters ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core-test/project/vs/core-test.vcxproj.filters b/modules/platforms/cpp/core-test/project/vs/core-test.vcxproj.filters index 2259f4c..0366374 100644 --- a/modules/platforms/cpp/core-test/project/vs/core-test.vcxproj.filters +++ b/modules/platforms/cpp/core-test/project/vs/core-test.vcxproj.filters @@ -43,6 +43,18 @@ <ClCompile Include="..\..\src\transactions_test.cpp"> <Filter>Code</Filter> </ClCompile> + <ClCompile Include="..\..\src\bits_test.cpp"> + <Filter>Code</Filter> + </ClCompile> + <ClCompile Include="..\..\src\decimal_test.cpp"> + <Filter>Code</Filter> + </ClCompile> + <ClCompile Include="..\..\src\fixed_size_array_test.cpp"> + <Filter>Code</Filter> + </ClCompile> + <ClCompile Include="..\..\src\dynamic_size_array_test.cpp"> + <Filter>Code</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\include\teamcity_messages.h"> http://git-wip-us.apache.org/repos/asf/ignite/blob/5cc1f074/modules/platforms/cpp/core-test/src/bits_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core-test/src/bits_test.cpp b/modules/platforms/cpp/core-test/src/bits_test.cpp new file mode 100644 index 0000000..3aadf36 --- /dev/null +++ b/modules/platforms/cpp/core-test/src/bits_test.cpp @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MSC_VER +# define BOOST_TEST_DYN_LINK +#endif + +#include <boost/test/unit_test.hpp> + +#include <ignite/common/bits.h> + +using namespace ignite; +using namespace ignite::common::bits; + +BOOST_AUTO_TEST_SUITE(BitsTestSuite) + +BOOST_AUTO_TEST_CASE(TestNumberOfLeadingZeroes) +{ + BOOST_CHECK_EQUAL(32, NumberOfLeadingZerosI32(0)); + + BOOST_CHECK_EQUAL(31, NumberOfLeadingZerosI32(1)); + + BOOST_CHECK_EQUAL(30, NumberOfLeadingZerosI32(2)); + BOOST_CHECK_EQUAL(30, NumberOfLeadingZerosI32(3)); + + BOOST_CHECK_EQUAL(29, NumberOfLeadingZerosI32(4)); + BOOST_CHECK_EQUAL(29, NumberOfLeadingZerosI32(5)); + BOOST_CHECK_EQUAL(29, NumberOfLeadingZerosI32(7)); + + BOOST_CHECK_EQUAL(28, NumberOfLeadingZerosI32(8)); + BOOST_CHECK_EQUAL(28, NumberOfLeadingZerosI32(12)); + BOOST_CHECK_EQUAL(28, NumberOfLeadingZerosI32(15)); + + BOOST_CHECK_EQUAL(0, NumberOfLeadingZerosI32(0xFFFFFFFF)); + BOOST_CHECK_EQUAL(0, NumberOfLeadingZerosI32(0x80000000)); + + BOOST_CHECK_EQUAL(1, NumberOfLeadingZerosI32(0x7FFFFFFF)); + BOOST_CHECK_EQUAL(1, NumberOfLeadingZerosI32(0x40000000)); + + BOOST_CHECK_EQUAL(8, NumberOfLeadingZerosI32(0x00FFFFFF)); + BOOST_CHECK_EQUAL(8, NumberOfLeadingZerosI32(0x00F00000)); + BOOST_CHECK_EQUAL(8, NumberOfLeadingZerosI32(0x00800000)); + + BOOST_CHECK_EQUAL(9, NumberOfLeadingZerosI32(0x00700000)); + BOOST_CHECK_EQUAL(9, NumberOfLeadingZerosI32(0x00400000)); + BOOST_CHECK_EQUAL(9, NumberOfLeadingZerosI32(0x006C0395)); +} + +BOOST_AUTO_TEST_CASE(TestNumberOfTrailingZeroes) +{ + BOOST_CHECK_EQUAL(0, NumberOfTrailingZerosI32(1)); + BOOST_CHECK_EQUAL(0, NumberOfTrailingZerosI32(3)); + BOOST_CHECK_EQUAL(0, NumberOfTrailingZerosI32(5)); + BOOST_CHECK_EQUAL(0, NumberOfTrailingZerosI32(7)); + BOOST_CHECK_EQUAL(0, NumberOfTrailingZerosI32(15)); + BOOST_CHECK_EQUAL(0, NumberOfTrailingZerosI32(0xFFFFFFFF)); + BOOST_CHECK_EQUAL(0, NumberOfTrailingZerosI32(0x7FFFFFFF)); + BOOST_CHECK_EQUAL(0, NumberOfTrailingZerosI32(0x00FFFFFF)); + BOOST_CHECK_EQUAL(0, NumberOfTrailingZerosI32(0x006C0395)); + + BOOST_CHECK_EQUAL(1, NumberOfTrailingZerosI32(2)); + + BOOST_CHECK_EQUAL(2, NumberOfTrailingZerosI32(4)); + BOOST_CHECK_EQUAL(2, NumberOfTrailingZerosI32(12)); + + BOOST_CHECK_EQUAL(3, NumberOfTrailingZerosI32(8)); + + BOOST_CHECK_EQUAL(20, NumberOfTrailingZerosI32(0xFFF00000)); + BOOST_CHECK_EQUAL(20, NumberOfTrailingZerosI32(0x00F00000)); + BOOST_CHECK_EQUAL(20, NumberOfTrailingZerosI32(0x00700000)); + BOOST_CHECK_EQUAL(20, NumberOfTrailingZerosI32(0x80700000)); + + BOOST_CHECK_EQUAL(22, NumberOfTrailingZerosI32(0x00400000)); + BOOST_CHECK_EQUAL(22, NumberOfTrailingZerosI32(0x80400000)); + BOOST_CHECK_EQUAL(22, NumberOfTrailingZerosI32(0x10400000)); + + BOOST_CHECK_EQUAL(23, NumberOfTrailingZerosI32(0x00800000)); + BOOST_CHECK_EQUAL(23, NumberOfTrailingZerosI32(0x80800000)); + BOOST_CHECK_EQUAL(23, NumberOfTrailingZerosI32(0xFF800000)); + + BOOST_CHECK_EQUAL(30, NumberOfTrailingZerosI32(0x40000000)); + BOOST_CHECK_EQUAL(30, NumberOfTrailingZerosI32(0xC0000000)); + + BOOST_CHECK_EQUAL(31, NumberOfTrailingZerosI32(0x80000000)); + + BOOST_CHECK_EQUAL(32, NumberOfTrailingZerosI32(0)); +} + +BOOST_AUTO_TEST_CASE(TestBitCount) +{ + BOOST_CHECK_EQUAL(0, BitCountI32(0)); + + for (int j = 0; j < 32; ++j) + { + const int32_t testNum = 0xFFFFFFFFUL >> (31 - j); + + for (int i = 0; i < (32 - j); ++i) + BOOST_CHECK_EQUAL(j + 1, BitCountI32(testNum)); + } + + for (int j = 0; j < 32; j += 2) + { + const int32_t testNum = 0xAAAAAAAAUL >> (31 - j); + + for (int i = 0; i < (32 - j); ++i) + BOOST_CHECK_EQUAL((j / 2) + 1, BitCountI32(testNum)); + } +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/5cc1f074/modules/platforms/cpp/core-test/src/decimal_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core-test/src/decimal_test.cpp b/modules/platforms/cpp/core-test/src/decimal_test.cpp new file mode 100644 index 0000000..47fe8fc --- /dev/null +++ b/modules/platforms/cpp/core-test/src/decimal_test.cpp @@ -0,0 +1,1101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MSC_VER +# define BOOST_TEST_DYN_LINK +#endif + +#include <boost/test/unit_test.hpp> + +#include <ignite/common/bits.h> +#include <ignite/common/decimal.h> + +using namespace ignite; +using namespace ignite::common; +using namespace ignite::common::bits; + +template<typename T> +void CheckOutputSimple(int64_t val) +{ + T dec(val); + + std::stringstream ss1; + std::stringstream ss2; + + ss1 << val; + ss2 << dec; + + BOOST_CHECK_EQUAL(ss1.str(), ss2.str()); +} + +template<typename T> +void CheckInputOutput(const std::string& val) +{ + T dec; + std::string res; + + std::stringstream ss1; + ss1 << val; + ss1 >> dec; + + std::stringstream ss2; + ss2 << dec; + res = ss2.str(); + + BOOST_CHECK_EQUAL(val, res); +} + +template<typename T> +void CheckOutputInput(const T& val) +{ + T dec; + std::stringstream ss; + ss << val; + ss >> dec; + + BOOST_CHECK_EQUAL(val, dec); +} + +void CheckDoubleCast(double val) +{ + Decimal dec; + + dec.AssignDouble(val); + + BOOST_CHECK_CLOSE(val, dec.ToDouble(), 1E-10); +} + +BOOST_AUTO_TEST_SUITE(DecimalTestSuite) + +BOOST_AUTO_TEST_CASE(TestMultiplyBigIntegerArguments) +{ + BigInteger bigInt(12345); + + BigInteger res; + + // 152399025 + bigInt.Multiply(BigInteger(12345), res); + + { + const BigInteger::MagArray &mag = res.GetMagnitude(); + + BOOST_CHECK_EQUAL(mag.GetSize(), 1); + + BOOST_CHECK_EQUAL(mag[0], 152399025ULL); + } + + // 152399025 + bigInt.AssignInt64(12345); + bigInt.Multiply(bigInt, res); + + { + const BigInteger::MagArray &mag = res.GetMagnitude(); + + BOOST_CHECK_EQUAL(mag.GetSize(), 1); + + BOOST_CHECK_EQUAL(mag[0], 152399025ULL); + } + + // 152399025 + bigInt.AssignInt64(12345); + bigInt.Multiply(BigInteger(12345), bigInt); + + { + const BigInteger::MagArray &mag = bigInt.GetMagnitude(); + + BOOST_CHECK_EQUAL(mag.GetSize(), 1); + + BOOST_CHECK_EQUAL(mag[0], 152399025ULL); + } + + // 152399025 + bigInt.AssignInt64(12345); + bigInt.Multiply(bigInt, bigInt); + + { + const BigInteger::MagArray &mag = bigInt.GetMagnitude(); + + BOOST_CHECK_EQUAL(mag.GetSize(), 1); + + BOOST_CHECK_EQUAL(mag[0], 152399025ULL); + } +} + +BOOST_AUTO_TEST_CASE(TestMultiplyBigIntegerBigger) +{ + BigInteger bigInt(12345); + + BigInteger buf; + + // 152399025 + bigInt.Multiply(bigInt, bigInt); + + buf.Assign(bigInt); + + // 3539537889086624823140625 + // 0002 ED86 BBC3 30D1 DDC6 6111 + bigInt.Multiply(buf, bigInt); + bigInt.Multiply(buf, bigInt); + + { + const BigInteger::MagArray &mag = bigInt.GetMagnitude(); + + BOOST_CHECK_EQUAL(mag.GetSize(), 3); + + BOOST_CHECK_EQUAL(mag[0], 0xDDC66111); + BOOST_CHECK_EQUAL(mag[1], 0xBBC330D1); + BOOST_CHECK_EQUAL(mag[2], 0x0002ED86); + } + + // 2698355789040138398691723863616167551412718750 == + // 0078 FF9A F760 4E12 4A1F 3179 D038 D455 630F CC9E + bigInt.Multiply(BigInteger(32546826734), bigInt); + bigInt.Multiply(BigInteger(23423079641), bigInt); + + { + const BigInteger::MagArray &mag = bigInt.GetMagnitude(); + + BOOST_CHECK_EQUAL(mag.GetSize(), 5); + + BOOST_CHECK_EQUAL(mag[0], 0x630FCC9E); + BOOST_CHECK_EQUAL(mag[1], 0xD038D455); + BOOST_CHECK_EQUAL(mag[2], 0x4A1F3179); + BOOST_CHECK_EQUAL(mag[3], 0xF7604E12); + BOOST_CHECK_EQUAL(mag[4], 0x0078FF9A); + } +} + +BOOST_AUTO_TEST_CASE(TestPowBigInteger) +{ + BigInteger bigInt(12345); + + { + const BigInteger::MagArray &mag = bigInt.GetMagnitude(); + + BOOST_CHECK_EQUAL(mag.GetSize(), 1); + + BOOST_CHECK_EQUAL(mag[0], 12345); + } + + // 152399025 + bigInt.Pow(2); + + { + const BigInteger::MagArray &mag = bigInt.GetMagnitude(); + + BOOST_CHECK_EQUAL(mag.GetSize(), 1); + + BOOST_CHECK_EQUAL(mag[0], 152399025ULL); + } + + // 3539537889086624823140625 + // 0002 ED86 BBC3 30D1 DDC6 6111 + bigInt.Pow(3); + + { + const BigInteger::MagArray &mag = bigInt.GetMagnitude(); + + BOOST_CHECK_EQUAL(mag.GetSize(), 3); + + BOOST_CHECK_EQUAL(mag[0], 0xDDC66111); + BOOST_CHECK_EQUAL(mag[1], 0xBBC330D1); + BOOST_CHECK_EQUAL(mag[2], 0x0002ED86); + } + + //3086495556566025694024226933269611093366465997140345415945924110519533775 + //2241867322136254278528975546698722592953892009291022792452635153187272387 + //9105398830363346664660724134489229239181447334384883937966927158758068117 + //094808258116245269775390625 + // + // 0000 B4D0 1355 772E + // C174 C5F3 B840 74ED 6A54 B544 48E1 E308 6A80 6050 7D37 A56F + // 54E6 FF91 13FF 7B0A 455C F649 F4CD 37D0 C5B0 0507 1BFD 9083 + // 8F13 08B4 D962 08FC FBC0 B5AB F9F9 06C9 94B3 9715 8C43 C94F + // 4891 09E5 57AA 66C9 A4F4 3494 A938 89FE 87AF 9056 7D90 17A1 + bigInt.Pow(10); + + { + const BigInteger::MagArray &mag = bigInt.GetMagnitude(); + + BOOST_CHECK_EQUAL(mag.GetSize(), 26); + + BOOST_CHECK_EQUAL(mag[0], 0x7D9017A1); + BOOST_CHECK_EQUAL(mag[1], 0x87AF9056); + BOOST_CHECK_EQUAL(mag[2], 0xA93889FE); + BOOST_CHECK_EQUAL(mag[3], 0xA4F43494); + BOOST_CHECK_EQUAL(mag[4], 0x57AA66C9); + BOOST_CHECK_EQUAL(mag[5], 0x489109E5); + BOOST_CHECK_EQUAL(mag[6], 0x8C43C94F); + BOOST_CHECK_EQUAL(mag[7], 0x94B39715); + BOOST_CHECK_EQUAL(mag[8], 0xF9F906C9); + BOOST_CHECK_EQUAL(mag[9], 0xFBC0B5AB); + BOOST_CHECK_EQUAL(mag[10], 0xD96208FC); + BOOST_CHECK_EQUAL(mag[11], 0x8F1308B4); + BOOST_CHECK_EQUAL(mag[12], 0x1BFD9083); + BOOST_CHECK_EQUAL(mag[13], 0xC5B00507); + BOOST_CHECK_EQUAL(mag[14], 0xF4CD37D0); + BOOST_CHECK_EQUAL(mag[15], 0x455CF649); + BOOST_CHECK_EQUAL(mag[16], 0x13FF7B0A); + BOOST_CHECK_EQUAL(mag[17], 0x54E6FF91); + BOOST_CHECK_EQUAL(mag[18], 0x7D37A56F); + BOOST_CHECK_EQUAL(mag[19], 0x6A806050); + BOOST_CHECK_EQUAL(mag[20], 0x48E1E308); + BOOST_CHECK_EQUAL(mag[21], 0x6A54B544); + BOOST_CHECK_EQUAL(mag[22], 0xB84074ED); + BOOST_CHECK_EQUAL(mag[23], 0xC174C5F3); + BOOST_CHECK_EQUAL(mag[24], 0x1355772E); + BOOST_CHECK_EQUAL(mag[25], 0x0000B4D0); + } + + bigInt.AssignInt64(-1); + + bigInt.Pow(57298735); + BOOST_REQUIRE_EQUAL(bigInt.ToInt64(), -1); + + bigInt.Pow(325347312); + BOOST_REQUIRE_EQUAL(bigInt.ToInt64(), 1); + + bigInt.AssignInt64(2); + + bigInt.Pow(10); + BOOST_REQUIRE_EQUAL(bigInt.ToInt64(), 1024); + + bigInt.AssignInt64(-2); + + bigInt.Pow(10); + BOOST_REQUIRE_EQUAL(bigInt.ToInt64(), 1024); + + bigInt.AssignInt64(2); + + bigInt.Pow(11); + BOOST_REQUIRE_EQUAL(bigInt.ToInt64(), 2048); + + bigInt.AssignInt64(-2); + + bigInt.Pow(11); + BOOST_REQUIRE_EQUAL(bigInt.ToInt64(), -2048); +} + +BOOST_AUTO_TEST_CASE(TestMultiplyDivideSimple) +{ + BigInteger val; + BigInteger res; + BigInteger rem; + + val.AssignInt64(23225462820950625LL); + + // 23225462820 and 950625 + BigInteger bi1; + BigInteger bi2; + val.Divide(BigInteger(1000000), bi1, bi2); + + // 23225 and 462820 + BigInteger bi3; + BigInteger bi4; + bi1.Divide(BigInteger(1000000), bi3, bi4); + + BOOST_CHECK_EQUAL(bi2.ToInt64(), 950625LL); + BOOST_CHECK_EQUAL(bi3.ToInt64(), 23225LL); + BOOST_CHECK_EQUAL(bi4.ToInt64(), 462820LL); + + BigInteger(0).Divide(BigInteger(1), res, rem); + + BOOST_CHECK_EQUAL(res, BigInteger(0)); + BOOST_CHECK_EQUAL(rem, BigInteger(0)); + + BigInteger(0).Divide(BigInteger(100), res, rem); + + BOOST_CHECK_EQUAL(res, BigInteger(0)); + BOOST_CHECK_EQUAL(rem, BigInteger(0)); + + BigInteger(0).Divide(BigInteger(-1), res, rem); + + BOOST_CHECK_EQUAL(res, BigInteger(0)); + BOOST_CHECK_EQUAL(rem, BigInteger(0)); + + BigInteger(0).Divide(BigInteger(-100), res, rem); + + BOOST_CHECK_EQUAL(res, BigInteger(0)); + BOOST_CHECK_EQUAL(rem, BigInteger(0)); + + BigInteger(1).Divide(BigInteger(1), res, rem); + + BOOST_CHECK_EQUAL(res, BigInteger(1)); + BOOST_CHECK_EQUAL(rem, BigInteger(0)); + + BigInteger(10).Divide(BigInteger(1), res, rem); + + BOOST_CHECK_EQUAL(res, BigInteger(10)); + BOOST_CHECK_EQUAL(rem, BigInteger(0)); + + BigInteger(-1).Divide(BigInteger(1), res, rem); + + BOOST_CHECK_EQUAL(res, BigInteger(-1)); + BOOST_CHECK_EQUAL(rem, BigInteger(0)); + + BigInteger(-10).Divide(BigInteger(1), res, rem); + + BOOST_CHECK_EQUAL(res, BigInteger(-10)); + BOOST_CHECK_EQUAL(rem, BigInteger(0)); + + BigInteger(1).Divide(BigInteger(-1), res, rem); + + BOOST_CHECK_EQUAL(res, BigInteger(-1)); + BOOST_CHECK_EQUAL(rem, BigInteger(0)); + + BigInteger(10).Divide(BigInteger(-1), res, rem); + + BOOST_CHECK_EQUAL(res, BigInteger(-10)); + BOOST_CHECK_EQUAL(rem, BigInteger(0)); + + BigInteger(-1).Divide(BigInteger(-1), res, rem); + + BOOST_CHECK_EQUAL(res, BigInteger(1)); + BOOST_CHECK_EQUAL(rem, BigInteger(0)); + + BigInteger(-10).Divide(BigInteger(-1), res, rem); + + BOOST_CHECK_EQUAL(res, BigInteger(10)); + BOOST_CHECK_EQUAL(rem, BigInteger(0)); + + BigInteger(123456789).Divide(BigInteger(1000), res); + BOOST_CHECK_EQUAL(res, BigInteger(123456)); + + val.AssignInt64(79823695862); + val.Divide(val, res); + + BOOST_CHECK_EQUAL(res, BigInteger(1)); + + val.AssignInt64(28658345673); + val.Divide(val, val); + + BOOST_CHECK_EQUAL(val, BigInteger(1)); + + val.AssignInt64(-97598673406); + val.Divide(val, res, val); + + BOOST_CHECK_EQUAL(res, BigInteger(1)); + BOOST_CHECK_EQUAL(val, BigInteger(0)); + + val.AssignInt64(1); + val.Divide(val, res, val); + + BOOST_CHECK_EQUAL(res, BigInteger(1)); + BOOST_CHECK_EQUAL(val, BigInteger(0)); +} + +BOOST_AUTO_TEST_CASE(TestDivideBigger) +{ + BigInteger res; + BigInteger rem; + + BigInteger("4790467782742318458842833081").Divide(BigInteger(1000000000000000000LL), res, rem); + + BOOST_CHECK_EQUAL(res.ToInt64(), 4790467782LL); + BOOST_CHECK_EQUAL(rem.ToInt64(), 742318458842833081LL); + + BigInteger("4790467782742318458842833081").Divide(BigInteger("10000000000000000000"), res, rem); + + BOOST_CHECK_EQUAL(res.ToInt64(), 479046778LL); + BOOST_CHECK_EQUAL(rem.ToInt64(), 2742318458842833081LL); + + BigInteger("328569986734256745892025106351608546013457217305539845689265945043650274304152384502658961485730864386").Divide( + BigInteger("759823640567289574925305534862590863490856903465"), res, rem); + + BOOST_CHECK_EQUAL(res, BigInteger("432429275942170114314334535709873138296890293268042448")); + BOOST_CHECK_EQUAL(rem, BigInteger("725289323707320757244048053769339286218272582066")); + + BigInteger("5789420569340865906230645903456092386459628364580763804659834658960883465807263084659832648768603645").Divide( + BigInteger("-29064503640646565660609983646665763458768340596340586"), res, rem); + + BOOST_CHECK_EQUAL(res, BigInteger("-199192136253942064949205579447876757418653967046")); + BOOST_CHECK_EQUAL(rem, BigInteger("-9693519879390725820633207073869515731754969332274689")); + + BigInteger("-107519074510758034695616045096493659264398569023607895679428769875976987594876903458769799098378994985793874569869348579").Divide( + BigInteger("197290846190263940610876503491586943095983984894898998999751636576150263056012501"), res, rem); + + BOOST_CHECK_EQUAL(res, BigInteger("-544977512069001243499439196429495600701")); + BOOST_CHECK_EQUAL(rem, BigInteger("-66382358009926062210728796777352226675944219851838448875365359123421443108985378")); + + BigInteger("9739565432896546050040656034658762836457836886868678345021405632645902354063045608267340568346582").Divide( + BigInteger("8263050146508634250640862503465899340625908694088569038"), res); + + BOOST_CHECK_EQUAL(res, BigInteger("1178688893351540421358600789386475098289416")); +} + +BOOST_AUTO_TEST_CASE(TestOutputSimpleBigInteger) +{ + CheckOutputSimple<BigInteger>(0); + + CheckOutputSimple<BigInteger>(1); + CheckOutputSimple<BigInteger>(9); + CheckOutputSimple<BigInteger>(10); + CheckOutputSimple<BigInteger>(11); + CheckOutputSimple<BigInteger>(19); + CheckOutputSimple<BigInteger>(123); + CheckOutputSimple<BigInteger>(1234); + CheckOutputSimple<BigInteger>(12345); + CheckOutputSimple<BigInteger>(123456); + CheckOutputSimple<BigInteger>(1234567); + CheckOutputSimple<BigInteger>(12345678); + CheckOutputSimple<BigInteger>(123456789); + CheckOutputSimple<BigInteger>(1234567890); + CheckOutputSimple<BigInteger>(12345678909); + CheckOutputSimple<BigInteger>(123456789098); + CheckOutputSimple<BigInteger>(1234567890987); + CheckOutputSimple<BigInteger>(12345678909876); + CheckOutputSimple<BigInteger>(123456789098765); + CheckOutputSimple<BigInteger>(1234567890987654); + CheckOutputSimple<BigInteger>(12345678909876543); + CheckOutputSimple<BigInteger>(123456789098765432); + CheckOutputSimple<BigInteger>(1234567890987654321); + CheckOutputSimple<BigInteger>(999999999999999999LL); + CheckOutputSimple<BigInteger>(999999999099999999LL); + CheckOutputSimple<BigInteger>(1000000000000000000LL); + CheckOutputSimple<BigInteger>(1000000000000000001LL); + CheckOutputSimple<BigInteger>(1000000005000000000LL); + CheckOutputSimple<BigInteger>(INT64_MAX); + + CheckOutputSimple<BigInteger>(-1); + CheckOutputSimple<BigInteger>(-9); + CheckOutputSimple<BigInteger>(-10); + CheckOutputSimple<BigInteger>(-11); + CheckOutputSimple<BigInteger>(-19); + CheckOutputSimple<BigInteger>(-123); + CheckOutputSimple<BigInteger>(-1234); + CheckOutputSimple<BigInteger>(-12345); + CheckOutputSimple<BigInteger>(-123456); + CheckOutputSimple<BigInteger>(-1234567); + CheckOutputSimple<BigInteger>(-12345678); + CheckOutputSimple<BigInteger>(-123456789); + CheckOutputSimple<BigInteger>(-1234567890); + CheckOutputSimple<BigInteger>(-12345678909); + CheckOutputSimple<BigInteger>(-123456789098); + CheckOutputSimple<BigInteger>(-1234567890987); + CheckOutputSimple<BigInteger>(-12345678909876); + CheckOutputSimple<BigInteger>(-123456789098765); + CheckOutputSimple<BigInteger>(-1234567890987654); + CheckOutputSimple<BigInteger>(-12345678909876543); + CheckOutputSimple<BigInteger>(-123456789098765432); + CheckOutputSimple<BigInteger>(-1234567890987654321); + CheckOutputSimple<BigInteger>(-999999999999999999LL); + CheckOutputSimple<BigInteger>(-999999999999999999LL); + CheckOutputSimple<BigInteger>(-1000000000000000000LL); + CheckOutputSimple<BigInteger>(-1000000000000000001LL); + CheckOutputSimple<BigInteger>(-1000000000000000000LL); + CheckOutputSimple<BigInteger>(INT64_MIN); +} + +BOOST_AUTO_TEST_CASE(TestOutputSimpleDecimal) +{ + CheckOutputSimple<Decimal>(0); + + CheckOutputSimple<Decimal>(1); + CheckOutputSimple<Decimal>(9); + CheckOutputSimple<Decimal>(10); + CheckOutputSimple<Decimal>(11); + CheckOutputSimple<Decimal>(19); + CheckOutputSimple<Decimal>(123); + CheckOutputSimple<Decimal>(1234); + CheckOutputSimple<Decimal>(12345); + CheckOutputSimple<Decimal>(123456); + CheckOutputSimple<Decimal>(1234567); + CheckOutputSimple<Decimal>(12345678); + CheckOutputSimple<Decimal>(123456789); + CheckOutputSimple<Decimal>(1234567890); + CheckOutputSimple<Decimal>(12345678909); + CheckOutputSimple<Decimal>(123456789098); + CheckOutputSimple<Decimal>(1234567890987); + CheckOutputSimple<Decimal>(12345678909876); + CheckOutputSimple<Decimal>(123456789098765); + CheckOutputSimple<Decimal>(1234567890987654); + CheckOutputSimple<Decimal>(12345678909876543); + CheckOutputSimple<Decimal>(123456789098765432); + CheckOutputSimple<Decimal>(1234567890987654321); + CheckOutputSimple<Decimal>(999999999999999999LL); + CheckOutputSimple<Decimal>(999999999099999999LL); + CheckOutputSimple<Decimal>(1000000000000000000LL); + CheckOutputSimple<Decimal>(1000000000000000001LL); + CheckOutputSimple<Decimal>(1000000005000000000LL); + CheckOutputSimple<Decimal>(INT64_MAX); + + CheckOutputSimple<Decimal>(-1); + CheckOutputSimple<Decimal>(-9); + CheckOutputSimple<Decimal>(-10); + CheckOutputSimple<Decimal>(-11); + CheckOutputSimple<Decimal>(-19); + CheckOutputSimple<Decimal>(-123); + CheckOutputSimple<Decimal>(-1234); + CheckOutputSimple<Decimal>(-12345); + CheckOutputSimple<Decimal>(-123456); + CheckOutputSimple<Decimal>(-1234567); + CheckOutputSimple<Decimal>(-12345678); + CheckOutputSimple<Decimal>(-123456789); + CheckOutputSimple<Decimal>(-1234567890); + CheckOutputSimple<Decimal>(-12345678909); + CheckOutputSimple<Decimal>(-123456789098); + CheckOutputSimple<Decimal>(-1234567890987); + CheckOutputSimple<Decimal>(-12345678909876); + CheckOutputSimple<Decimal>(-123456789098765); + CheckOutputSimple<Decimal>(-1234567890987654); + CheckOutputSimple<Decimal>(-12345678909876543); + CheckOutputSimple<Decimal>(-123456789098765432); + CheckOutputSimple<Decimal>(-1234567890987654321); + CheckOutputSimple<Decimal>(-999999999999999999LL); + CheckOutputSimple<Decimal>(-999999999099999999LL); + CheckOutputSimple<Decimal>(-1000000000000000000LL); + CheckOutputSimple<Decimal>(-1000000000000000001LL); + CheckOutputSimple<Decimal>(-1000000005000000000LL); + CheckOutputSimple<Decimal>(INT64_MIN); +} +BOOST_AUTO_TEST_CASE(TestInputOutputSimpleBigInteger) +{ + CheckInputOutput<BigInteger>("0"); + CheckInputOutput<BigInteger>("1"); + CheckInputOutput<BigInteger>("2"); + CheckInputOutput<BigInteger>("9"); + CheckInputOutput<BigInteger>("10"); + CheckInputOutput<BigInteger>("1123"); + CheckInputOutput<BigInteger>("64539472569345602304"); + CheckInputOutput<BigInteger>("2376926357280573482539570263854"); + CheckInputOutput<BigInteger>("407846050973948576230645736487560936425876349857823587643258934569364587268645394725693456023046037490024067294087609279"); + + CheckInputOutput<BigInteger>("1000000000000"); + CheckInputOutput<BigInteger>("1000000000000000000000000000"); + CheckInputOutput<BigInteger>("100000000000000000000000000000000000000000000000000000000000"); + + CheckInputOutput<BigInteger>("99999999999999"); + CheckInputOutput<BigInteger>("99999999999999999999999999999999"); + CheckInputOutput<BigInteger>("9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"); + + CheckInputOutput<BigInteger>("-1"); + CheckInputOutput<BigInteger>("-2"); + CheckInputOutput<BigInteger>("-9"); + CheckInputOutput<BigInteger>("-10"); + CheckInputOutput<BigInteger>("-1123"); + CheckInputOutput<BigInteger>("-64539472569345602304"); + CheckInputOutput<BigInteger>("-2376926357280573482539570263854"); + CheckInputOutput<BigInteger>("-407846050973948576230645736487560936425876349857823587643258934569364587268645394725693456023046037490024067294087609279"); + + CheckInputOutput<BigInteger>("-1000000000000"); + CheckInputOutput<BigInteger>("-1000000000000000000000000000"); + CheckInputOutput<BigInteger>("-100000000000000000000000000000000000000000000000000000000000"); + + CheckInputOutput<BigInteger>("-99999999999999"); + CheckInputOutput<BigInteger>("-99999999999999999999999999999999"); + CheckInputOutput<BigInteger>("-9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"); +} + +BOOST_AUTO_TEST_CASE(TestInputOutputSimpleDecimal) +{ + CheckInputOutput<Decimal>("0"); + CheckInputOutput<Decimal>("1"); + CheckInputOutput<Decimal>("2"); + CheckInputOutput<Decimal>("9"); + CheckInputOutput<Decimal>("10"); + CheckInputOutput<Decimal>("1123"); + CheckInputOutput<Decimal>("64539472569345602304"); + CheckInputOutput<Decimal>("2376926357280573482539570263854"); + CheckInputOutput<Decimal>("407846050973948576230645736487560936425876349857823587643258934569364587268645394725693456023046037490024067294087609279"); + + CheckInputOutput<Decimal>("1000000000000"); + CheckInputOutput<Decimal>("1000000000000000000000000000"); + CheckInputOutput<Decimal>("100000000000000000000000000000000000000000000000000000000000"); + + CheckInputOutput<Decimal>("99999999999999"); + CheckInputOutput<Decimal>("99999999999999999999999999999999"); + CheckInputOutput<Decimal>("9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"); + + CheckInputOutput<Decimal>("-1"); + CheckInputOutput<Decimal>("-2"); + CheckInputOutput<Decimal>("-9"); + CheckInputOutput<Decimal>("-10"); + CheckInputOutput<Decimal>("-1123"); + CheckInputOutput<Decimal>("-64539472569345602304"); + CheckInputOutput<Decimal>("-2376926357280573482539570263854"); + CheckInputOutput<Decimal>("-407846050973948576230645736487560936425876349857823587643258934569364587268645394725693456023046037490024067294087609279"); + + CheckInputOutput<Decimal>("-1000000000000"); + CheckInputOutput<Decimal>("-1000000000000000000000000000"); + CheckInputOutput<Decimal>("-100000000000000000000000000000000000000000000000000000000000"); + + CheckInputOutput<Decimal>("-99999999999999"); + CheckInputOutput<Decimal>("-99999999999999999999999999999999"); + CheckInputOutput<Decimal>("-9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"); + + CheckInputOutput<Decimal>("0.1"); + CheckInputOutput<Decimal>("0.2"); + CheckInputOutput<Decimal>("0.3"); + CheckInputOutput<Decimal>("0.4"); + CheckInputOutput<Decimal>("0.5"); + CheckInputOutput<Decimal>("0.6"); + CheckInputOutput<Decimal>("0.7"); + CheckInputOutput<Decimal>("0.8"); + CheckInputOutput<Decimal>("0.9"); + CheckInputOutput<Decimal>("0.01"); + CheckInputOutput<Decimal>("0.001"); + CheckInputOutput<Decimal>("0.0001"); + CheckInputOutput<Decimal>("0.00001"); + CheckInputOutput<Decimal>("0.000001"); + CheckInputOutput<Decimal>("0.0000001"); + + CheckInputOutput<Decimal>("0.00000000000000000000000000000000001"); + CheckInputOutput<Decimal>("0.10000000000000000000000000000000001"); + CheckInputOutput<Decimal>("0.10101010101010101010101010101010101"); + CheckInputOutput<Decimal>("0.99999999999999999999999999999999999"); + CheckInputOutput<Decimal>("0.79287502687354897253590684568634528762"); + + CheckInputOutput<Decimal>("0.00000000000000000000000000000000000000000000000000000001"); + CheckInputOutput<Decimal>("0.10000000000000000000000000000000000000000000000000000001"); + CheckInputOutput<Decimal>("0.1111111111111111111111111111111111111111111111111111111111"); + CheckInputOutput<Decimal>("0.9999999999999999999999999999999999999999999999999999999999999999999"); + CheckInputOutput<Decimal>("0.436589746389567836745873648576289634589763845768268457683762864587684635892768346589629"); + + CheckInputOutput<Decimal>("0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"); + CheckInputOutput<Decimal>("0.10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"); + CheckInputOutput<Decimal>("0.111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"); + CheckInputOutput<Decimal>("0.999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"); + CheckInputOutput<Decimal>("0.436589746389567836745873648576289634589763845768268457683762864587684635892768346549385700256032605603246580726384075680247634627357023645889629"); + + CheckInputOutput<Decimal>("-0.1"); + CheckInputOutput<Decimal>("-0.2"); + CheckInputOutput<Decimal>("-0.3"); + CheckInputOutput<Decimal>("-0.4"); + CheckInputOutput<Decimal>("-0.5"); + CheckInputOutput<Decimal>("-0.6"); + CheckInputOutput<Decimal>("-0.7"); + CheckInputOutput<Decimal>("-0.8"); + CheckInputOutput<Decimal>("-0.9"); + CheckInputOutput<Decimal>("-0.01"); + CheckInputOutput<Decimal>("-0.001"); + CheckInputOutput<Decimal>("-0.0001"); + CheckInputOutput<Decimal>("-0.00001"); + CheckInputOutput<Decimal>("-0.000001"); + CheckInputOutput<Decimal>("-0.0000001"); + + CheckInputOutput<Decimal>("-0.00000000000000000000000000000000001"); + CheckInputOutput<Decimal>("-0.10000000000000000000000000000000001"); + CheckInputOutput<Decimal>("-0.10101010101010101010101010101010101"); + CheckInputOutput<Decimal>("-0.99999999999999999999999999999999999"); + CheckInputOutput<Decimal>("-0.79287502687354897253590684568634528762"); + + CheckInputOutput<Decimal>("-0.00000000000000000000000000000000000000000000000000000001"); + CheckInputOutput<Decimal>("-0.10000000000000000000000000000000000000000000000000000001"); + CheckInputOutput<Decimal>("-0.1111111111111111111111111111111111111111111111111111111111"); + CheckInputOutput<Decimal>("-0.9999999999999999999999999999999999999999999999999999999999999999999"); + CheckInputOutput<Decimal>("-0.436589746389567836745873648576289634589763845768268457683762864587684635892768346589629"); + + CheckInputOutput<Decimal>("-0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"); + CheckInputOutput<Decimal>("-0.10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"); + CheckInputOutput<Decimal>("-0.111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"); + CheckInputOutput<Decimal>("-0.999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"); + CheckInputOutput<Decimal>("-0.436589746389567836745873648576289634589763845768268457683762864587684635892768346549385700256032605603246580726384075680247634627357023645889629"); + + CheckInputOutput<Decimal>("1.1"); + CheckInputOutput<Decimal>("12.21"); + CheckInputOutput<Decimal>("123.321"); + CheckInputOutput<Decimal>("1234.4321"); + CheckInputOutput<Decimal>("12345.54321"); + CheckInputOutput<Decimal>("123456.654321"); + CheckInputOutput<Decimal>("1234567.7654321"); + CheckInputOutput<Decimal>("12345678.87654321"); + CheckInputOutput<Decimal>("123456789.987654321"); + CheckInputOutput<Decimal>("1234567890.0987654321"); + CheckInputOutput<Decimal>("12345678909.90987654321"); + CheckInputOutput<Decimal>("123456789098.890987654321"); + CheckInputOutput<Decimal>("1234567890987.7890987654321"); + CheckInputOutput<Decimal>("12345678909876.67890987654321"); + CheckInputOutput<Decimal>("123456789098765.567890987654321"); + CheckInputOutput<Decimal>("1234567890987654.4567890987654321"); + CheckInputOutput<Decimal>("12345678909876543.34567890987654321"); + CheckInputOutput<Decimal>("123456789098765432.234567890987654321"); + CheckInputOutput<Decimal>("1234567890987654321.1234567890987654321"); + CheckInputOutput<Decimal>("12345678909876543210.01234567890987654321"); + CheckInputOutput<Decimal>("10000000000000000000000000000000000000000000000000000000000000.000000000000000000000000000000000000000000000000000000000000001"); + CheckInputOutput<Decimal>("111111111111111111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111111111"); + CheckInputOutput<Decimal>("99999999999999999999999999999999999999999999999999999999999999999999.99999999999999999999999999999999999999999999999999999999999999999999"); + CheckInputOutput<Decimal>("458796987658934265896483756892638456782376482605002747502306790283640563.12017054126750641065780784583204650763485718064875683468568360506340563042567"); + + CheckInputOutput<Decimal>("-1.1"); + CheckInputOutput<Decimal>("-12.21"); + CheckInputOutput<Decimal>("-123.321"); + CheckInputOutput<Decimal>("-1234.4321"); + CheckInputOutput<Decimal>("-12345.54321"); + CheckInputOutput<Decimal>("-123456.654321"); + CheckInputOutput<Decimal>("-1234567.7654321"); + CheckInputOutput<Decimal>("-12345678.87654321"); + CheckInputOutput<Decimal>("-123456789.987654321"); + CheckInputOutput<Decimal>("-1234567890.0987654321"); + CheckInputOutput<Decimal>("-12345678909.90987654321"); + CheckInputOutput<Decimal>("-123456789098.890987654321"); + CheckInputOutput<Decimal>("-1234567890987.7890987654321"); + CheckInputOutput<Decimal>("-12345678909876.67890987654321"); + CheckInputOutput<Decimal>("-123456789098765.567890987654321"); + CheckInputOutput<Decimal>("-1234567890987654.4567890987654321"); + CheckInputOutput<Decimal>("-12345678909876543.34567890987654321"); + CheckInputOutput<Decimal>("-123456789098765432.234567890987654321"); + CheckInputOutput<Decimal>("-1234567890987654321.1234567890987654321"); + CheckInputOutput<Decimal>("-12345678909876543210.01234567890987654321"); + CheckInputOutput<Decimal>("-10000000000000000000000000000000000000000000000000000000000000.000000000000000000000000000000000000000000000000000000000000001"); + CheckInputOutput<Decimal>("-111111111111111111111111111111111111111111111111111111111111111111111.11111111111111111111111111111111111111111111111111111111111111"); + CheckInputOutput<Decimal>("-99999999999999999999999999999999999999999999999999999999999999999999.99999999999999999999999999999999999999999999999999999999999999999999"); + CheckInputOutput<Decimal>("-458796987658934265896483756892638456782376482605002747502306790283640563.12017054126750641065780784583204650763485718064875683468568360506340563042567"); +} + +BOOST_AUTO_TEST_CASE(TestInputSimpleDecimal) +{ + CheckOutputInput(Decimal(0)); + + CheckOutputInput(Decimal(1)); + CheckOutputInput(Decimal(9)); + CheckOutputInput(Decimal(10)); + CheckOutputInput(Decimal(11)); + CheckOutputInput(Decimal(19)); + CheckOutputInput(Decimal(123)); + CheckOutputInput(Decimal(1234)); + CheckOutputInput(Decimal(12345)); + CheckOutputInput(Decimal(123456)); + CheckOutputInput(Decimal(1234567)); + CheckOutputInput(Decimal(12345678)); + CheckOutputInput(Decimal(123456789)); + CheckOutputInput(Decimal(1234567890)); + CheckOutputInput(Decimal(12345678909)); + CheckOutputInput(Decimal(123456789098)); + CheckOutputInput(Decimal(1234567890987)); + CheckOutputInput(Decimal(12345678909876)); + CheckOutputInput(Decimal(123456789098765)); + CheckOutputInput(Decimal(1234567890987654)); + CheckOutputInput(Decimal(12345678909876543)); + CheckOutputInput(Decimal(123456789098765432)); + CheckOutputInput(Decimal(1234567890987654321)); + CheckOutputInput(Decimal(999999999999999999LL)); + CheckOutputInput(Decimal(999999999099999999LL)); + CheckOutputInput(Decimal(1000000000000000000LL)); + CheckOutputInput(Decimal(1000000000000000001LL)); + CheckOutputInput(Decimal(1000000005000000000LL)); + CheckOutputInput(Decimal(INT64_MAX)); + + CheckOutputInput(Decimal(-1)); + CheckOutputInput(Decimal(-9)); + CheckOutputInput(Decimal(-10)); + CheckOutputInput(Decimal(-11)); + CheckOutputInput(Decimal(-19)); + CheckOutputInput(Decimal(-123)); + CheckOutputInput(Decimal(-1234)); + CheckOutputInput(Decimal(-12345)); + CheckOutputInput(Decimal(-123456)); + CheckOutputInput(Decimal(-1234567)); + CheckOutputInput(Decimal(-12345678)); + CheckOutputInput(Decimal(-123456789)); + CheckOutputInput(Decimal(-1234567890)); + CheckOutputInput(Decimal(-12345678909)); + CheckOutputInput(Decimal(-123456789098)); + CheckOutputInput(Decimal(-1234567890987)); + CheckOutputInput(Decimal(-12345678909876)); + CheckOutputInput(Decimal(-123456789098765)); + CheckOutputInput(Decimal(-1234567890987654)); + CheckOutputInput(Decimal(-12345678909876543)); + CheckOutputInput(Decimal(-123456789098765432)); + CheckOutputInput(Decimal(-1234567890987654321)); + CheckOutputInput(Decimal(-999999999999999999LL)); + CheckOutputInput(Decimal(-999999999099999999LL)); + CheckOutputInput(Decimal(-1000000000000000000LL)); + CheckOutputInput(Decimal(-1000000000000000001LL)); + CheckOutputInput(Decimal(-1000000005000000000LL)); + CheckOutputInput(Decimal(INT64_MIN)); +} + +BOOST_AUTO_TEST_CASE(TestScalingSmall) +{ + Decimal decimal(12345, 2); + BOOST_CHECK_EQUAL(decimal.GetPrecision(), 5); + + decimal.SetScale(0, decimal); + + BOOST_CHECK_EQUAL(decimal.GetPrecision(), 3); + + BOOST_CHECK_EQUAL(decimal.ToInt64(), 123); +} + +BOOST_AUTO_TEST_CASE(TestScalingBig) +{ + BigInteger bigInt(69213205262741); + + Decimal decimal; + BOOST_CHECK_EQUAL(decimal.GetPrecision(), 1); + + // 4790467782742318458842833081 + bigInt.Multiply(bigInt, bigInt); + + decimal = Decimal(bigInt, 0); + BOOST_CHECK_EQUAL(decimal.GetPrecision(), 28); + + // 22948581577492104846692006446607391554788985798427952561 + bigInt.Multiply(bigInt, bigInt); + + decimal = Decimal(bigInt, 0); + BOOST_CHECK_EQUAL(decimal.GetPrecision(), 56); + + // 22948581577492104846692006446607391554.788985798427952561 + decimal = Decimal(bigInt, 18); + + // 22948581577492104846692006446607391554 + decimal.SetScale(0, decimal); + + BOOST_CHECK_EQUAL(decimal.GetPrecision(), 38); + + // 22948581.577492104846692006446607391554788985798427952561 + decimal = Decimal(bigInt, 48); + + // 22948581 + decimal.SetScale(0, decimal); + + BOOST_CHECK_EQUAL(decimal.GetPrecision(), 8); + BOOST_CHECK_EQUAL(decimal.ToInt64(), 22948581); + + // 636471904553811060306806140254026286906087997856914463925431295610150712 + // 436301540552945788827650832722026963914694916372255230793492080431332686 + // 268324254350022490844698008329270553114204362445999680199136593689695140 + // 0874934591063287320666899465891248127072522251998904759858801 + bigInt.Pow(5); + + // 63647190455381106.030680614025402628690608799785691446392543129561015071 + // 243630154055294578882765083272202696391469491637225523079349208043133268 + // 626832425435002249084469800832927055311420436244599968019913659368969514 + // 00874934591063287320666899465891248127072522251998904759858801 + decimal = Decimal(bigInt, 260); + BOOST_CHECK_EQUAL(decimal.GetPrecision(), 277); + + // 63647190455381106 + decimal.SetScale(0, decimal); + + BOOST_CHECK_EQUAL(decimal.GetPrecision(), 17); + BOOST_CHECK_EQUAL(decimal.ToInt64(), 63647190455381106LL); +} + +BOOST_AUTO_TEST_CASE(TestPrecisionSimple) +{ + Decimal test(1); + + BOOST_CHECK_EQUAL(Decimal(-9).GetPrecision(), 1); + BOOST_CHECK_EQUAL(Decimal(-8).GetPrecision(), 1); + BOOST_CHECK_EQUAL(Decimal(-7).GetPrecision(), 1); + BOOST_CHECK_EQUAL(Decimal(-6).GetPrecision(), 1); + BOOST_CHECK_EQUAL(Decimal(-5).GetPrecision(), 1); + BOOST_CHECK_EQUAL(Decimal(-4).GetPrecision(), 1); + BOOST_CHECK_EQUAL(Decimal(-3).GetPrecision(), 1); + BOOST_CHECK_EQUAL(Decimal(-2).GetPrecision(), 1); + BOOST_CHECK_EQUAL(Decimal(-1).GetPrecision(), 1); + BOOST_CHECK_EQUAL(Decimal(0).GetPrecision(), 1); + BOOST_CHECK_EQUAL(Decimal(1).GetPrecision(), 1); + BOOST_CHECK_EQUAL(Decimal(2).GetPrecision(), 1); + BOOST_CHECK_EQUAL(Decimal(3).GetPrecision(), 1); + BOOST_CHECK_EQUAL(Decimal(4).GetPrecision(), 1); + BOOST_CHECK_EQUAL(Decimal(5).GetPrecision(), 1); + BOOST_CHECK_EQUAL(Decimal(6).GetPrecision(), 1); + BOOST_CHECK_EQUAL(Decimal(7).GetPrecision(), 1); + BOOST_CHECK_EQUAL(Decimal(8).GetPrecision(), 1); + BOOST_CHECK_EQUAL(Decimal(9).GetPrecision(), 1); + + BOOST_CHECK_EQUAL(Decimal(2147483648LL).GetPrecision(), 10); // 2^31: 10 digits + BOOST_CHECK_EQUAL(Decimal(-2147483648LL).GetPrecision(), 10); // -2^31: 10 digits + BOOST_CHECK_EQUAL(Decimal(98893745455LL).GetPrecision(), 11); // random: 11 digits + BOOST_CHECK_EQUAL(Decimal(3455436789887LL).GetPrecision(), 13); // random: 13 digits + BOOST_CHECK_EQUAL(Decimal(140737488355328LL).GetPrecision(), 15); // 2^47: 15 digits + BOOST_CHECK_EQUAL(Decimal(-140737488355328LL).GetPrecision(), 15); // -2^47: 15 digits + BOOST_CHECK_EQUAL(Decimal(7564232235739573LL).GetPrecision(), 16); // random: 16 digits + BOOST_CHECK_EQUAL(Decimal(25335434990002322LL).GetPrecision(), 17); // random: 17 digits + BOOST_CHECK_EQUAL(Decimal(9223372036854775807LL).GetPrecision(), 19); // 2^63 - 1: 19 digits + BOOST_CHECK_EQUAL(Decimal(-9223372036854775807LL).GetPrecision(), 19); // -2^63 + 1: 19 digits +} + +BOOST_AUTO_TEST_CASE(TestPrecisionChange) +{ + BigInteger bigInt(32421); + + //75946938183 + bigInt.Multiply(BigInteger(2342523), bigInt); + + //4244836901495581620 + bigInt.Multiply(BigInteger(55892140), bigInt); + + //1361610054778960404282184020 + bigInt.Multiply(BigInteger(320768521), bigInt); + + //1454144449122723409814375680476734820 + bigInt.Multiply(BigInteger(1067959541), bigInt); + + //117386322514277938455905731466723946155156640 + bigInt.Multiply(BigInteger(80725352), bigInt); + + //1173863225142779384559.05731466723946155156640 + Decimal decimal(bigInt, 23); + + BOOST_CHECK_EQUAL(decimal.GetPrecision(), 45); + BOOST_CHECK_EQUAL(decimal.GetScale(), 23); + + for (int32_t i = 0; i < decimal.GetScale(); ++i) + { + decimal.SetScale(i, decimal); + + BOOST_CHECK_EQUAL(decimal.GetPrecision(), decimal.GetPrecision() - decimal.GetScale() + i); + } +} + +BOOST_AUTO_TEST_CASE(TestDoubleCast) +{ + CheckDoubleCast(100000000000000.0); + CheckDoubleCast(10000000000000.0); + CheckDoubleCast(1000000000000.0); + CheckDoubleCast(100000000000.0); + CheckDoubleCast(10000000000.0); + CheckDoubleCast(1000000000.0); + CheckDoubleCast(100000000.0); + CheckDoubleCast(10000000.0); + CheckDoubleCast(1000000.0); + CheckDoubleCast(100000.0); + CheckDoubleCast(10000.0); + CheckDoubleCast(1000.0); + CheckDoubleCast(100.0); + CheckDoubleCast(10.0); + CheckDoubleCast(1.0); + CheckDoubleCast(0.1); + CheckDoubleCast(0.01); + CheckDoubleCast(0.001); + CheckDoubleCast(0.0001); + CheckDoubleCast(0.00001); + CheckDoubleCast(0.000001); + CheckDoubleCast(0.0000001); + CheckDoubleCast(0.00000001); + CheckDoubleCast(0.000000001); + CheckDoubleCast(0.0000000001); + CheckDoubleCast(0.00000000001); + CheckDoubleCast(0.000000000001); + CheckDoubleCast(0.00000000000001); + CheckDoubleCast(0.000000000000001); + + CheckDoubleCast(2379506093465806.); + CheckDoubleCast(172650963870256.3); + CheckDoubleCast(63506206502638.57); + CheckDoubleCast(8946589364589.763); + CheckDoubleCast(896258976348.9568); + CheckDoubleCast(28967349256.39428); + CheckDoubleCast(2806348972.689369); + CheckDoubleCast(975962354.2835845); + CheckDoubleCast(96342568.93542342); + CheckDoubleCast(6875825.934892387); + CheckDoubleCast(314969.6543969458); + CheckDoubleCast(32906.02476506344); + CheckDoubleCast(9869.643965396453); + CheckDoubleCast(779.6932689452953); + CheckDoubleCast(75.93592963492326); + CheckDoubleCast(8.719654293587452); + CheckDoubleCast(.90001236587463439); + + CheckDoubleCast(-235235E-100); + CheckDoubleCast(-235235E-90); + CheckDoubleCast(-235235E-80); + CheckDoubleCast(-235235E-70); + CheckDoubleCast(-235235E-60); + CheckDoubleCast(-235235E-50); + CheckDoubleCast(-235235E-40); + CheckDoubleCast(-235235E-30); + CheckDoubleCast(-235235E-25); + CheckDoubleCast(-235235E-20); + CheckDoubleCast(-235235E-15); + CheckDoubleCast(-235235E-10); + CheckDoubleCast(-235235E-9); + CheckDoubleCast(-235235E-8); + CheckDoubleCast(-235235E-7); + CheckDoubleCast(-235235E-6); + CheckDoubleCast(-235235E-5); + CheckDoubleCast(-235235E-4); + CheckDoubleCast(-235235E-2); + CheckDoubleCast(-235235E-1); + CheckDoubleCast(-235235); + CheckDoubleCast(-235235E+1); + CheckDoubleCast(-235235E+2); + CheckDoubleCast(-235235E+3); + CheckDoubleCast(-235235E+4); + CheckDoubleCast(-235235E+5); + CheckDoubleCast(-235235E+6); + CheckDoubleCast(-235235E+7); + CheckDoubleCast(-235235E+8); + CheckDoubleCast(-235235E+9); + CheckDoubleCast(-235235E+10); + CheckDoubleCast(-235235E+15); + CheckDoubleCast(-235235E+20); + CheckDoubleCast(-235235E+25); + CheckDoubleCast(-235235E+30); + CheckDoubleCast(-235235E+40); + CheckDoubleCast(-235235E+50); + CheckDoubleCast(-235235E+60); + CheckDoubleCast(-235235E+70); + CheckDoubleCast(-235235E+80); + CheckDoubleCast(-235235E+90); + CheckDoubleCast(-235235E+100); + + CheckDoubleCast(-2379506093465806.); + CheckDoubleCast(-172650963870256.3); + CheckDoubleCast(-63506206502638.57); + CheckDoubleCast(-8946589364589.763); + CheckDoubleCast(-896258976348.9568); + CheckDoubleCast(-28967349256.39428); + CheckDoubleCast(-2806348972.689369); + CheckDoubleCast(-975962354.2835845); + CheckDoubleCast(-96342568.93542342); + CheckDoubleCast(-6875825.934892387); + CheckDoubleCast(-314969.6543969458); + CheckDoubleCast(-32906.02476506344); + CheckDoubleCast(-9869.643965396453); + CheckDoubleCast(-779.6932689452953); + CheckDoubleCast(-75.93592963492326); + CheckDoubleCast(-8.719654293587452); + CheckDoubleCast(-.90001236587463439); + + CheckDoubleCast(-100000000000000.0); + CheckDoubleCast(-10000000000000.0); + CheckDoubleCast(-1000000000000.0); + CheckDoubleCast(-100000000000.0); + CheckDoubleCast(-10000000000.0); + CheckDoubleCast(-1000000000.0); + CheckDoubleCast(-100000000.0); + CheckDoubleCast(-10000000.0); + CheckDoubleCast(-1000000.0); + CheckDoubleCast(-100000.0); + CheckDoubleCast(-10000.0); + CheckDoubleCast(-1000.0); + CheckDoubleCast(-100.0); + CheckDoubleCast(-10.0); + CheckDoubleCast(-1.0); + CheckDoubleCast(-0.1); + CheckDoubleCast(-0.01); + CheckDoubleCast(-0.001); + CheckDoubleCast(-0.0001); + CheckDoubleCast(-0.00001); + CheckDoubleCast(-0.000001); + CheckDoubleCast(-0.0000001); + CheckDoubleCast(-0.00000001); + CheckDoubleCast(-0.000000001); + CheckDoubleCast(-0.0000000001); + CheckDoubleCast(-0.00000000001); + CheckDoubleCast(-0.000000000001); + CheckDoubleCast(-0.00000000000001); + CheckDoubleCast(-0.000000000000001); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file
