From 64f903f21deb2ee6cc20eea84b574e920a24c60e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 27 May 2012 16:40:25 -0700 Subject: [PATCH] Finish the rewrite. --- src/Amount.cpp | 129 +++++++++++++++++++++++++++++++----------- src/SerializedTypes.h | 18 +++--- 2 files changed, 103 insertions(+), 44 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 9e869e163b..e2c6ff7cac 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -420,19 +420,37 @@ STAmount& STAmount::operator=(uint64 v) } STAmount& STAmount::operator+=(uint64 v) -{ // FIXME - if (mIsNative) mValue += v; +{ + if (mIsNative) + { + if (mIsNegative) + *this += STAmount(v); + else mValue += v; + } else *this += STAmount(mCurrency, v); return *this; } STAmount& STAmount::operator-=(uint64 v) -{ // FIXME +{ if (mIsNative) { - if (v > mValue) - throw std::runtime_error("amount underflow"); - mValue -= v; + if (mIsNegative) + { + if (v >= mValue) + { + mIsNegative = false; + mValue = v - mValue; + } + else + mValue += v; + } + else if (v > mValue) + { + mIsNegative = true; + mValue = v - mValue; + } + else mValue -= v; } else *this -= STAmount(mCurrency, v); return *this; @@ -470,19 +488,28 @@ bool STAmount::operator>=(uint64 v) const } STAmount STAmount::operator+(uint64 v) const -{ // FIXME +{ if (!mIsNative) throw std::runtime_error("operation not legal no non-native currency"); - return STAmount(true, mValue + v); + if (mIsNegative) + { + if (v >= mValue) + return STAmount(false, v - mValue); // >=0 result + else return STAmount(true, mValue - v); // <0 result + } + return STAmount(false, mValue + v); } STAmount STAmount::operator-(uint64 v) const -{ // FIXME +{ if (!mIsNative) throw std::runtime_error("operation not legal no non-native currency"); if (mValue < v) throw std::runtime_error("native currency underflow"); - return STAmount(true, mValue - v); + if (mIsNegative) + return STAmount(true, mValue + v); + else if (v > mValue) return STAmount(true, v - mValue); + return STAmount(false, mValue - v); } STAmount::operator double() const @@ -493,53 +520,89 @@ STAmount::operator double() const return static_cast(mValue) * pow(10.0, mOffset); } -STAmount operator+(STAmount v1, STAmount v2) +STAmount operator+(const STAmount& v1, const STAmount& v2) { // We can check for precision loss here (value%10)!=0 // FIXME v1.throwComparable(v2); if (v1.mIsNative) - return STAmount(v1.mValue + v2.mValue); + { + int64 iv1, iv2, s; + if (v1.mIsNegative) iv1 = -v1.mValue; + else iv1 = v1.mValue; + if (v2.mIsNegative) iv2 = -v2.mValue; + else iv2 = v2.mValue; + s = iv1 + iv2; + if (s >= 0) return STAmount(s, false); + else return STAmount(-s, true); + } if (v1.isZero()) return v2; if (v2.isZero()) return v1; - while (v1.mOffset < v2.mOffset) + int ov1 = v1.mOffset, ov2 = v2.mOffset; + int64 vv1 = v1.mValue, vv2 = v2.mValue; + if (v1.mIsNegative) vv1 = -vv1; + if (v2.mIsNegative) vv2 = -vv2; + + while (ov1 < ov2) { - v1.mValue /= 10; - ++v1.mOffset; + vv1 /= 10; + ++ov1; } - while (v2.mOffset < v1.mOffset) + while (ov2 < ov1) { - v2.mValue /= 10; - ++v2.mOffset; + vv2 /= 10; + ++ov2; } - // this addition cannot overflow a uint64, it can overflow an STAmount and the constructor will throw - return STAmount(v1.name, v1.mCurrency, v1.mValue + v2.mValue, v1.mOffset); + // this addition cannot overflow an int64, it can overflow an STAmount and the constructor will throw + + int64 fv = vv1 + vv2; + if (fv >= 0) + return STAmount(v1.name, v1.mCurrency, fv, ov1, false); + else + return STAmount(v1.name, v1.mCurrency, -fv, ov1, true); } -STAmount operator-(STAmount v1, STAmount v2) +STAmount operator-(const STAmount& v1, const STAmount& v2) { -// FIXME v1.throwComparable(v2); if (v2.mIsNative) { - if (v2.mValue > v1.mValue) - throw std::runtime_error("amount underflow"); - return STAmount(v1.mValue - v2.mValue); + int64 iv1, iv2, s; + if (v1.mIsNegative) iv1 = -v1.mValue; + else iv1 = v1.mValue; + if (v2.mIsNegative) iv2 = -v2.mValue; + else iv2 = v2.mValue; + s = iv1 - iv2; + if (s >= 0) return STAmount(s, false); + else return STAmount(-s, true); } if (v2.isZero()) return v1; if (v1.isZero() || (v2.mOffset > v1.mOffset) ) throw std::runtime_error("value underflow"); - while (v1.mOffset > v2.mOffset) - { - v2.mValue /= 10; - ++v2.mOffset; - } - if (v1.mValue < v2.mValue) - throw std::runtime_error("value underflow"); + int ov1 = v1.mOffset, ov2 = v2.mOffset; + int64 vv1 = v1.mValue, vv2 = v2.mValue; + if (v1.mIsNegative) vv1 = -vv1; + if (v2.mIsNegative) vv2 = -vv2; - return STAmount(v1.name, v1.mCurrency, v1.mValue - v2.mValue, v1.mOffset); + while (ov1 < ov2) + { + vv1 /= 10; + ++ov1; + } + while (ov2 < ov1) + { + vv2 /= 10; + ++ov2; + } + // this subtraction cannot overflow an int64, it can overflow an STAmount and the constructor will throw + + int64 fv = vv1 - vv2; + if (fv >= 0) + return STAmount(v1.name, v1.mCurrency, fv, ov1, false); + else + return STAmount(v1.name, v1.mCurrency, -fv, ov1, true); } STAmount divide(const STAmount& num, const STAmount& den, const uint160& currencyOut) diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index c992b52720..59aa59ca1c 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -220,21 +220,17 @@ protected: static const uint64 cNotNative = 0x8000000000000000ull; static const uint64 cPosNative = 0x4000000000000000ull; - STAmount(bool, uint64 value) : mValue(value), mOffset(0), mIsNative(true), mIsNegative(false) { ; } + STAmount(bool isNeg, uint64 value) : mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNeg) { ; } STAmount(const char *name, uint64 value, bool isNegative) : SerializedType(name), mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNegative) { ; } - STAmount(const char *nm, const uint160& cur, uint64 v, int off, bool isNegative) - : SerializedType(nm), mCurrency(cur), mValue(v), mOffset(off), mIsNative(false), mIsNegative(isNegative) - { ; } - uint64 toUInt64() const; public: - STAmount(uint64 v = 0) : mValue(v), mOffset(0), mIsNative(true), mIsNegative(false) - { ; } + STAmount(uint64 v = 0, bool isNeg = false) : mValue(v), mOffset(0), mIsNative(true), mIsNegative(isNeg) + { if (v==0) mIsNegative = false; } STAmount(const char* n, uint64 v = 0) : SerializedType(n), mValue(v), mOffset(0), mIsNative(true), mIsNegative(false) @@ -244,8 +240,8 @@ public: : mCurrency(currency), mValue(v), mOffset(off), mIsNegative(false) { canonicalize(); } - STAmount(const char* n, const uint160& currency, uint64 v = 0, int off = 0) : SerializedType(n), - mCurrency(currency), mValue(v), mOffset(off), mIsNegative(false) + STAmount(const char* n, const uint160& currency, uint64 v = 0, int off = 0, bool isNeg = false) : + SerializedType(n), mCurrency(currency), mValue(v), mOffset(off), mIsNegative(isNeg) { canonicalize(); } static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) @@ -303,8 +299,8 @@ public: operator double() const; - friend STAmount operator+(STAmount v1, STAmount v2); - friend STAmount operator-(STAmount v1, STAmount v2); + friend STAmount operator+(const STAmount& v1, const STAmount& v2); + friend STAmount operator-(const STAmount& v1, const STAmount& v2); friend STAmount divide(const STAmount& v1, const STAmount& v2, const uint160& currencyOut); friend STAmount multiply(const STAmount& v1, const STAmount& v2, const uint160& currencyOut);