About half of the rework to support signed floating point amounts.

This commit is contained in:
JoelKatz
2012-05-27 15:54:38 -07:00
parent 3fcdf31096
commit 47fefdc26c
2 changed files with 90 additions and 33 deletions

View File

@@ -164,6 +164,7 @@ void STAmount::canonicalize()
if (mValue == 0)
{
mOffset = 0;
mIsNegative = false;
return;
}
@@ -187,6 +188,7 @@ void STAmount::canonicalize()
if (mValue == 0)
{
mOffset = -100;
mIsNegative = false;
return;
}
@@ -217,13 +219,16 @@ void STAmount::add(Serializer& s) const
if (mIsNative)
{
assert(mOffset == 0);
s.add64(mValue);
if (!mIsNegative) s.add64(mValue | cPosNative);
else s.add64(mValue);
return;
}
if (isZero())
s.add64(cNotNative);
else // Adding 396 centers the offset and sets the "not native" flag
s.add64(mValue + (static_cast<uint64>(mOffset + 396) << (64 - 9)));
else if (mIsNegative) // 512 = not native
s.add64(mValue | (static_cast<uint64>(mOffset + 512 + 97) << (64 - 10)));
else // 256 = positive
s.add64(mValue | (static_cast<uint64>(mOffset + 512 + 256 + 97) << (64 - 10)));
s.add160(mCurrency);
}
@@ -232,34 +237,45 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name)
uint64 value = sit.get64();
if ((value & cNotNative) == 0)
return new STAmount(name, value);
{ // native
if ((value & cPosNative) != 0)
return new STAmount(name, value & ~cPosNative, false); // positive
return new STAmount(name, value, true); // negative
}
uint160 currency = sit.get160();
if (!currency)
throw std::runtime_error("invalid native currency");
int offset = static_cast<int>(value >> (64-9)); // 9 bits for the offset and "not native" flag
value &= ~(1023ull << (64-9));
int offset = static_cast<int>(value >> (64 - 10)); // 10 bits for the offset, sign and "not native" flag
value &= ~(1023ull << (64-10));
if (value == 0)
{
if (offset != 256)
if (offset != 512)
throw std::runtime_error("invalid currency value");
return new STAmount(name, currency);
}
else
{
offset -= 396; // center the range and remove the "not native" bit
if ((value < cMinValue) || (value > cMaxValue) || (offset < cMinOffset) || (offset > cMaxOffset))
throw std::runtime_error("invalid currency value");
}
return new STAmount(name, currency, value, offset);
bool isNegative = (offset & 256) == 0;
offset = (offset & 255) - 97; // center the range
if ((value < cMinValue) || (value > cMaxValue) || (offset < cMinOffset) || (offset > cMaxOffset))
throw std::runtime_error("invalid currency value");
return new STAmount(name, currency, value, offset, isNegative);
}
std::string STAmount::getRaw() const
{ // show raw internal form
if (mValue == 0) return "0";
if (mIsNative) return boost::lexical_cast<std::string>(mValue);
return mCurrency.GetHex() + ": " +
if (mIsNative)
{
if (mIsNegative) return std::string("-") + boost::lexical_cast<std::string>(mValue);
else return boost::lexical_cast<std::string>(mValue);
}
if (mIsNegative)
return mCurrency.GetHex() + ": -" +
boost::lexical_cast<std::string>(mValue) + "e" + boost::lexical_cast<std::string>(mOffset);
else return mCurrency.GetHex() + ": " +
boost::lexical_cast<std::string>(mValue) + "e" + boost::lexical_cast<std::string>(mOffset);
}
@@ -267,9 +283,19 @@ std::string STAmount::getText() const
{ // keep full internal accuracy, but make more human friendly if posible
if (isZero()) return "0";
if (mIsNative)
return boost::lexical_cast<std::string>(mValue);
{
if (mIsNegative)
return std::string("-") + boost::lexical_cast<std::string>(mValue);
else return boost::lexical_cast<std::string>(mValue);
}
if ((mOffset < -25) || (mOffset > -5))
return boost::lexical_cast<std::string>(mValue) + "e" + boost::lexical_cast<std::string>(mOffset);
{
if (mIsNegative)
return std::string("-") + boost::lexical_cast<std::string>(mValue) +
"e" + boost::lexical_cast<std::string>(mOffset);
else
return boost::lexical_cast<std::string>(mValue) + "e" + boost::lexical_cast<std::string>(mOffset);
}
std::string val = "000000000000000000000000000";
val += boost::lexical_cast<std::string>(mValue);
@@ -285,6 +311,9 @@ std::string STAmount::getText() const
pre = pre.substr(s_pre);
size_t s_post = post.find_last_not_of('0');
if (mIsNegative) pre = std::string("-") + pre;
if (s_post == std::string::npos)
return pre;
else
@@ -365,6 +394,12 @@ STAmount& STAmount::operator-=(const STAmount& a)
return *this;
}
STAmount STAmount::operator-(void) const
{
if (mValue == 0) return STAmount(NULL, mValue, mOffset, mIsNative, !mIsNegative);
return *this;
}
STAmount& STAmount::operator=(const STAmount& a)
{
mValue = a.mValue;
@@ -779,6 +814,8 @@ BOOST_AUTO_TEST_CASE( CustomCurrency_test )
uint160 currency(1);
STAmount zero(currency), one(currency, 1), hundred(currency, 100);
serdes(one).getRaw();
if (serdes(zero) != zero) BOOST_FAIL("STAmount fail");
if (serdes(one) != one) BOOST_FAIL("STAmount fail");
if (serdes(hundred) != hundred) BOOST_FAIL("STAmount fail");

View File

@@ -208,49 +208,68 @@ protected:
uint160 mCurrency;
uint64 mValue;
int mOffset;
bool mIsNative;
bool mIsNative, mIsNegative;
void canonicalize();
STAmount* duplicate() const { return new STAmount(name, mCurrency, mValue, mOffset); }
STAmount* duplicate() const { return new STAmount(*this); }
static STAmount* construct(SerializerIterator&, const char* name = NULL);
STAmount(bool, uint64 value) : mValue(value), mOffset(0), mIsNative(true) { ; }
static const int cMinOffset = -96, cMaxOffset = 80;
static const uint64 cMinValue = 1000000000000000ull, cMaxValue = 9999999999999999ull;
static const uint64 cMaxNative = 9000000000000000000ull;
static const uint64 cNotNative = 0x8000000000000000ull;
static const uint64 cPosNative = 0x4000000000000000ull;
STAmount(bool, uint64 value) : mValue(value), mOffset(0), mIsNative(true), mIsNegative(false) { ; }
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)
{ ; }
public:
STAmount(uint64 v = 0) : mValue(v), mOffset(0), mIsNative(true)
STAmount(uint64 v = 0) : mValue(v), mOffset(0), mIsNative(true), mIsNegative(false)
{ ; }
STAmount(const char* n, uint64 v = 0) : SerializedType(n), mValue(v), mOffset(0), mIsNative(true)
STAmount(const char* n, uint64 v = 0)
: SerializedType(n), mValue(v), mOffset(0), mIsNative(true), mIsNegative(false)
{ ; }
STAmount(const uint160& currency, uint64 v = 0, int off = 0) : mCurrency(currency), mValue(v), mOffset(off)
STAmount(const uint160& currency, uint64 v = 0, int off = 0)
: 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)
mCurrency(currency), mValue(v), mOffset(off), mIsNegative(false)
{ canonicalize(); }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char* name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const { return mIsNative ? 8 : 28; }
SerializedTypeID getSType() const { return STI_AMOUNT; }
int getLength() const { return mIsNative ? 8 : 28; }
SerializedTypeID getSType() const { return STI_AMOUNT; }
std::string getText() const;
std::string getRaw() const;
void add(Serializer& s) const;
int getOffset() const { return mOffset; }
uint64 getValue() const { return mValue; }
void setValue(const STAmount& v) { mValue=v; }
int getOffset() const { return mOffset; }
uint64 getValue() const { return mValue; }
void setValue(const STAmount& v) { mValue=v; }
std::string getCurrencyHuman();
bool isNative() const { return mIsNative; }
bool isNative() const { return mIsNative; }
bool isZero() const { return mValue == 0; }
bool isNegative() const { return mIsNegative && !isZero(); }
bool isPositive() const { return !mIsNegative && !isZero(); }
bool isGEZero() const { return !mIsNegative; }
void changeSign() { if (!isZero()) mIsNegative = !mIsNegative; }
void zero() { mOffset = mIsNative ? -100 : 0; mValue = 0; mIsNegative = false; }
const uint160& getCurrency() const { return mCurrency; }
void zero() { mOffset = mIsNative ? -100 : 0; mValue = 0; }
bool isZero() const { return mValue == 0; }
bool setValue(const std::string& sAmount, const std::string& sCurrency);
virtual bool isEquivalent(const SerializedType& t) const;
@@ -271,6 +290,7 @@ public:
bool operator>=(uint64) const;
STAmount operator+(uint64) const;
STAmount operator-(uint64) const;
STAmount operator-(void) const;
STAmount& operator+=(const STAmount&);
STAmount& operator-=(const STAmount&);