adding real 128 for fixed point 64.64 math
This commit is contained in:
parent
1a78fd2931
commit
b55ae3431a
3 changed files with 152 additions and 0 deletions
|
|
@ -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
36
include/fc/real128.hpp
Normal 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
115
src/real128.cpp
Normal 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
|
||||
Loading…
Reference in a new issue