From b0931108903f81cbef1ee1b0835a7b83538344eb Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 10 Apr 2012 13:11:20 -0700 Subject: [PATCH 01/15] Fixes. --- src/Amount.cpp | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 3cc30d7e0..4d2b60c4e 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -1,5 +1,6 @@ #include +#include #include @@ -49,7 +50,9 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name) std::string STAmount::getText() const { - return boost::lexical_cast(static_cast(*this)); + std::ostringstream str; + str << std::setprecision(16) << static_cast(*this); + return str.str(); } void STAmount::add(Serializer& s) const @@ -138,6 +141,12 @@ STAmount& STAmount::operator-=(uint64 v) return *this-=STAmount(v); } +STAmount::operator double() const +{ + if(!value) return 0.0; + return (static_cast(value)) * pow(10.0, offset); +} + STAmount operator+(STAmount v1, STAmount v2) { // We can check for precision loss here (value%10)!=0 while(v1.offset < v2.offset) @@ -170,8 +179,26 @@ STAmount operator-(STAmount v1, STAmount v2) return STAmount(v1.name, v1.value - v2.value, v1.offset); } -STAmount::operator double() const +STAmount getRate(const STAmount& offerIn, const STAmount& offerOut) { - if(!value) return 0.0; - return static_cast(value) * pow(10.0, offset); + CBigNum numerator, denominator, quotient; + + if(offerOut.value==0) throw std::runtime_error("illegal offer"); + if(offerIn.value==0) return STAmount(); + + if( (BN_zero(&numerator)!=1) || (BN_zero(&denominator)!=1) || + (BN_add_word(&numerator, offerIn.value)!=1) || + (BN_add_word(&denominator, offerOut.value)!=1) || + (BN_mul_word(&numerator, 1000000000000000ull)!=1) || + (BN_div("ient, NULL, &numerator, &denominator, CAutoBN_CTX())!=1) ) + throw std::runtime_error("internal bn error"); + + int offset=offerIn.offset - offerOut.offset - 15; + + while(BN_num_bits("ient)>60) + { + offset+=3; + BN_div_word("ient, 1000); + } + return STAmount(quotient.getulong(), offset); } From ad1ae6af23c29851ef8a1ed79f5111242406b001 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 10 Apr 2012 13:22:16 -0700 Subject: [PATCH 02/15] Fix mishandling of zero values. Must add to unit test! --- src/Amount.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 4d2b60c4e..13169332d 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -33,7 +33,6 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name) { uint64 value = sit.get64(); int offset = static_cast(value>>(64-8)); - offset-=142; value&=~(255ull<<(64-8)); if(value==0) { @@ -42,6 +41,7 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name) } else { + offset-=142; if( (valuecMaxValue) || (offsetcMaxOffset) ) throw std::runtime_error("invalid currency value"); } @@ -58,7 +58,7 @@ std::string STAmount::getText() const void STAmount::add(Serializer& s) const { uint64 v=value; - v+=(static_cast(offset+142) << (64-8)); + if(v!=0) v+=(static_cast(offset+142) << (64-8)); s.add64(v); } From 7ebd7a18450e263a33ffe741842375123c63538f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 10 Apr 2012 14:36:53 -0700 Subject: [PATCH 03/15] Cleanups, add comments, some fixes. --- src/Amount.cpp | 76 +++++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 13169332d..a034c35b0 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -6,12 +6,18 @@ #include "SerializedTypes.h" +// amount = value * [10 ^ offset] +// representation range is 10^80 - 10^(-80) +// on the wire, high 8 bits are (offset+142), low 56 bits are value +// value is zero if amount is zero, otherwise value is 10^15 - (10^16 - 1) inclusive + void STAmount::canonicalize() { if(value==0) { offset=0; value=0; + return; } while(valuecMaxValue) - { // Here we can make it throw on precision loss if we wish: ((value%10)!=0) + { if(offset>=cMaxOffset) throw std::runtime_error("value underflow"); value/=10; offset+=1; @@ -32,8 +38,10 @@ void STAmount::canonicalize() STAmount* STAmount::construct(SerializerIterator& sit, const char *name) { uint64 value = sit.get64(); - int offset = static_cast(value>>(64-8)); - value&=~(255ull<<(64-8)); + + int offset = static_cast(value >> (64-8)); + value &= ~(255ull << (64-8)); + if(value==0) { if(offset!=0) @@ -41,7 +49,7 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name) } else { - offset-=142; + offset -= 142; // center the range if( (valuecMaxValue) || (offsetcMaxOffset) ) throw std::runtime_error("invalid currency value"); } @@ -49,7 +57,7 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name) } std::string STAmount::getText() const -{ +{ // This should be re-implemented to put a '.' in the string form of the integer value std::ostringstream str; str << std::setprecision(16) << static_cast(*this); return str.str(); @@ -57,44 +65,48 @@ std::string STAmount::getText() const void STAmount::add(Serializer& s) const { - uint64 v=value; - if(v!=0) v+=(static_cast(offset+142) << (64-8)); - s.add64(v); + if (value==0) + s.add64(0); + else + s.add64(value + (static_cast(offset+142) << (64-8)))); } bool STAmount::isEquivalent(const SerializedType& t) const { - const STAmount* v=dynamic_cast(&t); + const STAmount* v = dynamic_cast(&t); if(!v) return false; - return (value==v->value) && (offset==v->offset); + return (value == v->value) && (offset == v->offset); } bool STAmount::operator==(const STAmount& a) const { - return (offset==a.offset) && (value==a.value); + return (offset == a.offset) && (value == a.value); } bool STAmount::operator!=(const STAmount& a) const { - return (offset!=a.offset) || (value!=a.value); + return (offset != a.offset) || (value != a.value); } bool STAmount::operator<(const STAmount& a) const { - if(offset(const STAmount& a) const { - if(offset>a.offset) return true; - if(a.offset>offset) return false; + if(value == 0) return a.value != 0; + if(offset > a.offset) return true; + if(a.offset > offset) return false; return value > a.value; } bool STAmount::operator<=(const STAmount& a) const { + if(value == 0) return a.value== 0; if(offset=(const STAmount& a) const { + if(value == 0) return true; if(offset>a.offset) return true; if(a.offset>offset) return false; return value >= a.value; @@ -175,7 +188,7 @@ STAmount operator-(STAmount v1, STAmount v2) v2.value/=10; v2.offset+=1; } - if(v1.value < v2.value) throw std::runtime_error("value overflow"); + if(v1.value < v2.value) throw std::runtime_error("value underflow"); return STAmount(v1.name, v1.value - v2.value, v1.offset); } @@ -183,22 +196,21 @@ STAmount getRate(const STAmount& offerIn, const STAmount& offerOut) { CBigNum numerator, denominator, quotient; - if(offerOut.value==0) throw std::runtime_error("illegal offer"); - if(offerIn.value==0) return STAmount(); + if(offerOut.value == 0) throw std::runtime_error("illegal offer"); + if(offerIn.value == 0) return STAmount(); - if( (BN_zero(&numerator)!=1) || (BN_zero(&denominator)!=1) || - (BN_add_word(&numerator, offerIn.value)!=1) || - (BN_add_word(&denominator, offerOut.value)!=1) || - (BN_mul_word(&numerator, 1000000000000000ull)!=1) || - (BN_div("ient, NULL, &numerator, &denominator, CAutoBN_CTX())!=1) ) - throw std::runtime_error("internal bn error"); - - int offset=offerIn.offset - offerOut.offset - 15; - - while(BN_num_bits("ient)>60) + // Compute (numerator * 10^16) / denominator + if( (BN_zero(&numerator) != 1) || (BN_zero(&denominator) != 1) || + (BN_add_word(&numerator, offerIn.value) != 1) || + (BN_add_word(&denominator, offerOut.value) != 1) || + (BN_mul_word(&numerator, 10000000000000000ull) != 1) || + (BN_div("ient, NULL, &numerator, &denominator, CAutoBN_CTX()) != 1) ) { - offset+=3; - BN_div_word("ient, 1000); + throw std::runtime_error("internal bn error"); } - return STAmount(quotient.getulong(), offset); + + // 10^15 <= quotient <= 10^17 + assert(BN_num_bytes("ient)<=60); + + return STAmount(quotient.getulong(), offerIn.offset - offerOut.offset - 16); } From 22d3354ccc5cd83980b664d7713826597ead89a2 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 10 Apr 2012 14:37:20 -0700 Subject: [PATCH 04/15] Typo. --- src/Amount.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index a034c35b0..d514ab0eb 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -68,7 +68,7 @@ void STAmount::add(Serializer& s) const if (value==0) s.add64(0); else - s.add64(value + (static_cast(offset+142) << (64-8)))); + s.add64(value + (static_cast(offset+142) << (64-8))); } bool STAmount::isEquivalent(const SerializedType& t) const From 6bf6d86cd9b34f0a5edbdd60ffce9141b095dded Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 10 Apr 2012 15:26:44 -0700 Subject: [PATCH 05/15] Offer logic seems to be working now. --- src/Amount.cpp | 73 ++++++++++++++++++++++++++++++++++++++----- src/SerializedTypes.h | 13 +++++--- 2 files changed, 74 insertions(+), 12 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index d514ab0eb..90ec1fc73 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -59,7 +59,7 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name) std::string STAmount::getText() const { // This should be re-implemented to put a '.' in the string form of the integer value std::ostringstream str; - str << std::setprecision(16) << static_cast(*this); + str << std::setprecision(14) << static_cast(*this); return str.str(); } @@ -192,17 +192,16 @@ STAmount operator-(STAmount v1, STAmount v2) return STAmount(v1.name, v1.value - v2.value, v1.offset); } -STAmount getRate(const STAmount& offerIn, const STAmount& offerOut) +STAmount operator/(const STAmount& num, const STAmount& den) { CBigNum numerator, denominator, quotient; - if(offerOut.value == 0) throw std::runtime_error("illegal offer"); - if(offerIn.value == 0) return STAmount(); + if(den.value == 0) throw std::runtime_error("illegal offer"); + if(num.value == 0) return STAmount(); // Compute (numerator * 10^16) / denominator - if( (BN_zero(&numerator) != 1) || (BN_zero(&denominator) != 1) || - (BN_add_word(&numerator, offerIn.value) != 1) || - (BN_add_word(&denominator, offerOut.value) != 1) || + if( (BN_add_word(&numerator, num.value) != 1) || + (BN_add_word(&denominator, den.value) != 1) || (BN_mul_word(&numerator, 10000000000000000ull) != 1) || (BN_div("ient, NULL, &numerator, &denominator, CAutoBN_CTX()) != 1) ) { @@ -212,5 +211,63 @@ STAmount getRate(const STAmount& offerIn, const STAmount& offerOut) // 10^15 <= quotient <= 10^17 assert(BN_num_bytes("ient)<=60); - return STAmount(quotient.getulong(), offerIn.offset - offerOut.offset - 16); + return STAmount(quotient.getulong(), num.offset - den.offset - 16); +} + +STAmount operator*(const STAmount &v1, const STAmount &v2) +{ + if( (v1.value == 0) || (v2.value == 0) ) return STAmount(); + + // Compute (numerator * denominator) / 10^15 + CBigNum v; + if( (BN_add_word(&v, v1.value) != 1) || + (BN_mul_word(&v, v2.value) != 1) || + (BN_div_word(&v, 1000000000000000ull) == ((BN_ULONG)-1)) ) + { + throw std::runtime_error("internal bn error"); + } + + // 10^15 <= product <= 10^17 + assert(BN_num_bytes(&v)<=60); + return STAmount(v.getulong(), v1.offset + v2.offset + 15); +} + +STAmount getRate(const STAmount& offerOut, const STAmount& offerIn) +{ + return offerOut / offerIn; +} + +STAmount getClaimed(STAmount& offerOut, STAmount& offerIn, STAmount& paid) +{ // if someone is offering (offerOut) for (offerIn), and I pay (paid), how much do I get? + + // If you pay nothing, you get nothing. Offer is untouched + if (paid.value == 0) return STAmount(); + + if( (offerIn.value == 0) || (offerOut.value == 0) ) + { // If the other is invalid or empty, you pay nothing and get nothing and the offer is dead + offerIn.zero(); + offerOut.zero(); + paid.zero(); + return STAmount(); + } + + if(paid >= offerIn) + { // If you pay equal to or more than the offer amount, you get the whole offer and pay its input + STAmount ret(offerOut); + paid = offerIn; + offerOut.zero(); + offerIn.zero(); + return ret; + } + + // partial satisfaction of a normal offer + STAmount ret = (paid * offerOut ) / offerIn; + offerOut -= ret; + offerIn -= paid; + if( (offerOut.value == 0) || (offerIn.value == 0) ) + { + offerIn.zero(); + offerOut.zero(); + } + return ret; } diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index ceddccb17..9dad1cb6f 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -195,6 +195,8 @@ public: int getOffset() const { return offset; } uint64 getValue() const { return value; } + void zero() { offset=0; value=0; } + bool isZero() const { return value==0; } virtual bool isEquivalent(const SerializedType& t) const; @@ -216,15 +218,18 @@ public: 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); // Someone is offering X for Y, what is the rate? - friend STAmount getRate(const STAmount& offerIn, const STAmount& offerOut); + friend STAmount getRate(const STAmount& offerOut, const STAmount& offerIn); - // Someone is offering X for Y, I pay Z, how much do I get? - friend STAmount getClaimed(const STAmount& offerIn, const STAmount& offerOut, const STAmount& paid); + // Someone is offering X for Y, I try to pay Z, how much do I get? + // And what's left of the offer? And how much do I actually pay? + friend STAmount getClaimed(STAmount& offerOut, STAmount& offerIn, STAmount& paid); // Someone is offering X for Y, I need Z, how much do I pay - friend STAmount getNeeded(const STAmount& offerIn, const STAmount& offerOut, const STAmount& needed); + friend STAmount getNeeded(const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed); }; class STHash128 : public SerializedType From ce30701744066ef1cfc4f6787bd2e416e279cd24 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 10 Apr 2012 16:04:28 -0700 Subject: [PATCH 06/15] Code to compute how much you need to pay to get a particular output from an offer. --- src/Amount.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Amount.cpp b/src/Amount.cpp index 90ec1fc73..9902a1b9e 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -234,6 +234,8 @@ STAmount operator*(const STAmount &v1, const STAmount &v2) STAmount getRate(const STAmount& offerOut, const STAmount& offerIn) { + // offerOut = how much comes out of the offer, from the offeror to the taker + // offerIn = how much goes into the offer, from the taker to the offeror return offerOut / offerIn; } @@ -271,3 +273,11 @@ STAmount getClaimed(STAmount& offerOut, STAmount& offerIn, STAmount& paid) } return ret; } + +STAmount getNeeded(const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed) +{ // Someone wants to get (needed) out of the offer, how much should they pay in? + if(offerOut.isZero()) return STAmount(); + if(needed >= offerOut) return needed; + STAmount ret = needed * (offerIn / offerOut); + return (ret > offerIn) ? offerIn : ret; +} From c1cd6163595a63d0c4be63ceb4abf8ec5e49bf94 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 10 Apr 2012 16:46:41 -0700 Subject: [PATCH 07/15] Always display these exactly. --- src/Amount.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 9902a1b9e..74ea62eb6 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -57,10 +57,26 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name) } std::string STAmount::getText() const -{ // This should be re-implemented to put a '.' in the string form of the integer value - std::ostringstream str; - str << std::setprecision(14) << static_cast(*this); - return str.str(); +{ + if( (offset<-25) || (offset>-5) ) + return boost::lexical_cast(value) + "e" + boost::lexical_cast(offset); + + std::string val="00000000000000000"; + val+=boost::lexical_cast(value); + val+="0000000000000000"; + + std::string pre=val.substr(0, offset+33); + std::string post=val.substr(offset+33); + + size_t s_pre=pre.find_first_not_of('0'); + if(s_pre==std::string::npos) pre="0"; + else pre=pre.substr(s_pre); + + size_t s_post=post.find_last_not_of('0'); + if(s_post==std::string::npos) + return pre; + else + return pre + "." + post.substr(0, s_post); } void STAmount::add(Serializer& s) const From db2846547f927234996ce2e3fc1ec0c6d5f9bcc8 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 10 Apr 2012 16:47:17 -0700 Subject: [PATCH 08/15] Missed one special cast. --- src/Amount.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Amount.cpp b/src/Amount.cpp index 74ea62eb6..699a0a707 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -58,6 +58,7 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name) std::string STAmount::getText() const { + if(value==0) return "0"; if( (offset<-25) || (offset>-5) ) return boost::lexical_cast(value) + "e" + boost::lexical_cast(offset); From e61ddb980e12ed6ff4383a92dadd67b5d011d7a7 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 10 Apr 2012 16:51:00 -0700 Subject: [PATCH 09/15] Off by one error. --- src/Amount.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 699a0a707..82632f97b 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -62,12 +62,12 @@ std::string STAmount::getText() const if( (offset<-25) || (offset>-5) ) return boost::lexical_cast(value) + "e" + boost::lexical_cast(offset); - std::string val="00000000000000000"; + std::string val="000000000000000000000000000"; val+=boost::lexical_cast(value); - val+="0000000000000000"; + val+="00000000000000000000000"; - std::string pre=val.substr(0, offset+33); - std::string post=val.substr(offset+33); + std::string pre=val.substr(0, offset+43); + std::string post=val.substr(offset+43); size_t s_pre=pre.find_first_not_of('0'); if(s_pre==std::string::npos) pre="0"; @@ -77,7 +77,7 @@ std::string STAmount::getText() const if(s_post==std::string::npos) return pre; else - return pre + "." + post.substr(0, s_post); + return pre + "." + post.substr(0, s_post+1); } void STAmount::add(Serializer& s) const From 48fe991cdba035b4bbf62c3dc4b26f78f55bad98 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 10 Apr 2012 17:00:40 -0700 Subject: [PATCH 10/15] Rounding fix. --- src/Amount.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 82632f97b..27ad847de 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -235,18 +235,18 @@ STAmount operator*(const STAmount &v1, const STAmount &v2) { if( (v1.value == 0) || (v2.value == 0) ) return STAmount(); - // Compute (numerator * denominator) / 10^15 + // Compute (numerator * denominator) / 10^16 CBigNum v; - if( (BN_add_word(&v, v1.value) != 1) || - (BN_mul_word(&v, v2.value) != 1) || - (BN_div_word(&v, 1000000000000000ull) == ((BN_ULONG)-1)) ) + if( (BN_add_word(&v, v1.value + 1) != 1) || + (BN_mul_word(&v, v2.value + 1) != 1) || + (BN_div_word(&v, 10000000000000000ull) == ((BN_ULONG)-1)) ) { throw std::runtime_error("internal bn error"); } - // 10^15 <= product <= 10^17 + // 10^16 <= product <= 10^18 assert(BN_num_bytes(&v)<=60); - return STAmount(v.getulong(), v1.offset + v2.offset + 15); + return STAmount(v.getulong(), v1.offset + v2.offset + 16); } STAmount getRate(const STAmount& offerOut, const STAmount& offerIn) @@ -280,7 +280,7 @@ STAmount getClaimed(STAmount& offerOut, STAmount& offerIn, STAmount& paid) } // partial satisfaction of a normal offer - STAmount ret = (paid * offerOut ) / offerIn; + STAmount ret = (paid * offerOut) / offerIn; offerOut -= ret; offerIn -= paid; if( (offerOut.value == 0) || (offerIn.value == 0) ) @@ -295,6 +295,6 @@ STAmount getNeeded(const STAmount& offerOut, const STAmount& offerIn, const STAm { // Someone wants to get (needed) out of the offer, how much should they pay in? if(offerOut.isZero()) return STAmount(); if(needed >= offerOut) return needed; - STAmount ret = needed * (offerIn / offerOut); + STAmount ret = (needed * offerIn) / offerOut; return (ret > offerIn) ? offerIn : ret; } From b771a11836873f925d089047a94b385a51b422d3 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 11 Apr 2012 00:27:49 -0700 Subject: [PATCH 11/15] A 1/3 lsb offset is needed to make the multiplication round down correctly. --- src/Amount.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 27ad847de..f5ac2b125 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -23,13 +23,13 @@ void STAmount::canonicalize() { if(offset<=cMinOffset) throw std::runtime_error("value overflow"); value*=10; - offset-=1; + --offset; } while(value>cMaxValue) { if(offset>=cMaxOffset) throw std::runtime_error("value underflow"); value/=10; - offset+=1; + ++offset; } assert( (value==0) || ( (value>=cMinValue) && (value<=cMaxValue) ) ); assert( (offset>=cMinOffset) && (offset<=cMaxOffset) ); @@ -235,11 +235,11 @@ STAmount operator*(const STAmount &v1, const STAmount &v2) { if( (v1.value == 0) || (v2.value == 0) ) return STAmount(); - // Compute (numerator * denominator) / 10^16 + // Compute (numerator*10 * denominator*10) / 10^18 CBigNum v; - if( (BN_add_word(&v, v1.value + 1) != 1) || - (BN_mul_word(&v, v2.value + 1) != 1) || - (BN_div_word(&v, 10000000000000000ull) == ((BN_ULONG)-1)) ) + if( (BN_add_word(&v, (v1.value*10) + 3) != 1) || + (BN_mul_word(&v, (v2.value*10) + 3) != 1) || + (BN_div_word(&v, 1000000000000000000ull) == ((BN_ULONG)-1)) ) { throw std::runtime_error("internal bn error"); } From dc8889668a462f9f9eb6ce5dcec0435533fc0463 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 11 Apr 2012 12:25:09 -0700 Subject: [PATCH 12/15] Simplification. --- src/Amount.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index f5ac2b125..76a4303d9 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -195,15 +195,11 @@ STAmount operator+(STAmount v1, STAmount v2) STAmount operator-(STAmount v1, STAmount v2) { // We can check for precision loss here (value%10)!=0 - while(v1.offset < v2.offset) - { - v1.value/=10; - v1.offset+=1; - } - while(v2.offset < v1.offset) + if(v2.offset > v1.offset) throw std::runtime_error("value underflow"); + while(v1.offset > v2.offset) { v2.value/=10; - v2.offset+=1; + ++v2.offset; } if(v1.value < v2.value) throw std::runtime_error("value underflow"); return STAmount(v1.name, v1.value - v2.value, v1.offset); From efd363538cfc895588e6e09f4f735b6e91681342 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 11 Apr 2012 12:32:41 -0700 Subject: [PATCH 13/15] Fix some special cases. Cleanup whitespace. --- src/Amount.cpp | 150 +++++++++++++++++++++++++++---------------------- 1 file changed, 82 insertions(+), 68 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 76a4303d9..16a5463af 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -13,26 +13,28 @@ void STAmount::canonicalize() { - if(value==0) + if (value == 0) { offset=0; value=0; return; } - while(valuecMaxValue) + while(value > cMaxValue) { - if(offset>=cMaxOffset) throw std::runtime_error("value underflow"); - value/=10; + if (offset >= cMaxOffset) + throw std::runtime_error("value underflow"); + value /= 10; ++offset; } - assert( (value==0) || ( (value>=cMinValue) && (value<=cMaxValue) ) ); - assert( (offset>=cMinOffset) && (offset<=cMaxOffset) ); + assert( (value == 0) || ( (value >= cMinValue) && (value <= cMaxValue) ) ); + assert( (offset >= cMinOffset) && (offset <= cMaxOffset) ); } STAmount* STAmount::construct(SerializerIterator& sit, const char *name) @@ -42,15 +44,15 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name) int offset = static_cast(value >> (64-8)); value &= ~(255ull << (64-8)); - if(value==0) + if (value == 0) { - if(offset!=0) + if (offset != 0) throw std::runtime_error("invalid currency value"); } else { offset -= 142; // center the range - if( (valuecMaxValue) || (offsetcMaxOffset) ) + if ( (value < cMinValue) || (value > cMaxValue) || (offset < cMinOffset) || (offset > cMaxOffset) ) throw std::runtime_error("invalid currency value"); } return new STAmount(name, value, offset); @@ -58,23 +60,25 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name) std::string STAmount::getText() const { - if(value==0) return "0"; - if( (offset<-25) || (offset>-5) ) + if (value == 0) return "0"; + if ( (offset < -25) || (offset > -5) ) return boost::lexical_cast(value) + "e" + boost::lexical_cast(offset); - std::string val="000000000000000000000000000"; - val+=boost::lexical_cast(value); - val+="00000000000000000000000"; + std::string val = "000000000000000000000000000"; + val += boost::lexical_cast(value); + val += "00000000000000000000000"; - std::string pre=val.substr(0, offset+43); - std::string post=val.substr(offset+43); + std::string pre = val.substr(0, offset+43); + std::string post = val.substr(offset+43); - size_t s_pre=pre.find_first_not_of('0'); - if(s_pre==std::string::npos) pre="0"; - else pre=pre.substr(s_pre); + size_t s_pre = pre.find_first_not_of('0'); + if (s_pre == std::string::npos) + pre="0"; + else + pre = pre.substr(s_pre); - size_t s_post=post.find_last_not_of('0'); - if(s_post==std::string::npos) + size_t s_post = post.find_last_not_of('0'); + if (s_post == std::string::npos) return pre; else return pre + "." + post.substr(0, s_post+1); @@ -82,16 +86,16 @@ std::string STAmount::getText() const void STAmount::add(Serializer& s) const { - if (value==0) + if (value == 0) s.add64(0); else - s.add64(value + (static_cast(offset+142) << (64-8))); + s.add64(value + (static_cast(offset + 142) << (64 - 8))); } bool STAmount::isEquivalent(const SerializedType& t) const { const STAmount* v = dynamic_cast(&t); - if(!v) return false; + if (!v) return false; return (value == v->value) && (offset == v->offset); } @@ -107,33 +111,33 @@ bool STAmount::operator!=(const STAmount& a) const bool STAmount::operator<(const STAmount& a) const { - if(value == 0) return false; - if(offset < a.offset) return true; - if(a.offset < offset) return false; + if (value == 0) return false; + if (offset < a.offset) return true; + if (a.offset < offset) return false; return value < a.value; } bool STAmount::operator>(const STAmount& a) const { - if(value == 0) return a.value != 0; - if(offset > a.offset) return true; - if(a.offset > offset) return false; + if (value == 0) return a.value != 0; + if (offset > a.offset) return true; + if (a.offset > offset) return false; return value > a.value; } bool STAmount::operator<=(const STAmount& a) const { - if(value == 0) return a.value== 0; - if(offset=(const STAmount& a) const { - if(value == 0) return true; - if(offset>a.offset) return true; - if(a.offset>offset) return false; + if (value == 0) return true; + if (offset > a.offset) return true; + if (a.offset > offset) return false; return value >= a.value; } @@ -151,57 +155,65 @@ STAmount& STAmount::operator-=(const STAmount& a) STAmount& STAmount::operator=(const STAmount& a) { - value=a.value; - offset=a.offset; + value = a.value; + offset = a.offset; return *this; } STAmount& STAmount::operator=(uint64 v) { - return *this=STAmount(v, 0); + return *this = STAmount(v, 0); } STAmount& STAmount::operator+=(uint64 v) { - return *this+=STAmount(v); + return *this += STAmount(v); } STAmount& STAmount::operator-=(uint64 v) { - return *this-=STAmount(v); + return *this -= STAmount(v); } STAmount::operator double() const { - if(!value) return 0.0; - return (static_cast(value)) * pow(10.0, offset); + if (!value) + return 0.0; + return static_cast(value) * pow(10.0, offset); } STAmount operator+(STAmount v1, STAmount v2) { // We can check for precision loss here (value%10)!=0 + if (v1.value == 0) return v2; + if (v2.value == 0) return v1; while(v1.offset < v2.offset) { - v1.value/=10; - v1.offset+=1; + v1.value /= 10; + ++v1.offset; } while(v2.offset < v1.offset) { - v2.value/=10; - v2.offset+=1; + v2.value /= 10; + ++v2.offset; } // this addition cannot overflow return STAmount(v1.name, v1.value + v2.value, v1.offset); } STAmount operator-(STAmount v1, STAmount v2) -{ // We can check for precision loss here (value%10)!=0 - if(v2.offset > v1.offset) throw std::runtime_error("value underflow"); +{ + if (v2.value == 0) return v1; + if ( (v1.value == 0) || (v2.offset > v1.offset) ) + throw std::runtime_error("value underflow"); + while(v1.offset > v2.offset) { - v2.value/=10; + v2.value /= 10; ++v2.offset; } - if(v1.value < v2.value) throw std::runtime_error("value underflow"); + if (v1.value < v2.value) + throw std::runtime_error("value underflow"); + return STAmount(v1.name, v1.value - v2.value, v1.offset); } @@ -209,39 +221,41 @@ STAmount operator/(const STAmount& num, const STAmount& den) { CBigNum numerator, denominator, quotient; - if(den.value == 0) throw std::runtime_error("illegal offer"); - if(num.value == 0) return STAmount(); + if (den.value == 0) throw std::runtime_error("illegal offer"); + if (num.value == 0) return STAmount(); // Compute (numerator * 10^16) / denominator - if( (BN_add_word(&numerator, num.value) != 1) || + if ((BN_add_word(&numerator, num.value) != 1) || (BN_add_word(&denominator, den.value) != 1) || (BN_mul_word(&numerator, 10000000000000000ull) != 1) || - (BN_div("ient, NULL, &numerator, &denominator, CAutoBN_CTX()) != 1) ) + (BN_div("ient, NULL, &numerator, &denominator, CAutoBN_CTX()) != 1)) { throw std::runtime_error("internal bn error"); } // 10^15 <= quotient <= 10^17 - assert(BN_num_bytes("ient)<=60); + assert(BN_num_bytes("ient) <= 60); return STAmount(quotient.getulong(), num.offset - den.offset - 16); } STAmount operator*(const STAmount &v1, const STAmount &v2) { - if( (v1.value == 0) || (v2.value == 0) ) return STAmount(); + if ( (v1.value == 0) || (v2.value == 0) ) + return STAmount(); // Compute (numerator*10 * denominator*10) / 10^18 CBigNum v; - if( (BN_add_word(&v, (v1.value*10) + 3) != 1) || + if ((BN_add_word(&v, (v1.value*10) + 3) != 1) || (BN_mul_word(&v, (v2.value*10) + 3) != 1) || - (BN_div_word(&v, 1000000000000000000ull) == ((BN_ULONG)-1)) ) + (BN_div_word(&v, 1000000000000000000ull) == ((BN_ULONG)-1))) { throw std::runtime_error("internal bn error"); } // 10^16 <= product <= 10^18 - assert(BN_num_bytes(&v)<=60); + assert(BN_num_bytes(&v) <= 60); + return STAmount(v.getulong(), v1.offset + v2.offset + 16); } @@ -258,7 +272,7 @@ STAmount getClaimed(STAmount& offerOut, STAmount& offerIn, STAmount& paid) // If you pay nothing, you get nothing. Offer is untouched if (paid.value == 0) return STAmount(); - if( (offerIn.value == 0) || (offerOut.value == 0) ) + if ( (offerIn.value == 0) || (offerOut.value == 0) ) { // If the other is invalid or empty, you pay nothing and get nothing and the offer is dead offerIn.zero(); offerOut.zero(); @@ -266,7 +280,7 @@ STAmount getClaimed(STAmount& offerOut, STAmount& offerIn, STAmount& paid) return STAmount(); } - if(paid >= offerIn) + if (paid >= offerIn) { // If you pay equal to or more than the offer amount, you get the whole offer and pay its input STAmount ret(offerOut); paid = offerIn; @@ -279,7 +293,7 @@ STAmount getClaimed(STAmount& offerOut, STAmount& offerIn, STAmount& paid) STAmount ret = (paid * offerOut) / offerIn; offerOut -= ret; offerIn -= paid; - if( (offerOut.value == 0) || (offerIn.value == 0) ) + if ( (offerOut.value == 0) || (offerIn.value == 0) ) { offerIn.zero(); offerOut.zero(); @@ -289,8 +303,8 @@ STAmount getClaimed(STAmount& offerOut, STAmount& offerIn, STAmount& paid) STAmount getNeeded(const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed) { // Someone wants to get (needed) out of the offer, how much should they pay in? - if(offerOut.isZero()) return STAmount(); - if(needed >= offerOut) return needed; + if (offerOut.isZero()) return STAmount(); + if (needed >= offerOut) return needed; STAmount ret = (needed * offerIn) / offerOut; return (ret > offerIn) ? offerIn : ret; } From ded4d19a652ed5827ded50105b59dcbb1e6502fe Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 11 Apr 2012 14:24:22 -0700 Subject: [PATCH 14/15] Optimize / operation. --- src/Amount.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 16a5463af..6d881c1fd 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -19,14 +19,14 @@ void STAmount::canonicalize() value=0; return; } - while(value < cMinValue) + while (value < cMinValue) { if (offset <= cMinOffset) throw std::runtime_error("value overflow"); value *= 10; --offset; } - while(value > cMaxValue) + while (value > cMaxValue) { if (offset >= cMaxOffset) throw std::runtime_error("value underflow"); @@ -186,12 +186,12 @@ STAmount operator+(STAmount v1, STAmount v2) { // We can check for precision loss here (value%10)!=0 if (v1.value == 0) return v2; if (v2.value == 0) return v1; - while(v1.offset < v2.offset) + while (v1.offset < v2.offset) { v1.value /= 10; ++v1.offset; } - while(v2.offset < v1.offset) + while (v2.offset < v1.offset) { v2.value /= 10; ++v2.offset; @@ -206,7 +206,7 @@ STAmount operator-(STAmount v1, STAmount v2) if ( (v1.value == 0) || (v2.offset > v1.offset) ) throw std::runtime_error("value underflow"); - while(v1.offset > v2.offset) + while (v1.offset > v2.offset) { v2.value /= 10; ++v2.offset; @@ -219,24 +219,23 @@ STAmount operator-(STAmount v1, STAmount v2) STAmount operator/(const STAmount& num, const STAmount& den) { - CBigNum numerator, denominator, quotient; + CBigNum v; if (den.value == 0) throw std::runtime_error("illegal offer"); if (num.value == 0) return STAmount(); // Compute (numerator * 10^16) / denominator - if ((BN_add_word(&numerator, num.value) != 1) || - (BN_add_word(&denominator, den.value) != 1) || - (BN_mul_word(&numerator, 10000000000000000ull) != 1) || - (BN_div("ient, NULL, &numerator, &denominator, CAutoBN_CTX()) != 1)) + if ((BN_add_word(&v, num.value) != 1) || + (BN_mul_word(&v, 10000000000000000ull) != 1) || + (BN_div_word(&v, den.value) == ((BN_ULONG)-1))) { throw std::runtime_error("internal bn error"); } // 10^15 <= quotient <= 10^17 - assert(BN_num_bytes("ient) <= 60); + assert(BN_num_bytes(&v) <= 60); - return STAmount(quotient.getulong(), num.offset - den.offset - 16); + return STAmount(v.getulong(), num.offset - den.offset - 16); } STAmount operator*(const STAmount &v1, const STAmount &v2) From 1c895a593d65723df9bfd5292ba54d6cf996e115 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 11 Apr 2012 14:59:31 -0700 Subject: [PATCH 15/15] Sync. --- src/Amount.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 6d881c1fd..0edb6bd44 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -58,6 +58,11 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name) return new STAmount(name, value, offset); } +std::string STAmount::getRaw() const +{ // show raw internal form + return boost::lexical_cast(value) + "e" + boost::lexical_cast(offset); +} + std::string STAmount::getText() const { if (value == 0) return "0"; @@ -246,7 +251,7 @@ STAmount operator*(const STAmount &v1, const STAmount &v2) // Compute (numerator*10 * denominator*10) / 10^18 CBigNum v; if ((BN_add_word(&v, (v1.value*10) + 3) != 1) || - (BN_mul_word(&v, (v2.value*10) + 3) != 1) || + (BN_mul_word(&v, (v2.value*10) + 3) != 1) || (BN_div_word(&v, 1000000000000000000ull) == ((BN_ULONG)-1))) { throw std::runtime_error("internal bn error");