Change fixed point types to have digit count

Signed-off-by: VoR0220 <rj@erisindustries.com>
This commit is contained in:
VoR0220
2017-07-19 21:49:01 +01:00
committed by Alex Beregszaszi
parent 6d6d4f6907
commit 78769f3b39
5 changed files with 127 additions and 113 deletions
+58 -43
View File
@@ -196,9 +196,9 @@ TypePointer Type::fromElementaryTypeName(ElementaryTypeNameToken const& _type)
case Token::UInt:
return make_shared<IntegerType>(256, IntegerType::Modifier::Unsigned);
case Token::Fixed:
return make_shared<FixedPointType>(128, 128, FixedPointType::Modifier::Signed);
return make_shared<FixedPointType>(128, 19, FixedPointType::Modifier::Signed);
case Token::UFixed:
return make_shared<FixedPointType>(128, 128, FixedPointType::Modifier::Unsigned);
return make_shared<FixedPointType>(128, 19, FixedPointType::Modifier::Unsigned);
case Token::Byte:
return make_shared<FixedBytesType>(1);
case Token::Address:
@@ -352,12 +352,13 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
else if (_convertTo.category() == Category::FixedPoint)
{
FixedPointType const& convertTo = dynamic_cast<FixedPointType const&>(_convertTo);
if (convertTo.integerBits() < m_bits || isAddress())
if (((u256(1) << m_bits) <= convertTo.numBits() && convertTo.fractionalDigits() == 0) || isAddress())
return false;
else if (isSigned())
return convertTo.isSigned();
else
return !convertTo.isSigned() || convertTo.integerBits() > m_bits;
return !convertTo.isSigned() || convertTo.numBits() > m_bits;
}
else
return false;
@@ -487,22 +488,20 @@ MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) cons
return MemberList::MemberMap();
}
FixedPointType::FixedPointType(int _integerBits, int _fractionalBits, FixedPointType::Modifier _modifier):
m_integerBits(_integerBits), m_fractionalBits(_fractionalBits), m_modifier(_modifier)
FixedPointType::FixedPointType(int _totalBits, int _fractionalDigits, FixedPointType::Modifier _modifier):
m_totalBits(_totalBits), m_fractionalDigits(_fractionalDigits), m_modifier(_modifier)
{
solAssert(
m_integerBits + m_fractionalBits > 0 &&
m_integerBits + m_fractionalBits <= 256 &&
m_integerBits % 8 == 0 &&
m_fractionalBits % 8 == 0,
8 <= m_totalBits && m_totalBits <= 256 && m_totalBits % 8 == 0 &&
0 <= m_fractionalDigits && m_fractionalDigits <= 80,
"Invalid bit number(s) for fixed type: " +
dev::toString(_integerBits) + "x" + dev::toString(_fractionalBits)
);
dev::toString(_totalBits) + "x" + dev::toString(_fractionalDigits)
);
}
string FixedPointType::identifier() const
{
return "t_" + string(isSigned() ? "" : "u") + "fixed" + std::to_string(integerBits()) + "x" + std::to_string(fractionalBits());
return "t_" + string(isSigned() ? "" : "u") + "fixed" + std::to_string(numBits()) + "x" + std::to_string(fractionalDigits());
}
bool FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) const
@@ -510,12 +509,10 @@ bool FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) const
if (_convertTo.category() == category())
{
FixedPointType const& convertTo = dynamic_cast<FixedPointType const&>(_convertTo);
if (convertTo.m_integerBits < m_integerBits || convertTo.m_fractionalBits < m_fractionalBits)
if (convertTo.numBits() < m_totalBits || convertTo.fractionalDigits() < m_fractionalDigits)
return false;
else if (isSigned())
return convertTo.isSigned();
else
return !convertTo.isSigned() || (convertTo.m_integerBits > m_integerBits);
return convertTo.maximumPossibleInteger() >= maximumPossibleInteger();
}
return false;
}
@@ -527,6 +524,31 @@ bool FixedPointType::isExplicitlyConvertibleTo(Type const& _convertTo) const
_convertTo.category() == Category::FixedBytes;
}
/*bool FixedPointType::canHoldInteger(unsigned const _bits, bool const _signed) const
{
// If fixed type has 200 bits and 2 fractional digits, integer has 8 bits, then conversion is possible.
// Write helper function that returns max integer number, not necessarily the bits.
// 2^m_bits <= integer
// REMINDER: The below was a work in progress until better solution thought up, see below:
// add min and max number functions to integer and fixed types, use them when converting types.
if (_signed && isSigned())
{
u256 maxInteger = (u256(1) << _bits) - 1;
u256 maxFixedInteger = u256(((u256(1) << numBits()) - 1) / (pow(bigint(10), decimalDigits())));
}
else if (_signed && !isSigned())
{
}
else
{
u256 maxInteger = (u256(1) << _bits) - 1;
u256 maxFixedInteger = u256(((u256(1) << numBits()) - 1) / (pow(bigint(10), decimalDigits())));
return maxInteger <= maxFixedInteger;
}
}*/
TypePointer FixedPointType::unaryOperatorResult(Token::Value _operator) const
{
// "delete" is ok for all fixed types
@@ -549,13 +571,13 @@ bool FixedPointType::operator==(Type const& _other) const
if (_other.category() != category())
return false;
FixedPointType const& other = dynamic_cast<FixedPointType const&>(_other);
return other.m_integerBits == m_integerBits && other.m_fractionalBits == m_fractionalBits && other.m_modifier == m_modifier;
return other.m_totalBits == m_totalBits && other.m_fractionalDigits == m_fractionalDigits && other.m_modifier == m_modifier;
}
string FixedPointType::toString(bool) const
{
string prefix = isSigned() ? "fixed" : "ufixed";
return prefix + dev::toString(m_integerBits) + "x" + dev::toString(m_fractionalBits);
return prefix + dev::toString(m_totalBits) + "x" + dev::toString(m_fractionalDigits);
}
TypePointer FixedPointType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
@@ -746,9 +768,12 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
// We disallow implicit conversion if we would have to truncate (fixedPointType()
// can return a type that requires truncation).
rational value = m_value * (bigint(1) << fixed->fractionalBits());
rational value = m_value * boost::multiprecision::pow(bigint(10), fixed->fractionalDigits());
cout << "value denominator: " << value.denominator() << endl;
cout << "value: " << value << endl;
return value.denominator() == 1 && fixed->isImplicitlyConvertibleTo(_convertTo);
}
cout << "could not convert to fixed type" << endl;
return false;
}
else if (_convertTo.category() == Category::FixedBytes)
@@ -954,9 +979,9 @@ u256 RationalNumberType::literalValue(Literal const*) const
{
auto fixed = fixedPointType();
solAssert(!!fixed, "");
rational shifted = m_value * (bigint(1) << fixed->fractionalBits());
// truncate
shiftedValue = shifted.numerator() / shifted.denominator();
shiftedValue = m_value.numerator() / m_value.denominator();
cout << "Shifted value: " << shiftedValue << endl;
}
// we ignore the literal and hope that the type was correctly determined
@@ -997,23 +1022,27 @@ shared_ptr<IntegerType const> RationalNumberType::integerType() const
shared_ptr<FixedPointType const> RationalNumberType::fixedPointType() const
{
bool negative = (m_value < 0);
unsigned fractionalBits = 0;
unsigned fractionalDigits = 0;
rational value = abs(m_value); // We care about the sign later.
rational maxValue = negative ?
rational(bigint(1) << 255, 1):
rational((bigint(1) << 256) - 1, 1);
while (value * 0x100 <= maxValue && value.denominator() != 1 && fractionalBits < 256)
while (value * 10 <= maxValue && value.denominator() != 1 && fractionalDigits < 80)
{
value *= 0x100;
fractionalBits += 8;
value *= 10;
fractionalDigits++;
}
if (value > maxValue)
{
cout << "value > maxValue" << endl;
return shared_ptr<FixedPointType const>();
}
// u256(v) is the actual value that will be put on the stack
// From here on, very similar to integerType()
bigint v = value.numerator() / value.denominator();
cout << "Big int: " << u256(v) << endl;
if (negative)
// modify value to satisfy bit requirements for negative numbers:
// add one bit for sign and decrement because negative numbers can be larger
@@ -1022,26 +1051,12 @@ shared_ptr<FixedPointType const> RationalNumberType::fixedPointType() const
if (v > u256(-1))
return shared_ptr<FixedPointType const>();
unsigned totalBits = bytesRequired(v) * 8;
unsigned totalBits = max(bytesRequired(v), 1u) * 8;
solAssert(totalBits <= 256, "");
unsigned integerBits = totalBits >= fractionalBits ? totalBits - fractionalBits : 0;
// Special case: Numbers between -1 and 0 have their sign bit in the fractional part.
if (negative && abs(m_value) < 1 && totalBits > fractionalBits)
{
fractionalBits += 8;
integerBits = 0;
}
if (integerBits > 256 || fractionalBits > 256 || fractionalBits + integerBits > 256)
return shared_ptr<FixedPointType const>();
if (integerBits == 0 && fractionalBits == 0)
{
integerBits = 0;
fractionalBits = 8;
}
cout << "rational turned into " << (negative ? "fixed" : "ufixed") << totalBits << "x" << fractionalDigits << endl;
return make_shared<FixedPointType>(
integerBits, fractionalBits,
totalBits, fractionalDigits,
negative ? FixedPointType::Modifier::Signed : FixedPointType::Modifier::Unsigned
);
}
+15 -8
View File
@@ -321,6 +321,10 @@ public:
int numBits() const { return m_bits; }
bool isAddress() const { return m_modifier == Modifier::Address; }
bool isSigned() const { return m_modifier == Modifier::Signed; }
u256 maximumPossibleInteger() const { return isSigned() ?
u256((u256(1) << m_bits) - 1):
u256((u256(1) << m_bits));
}
bigint minValue() const;
bigint maxValue() const;
@@ -342,7 +346,7 @@ public:
};
virtual Category category() const override { return Category::FixedPoint; }
explicit FixedPointType(int _integerBits, int _fractionalBits, Modifier _modifier = Modifier::Unsigned);
explicit FixedPointType(int _totalBits, int _fractionalDigits, Modifier _modifier = Modifier::Unsigned);
virtual std::string identifier() const override;
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
@@ -352,8 +356,8 @@ public:
virtual bool operator==(Type const& _other) const override;
virtual unsigned calldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : (m_integerBits + m_fractionalBits) / 8; }
virtual unsigned storageBytes() const override { return (m_integerBits + m_fractionalBits) / 8; }
virtual unsigned calldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : m_totalBits / 8; }
virtual unsigned storageBytes() const override { return m_totalBits / 8; }
virtual bool isValueType() const override { return true; }
virtual std::string toString(bool _short) const override;
@@ -361,14 +365,17 @@ public:
virtual TypePointer encodingType() const override { return shared_from_this(); }
virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
int numBits() const { return m_integerBits + m_fractionalBits; }
int integerBits() const { return m_integerBits; }
int fractionalBits() const { return m_fractionalBits; }
int numBits() const { return m_totalBits; }
int fractionalDigits() const { return m_fractionalDigits; }
bool isSigned() const { return m_modifier == Modifier::Signed; }
u256 maximumPossibleInteger() const { return isSigned() ?
u256(((u256(1) << m_totalBits) - 1) / (pow(bigint(10), m_fractionalDigits))):
u256(((u256(1) << m_totalBits)) / (pow(bigint(10), m_fractionalDigits)));
}
private:
int m_integerBits;
int m_fractionalBits;
int m_totalBits;
int m_fractionalDigits;
Modifier m_modifier;
};
+1 -1
View File
@@ -504,7 +504,7 @@ void CompilerUtils::convertType(
//shift all integer bits onto the left side of the fixed type
FixedPointType const& targetFixedPointType = dynamic_cast<FixedPointType const&>(_targetType);
if (auto typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack))
if (targetFixedPointType.integerBits() > typeOnStack->numBits())
if (targetFixedPointType.numBits() > typeOnStack->numBits())
cleanHigherOrderBits(*typeOnStack);
solUnimplemented("Not yet implemented - FixedPointType.");
}
+3 -7
View File
@@ -70,7 +70,7 @@ void ElementaryTypeNameToken::assertDetails(Token::Value _baseType, unsigned con
else if (_baseType == Token::UFixedMxN || _baseType == Token::FixedMxN)
{
solAssert(
_first + _second <= 256 && _first % 8 == 0 && _second % 8 == 0,
_first <= 256 && _first % 8 == 0 && _second >= 0 && _second <= 80,
"No elementary type " + string(Token::toString(_baseType)) + to_string(_first) + "x" + to_string(_second) + "."
);
}
@@ -157,12 +157,8 @@ tuple<Token::Value, unsigned int, unsigned int> Token::fromIdentifierOrKeyword(s
) {
int n = parseSize(positionX + 1, _literal.end());
if (
0 <= m && m <= 256 &&
8 <= n && n <= 256 &&
m + n > 0 &&
m + n <= 256 &&
m % 8 == 0 &&
n % 8 == 0
8 <= m && m <= 256 && m % 8 == 0 &&
0 <= n && n <= 80
) {
if (keyword == Token::UFixed)
return make_tuple(Token::UFixedMxN, m, n);