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
|
set( fc_sources
|
||||||
src/uint128.cpp
|
src/uint128.cpp
|
||||||
|
src/real128.cpp
|
||||||
src/variant.cpp
|
src/variant.cpp
|
||||||
src/exception.cpp
|
src/exception.cpp
|
||||||
src/variant_object.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