adding real 128 for fixed point 64.64 math

This commit is contained in:
Daniel Larimer 2014-10-15 17:00:49 -04:00
parent 1a78fd2931
commit b55ae3431a
3 changed files with 152 additions and 0 deletions

View file

@ -92,6 +92,7 @@ option( UNITY_BUILD OFF )
set( fc_sources
src/uint128.cpp
src/real128.cpp
src/variant.cpp
src/exception.cpp
src/variant_object.cpp

36
include/fc/real128.hpp Normal file
View file

@ -0,0 +1,36 @@
#include <fc/uint128.hpp>
namespace fc {
class variant;
/**
* Provides 64.64 fixed point math operations
* based upon base 2^64-1
*/
class real128
{
public:
real128( uint64_t integer = 0):fixed(integer){}
real128( const std::string& str );
operator std::string()const;
friend real128 operator * ( real128 a, const real128& b ) { a *= b; return a; }
friend real128 operator / ( real128 a, const real128& b ) { a /= b; return a; }
friend real128 operator + ( real128 a, const real128& b ) { a += b; return a; }
friend real128 operator - ( real128 a, const real128& b ) { a -= b; return a; }
real128& operator += ( const real128& o );
real128& operator -= ( const real128& o );
real128& operator /= ( const real128& o );
real128& operator *= ( const real128& o );
uint64_t to_uint64()const{ return fixed.high_bits(); }
private:
uint128 fixed;
};
void to_variant( const real128& var, variant& vo );
void from_variant( const variant& var, real128& vo );
} // namespace fc

115
src/real128.cpp Normal file
View file

@ -0,0 +1,115 @@
#include <fc/real128.hpp>
#include <fc/crypto/bigint.hpp>
#include <fc/exception/exception.hpp>
#include <sstream>
namespace fc
{
real128& real128::operator += ( const real128& o )
{
fixed += o.fixed;
return *this;
}
real128& real128::operator -= ( const real128& o )
{
fixed -= o.fixed;
return *this;
}
real128& real128::operator /= ( const real128& o )
{ try {
FC_ASSERT( o.fixed > uint128(0), "Divide by Zero" );
fc::bigint self(fixed);
fc::bigint other(o.fixed);
self *= fc::bigint(uint128(0,-1));
self /= other;
fixed = self;
return *this;
} FC_CAPTURE_AND_RETHROW( (*this)(o) ) }
real128& real128::operator *= ( const real128& o )
{ try {
fc::bigint self(fixed);
fc::bigint other(o.fixed);
self *= other;
self /= fc::bigint(uint128(0,-1));
fixed = self;
return *this;
} FC_CAPTURE_AND_RETHROW( (*this)(o) ) }
real128::real128( const std::string& ratio_str )
{
const char* c = ratio_str.c_str();
int digit = *c - '0';
if (digit >= 0 && digit <= 9)
{
uint64_t int_part = digit;
++c;
digit = *c - '0';
while (digit >= 0 && digit <= 9)
{
int_part = int_part * 10 + digit;
++c;
digit = *c - '0';
}
fixed = fc::uint128(int_part);
}
else
{
// if the string doesn't look like "123.45" or ".45", this code isn't designed to parse it correctly
// in particular, we don't try to handle leading whitespace or '+'/'-' indicators at the beginning
assert(*c == '.');
fixed = fc::uint128();
}
if (*c == '.')
{
c++;
digit = *c - '0';
if (digit >= 0 && digit <= 9)
{
int64_t frac_part = digit;
int64_t frac_magnitude = 10;
++c;
digit = *c - '0';
while (digit >= 0 && digit <= 9)
{
frac_part = frac_part * 10 + digit;
frac_magnitude *= 10;
++c;
digit = *c - '0';
}
*this += real128( frac_part ) / real128( frac_magnitude );
}
}
}
real128::operator std::string()const
{
std::stringstream ss;
ss << to_uint64();
ss << '.';
auto frac = *this * real128( uint128(-1,0) );
frac += real128(1);
ss << std::string( frac.fixed ).substr(1);
auto number = ss.str();
while( number.back() == '0' ) number.pop_back();
return number;
}
void to_variant( const real128& var, variant& vo )
{
vo = std::string(var);
}
void from_variant( const variant& var, real128& vo )
{
vo = real128(var.as_string());
}
} // namespace fc