From cd210c95a5a429293aa5c88965d3526116ba8723 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 8 Mar 2011 17:49:23 +0000 Subject: The new float format is in place. The encoder/decoder may not be as fast right now as it could be, but it is universal, which is preferable in many cases. We effectively use a normalized base-256 format to store the number, with a scale, also with a base of 256. Basically, with x86 doubles, the C99 standard textual, lossless hex encoding format is at max 23 bytes. This encoding is equivelent but at max 11 bytes, including the format specifier ('f'). --- src/float.cpp | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 118 insertions(+), 12 deletions(-) (limited to 'src/float.cpp') diff --git a/src/float.cpp b/src/float.cpp index 879d74b..f1e9ced 100644 --- a/src/float.cpp +++ b/src/float.cpp @@ -2,7 +2,10 @@ #include "gats/integer.h" #include +#include +#include +using namespace Bu; Gats::Float::Float() : fVal( 0.0 ) { @@ -19,25 +22,128 @@ Gats::Float::~Float() void Gats::Float::write( Bu::Stream &rOut ) const { - if( sWriteCache.isEmpty() ) + if( fVal == 0.0 ) { - char buf[50]; + if( signbit( fVal ) ) + rOut.write("FZ", 2 ); + else + rOut.write("Fz", 2 ); + } + else if( !isfinite( fVal ) ) + { + if( isnan( fVal ) ) + { + if( signbit( fVal ) ) + rOut.write("FN", 2 ); + else + rOut.write("Fn", 2 ); + } + else + { + if( signbit( fVal ) ) + rOut.write("FI", 2 ); + else + rOut.write("Fi", 2 ); + } + } + else + { + rOut.write("f", 1 ); + double d = fVal; + bool bNeg = false; + int64_t iScale=0; + if( signbit( d ) ) + { + bNeg = true; + d = -d; + } - int iSize = snprintf( buf, 50, "%la", fVal ); - sWriteCache.set( buf, iSize ); + if( d == 0.0 ) + { + } + else if( d < 1.0 ) + { + while( d < 1.0 ) + { + d *= 256.0; + iScale--; + } + } + else + { + while( d >= 256.0 ) + { + d *= 0x1p-8; // That's .00390625, or 1/256 + iScale++; + } + } + Bu::String s; + s += (uint8_t)(d); + d -= (int)d; + for( int j = 0; j < 150 && d; j++ ) + { + d = d*256.0; + s += (uint8_t)d; + d -= (int)d; + } + Gats::Integer::writePackedInt( rOut, bNeg?-s.getSize():s.getSize() ); + rOut.write( s.getStr(), s.getSize() ); + Gats::Integer::writePackedInt( rOut, iScale ); } - rOut.write("f", 1 ); - Gats::Integer::writePackedInt( rOut, sWriteCache.getSize() ); - rOut.write( sWriteCache.getStr(), sWriteCache.getSize() ); } void Gats::Float::read( Bu::Stream &rIn, char cType ) { - int iSize; - Gats::Integer::readPackedInt( rIn, iSize ); - char buf[50]; - buf[rIn.read( buf, iSize )] = '\0'; - sscanf( buf, "%la", &fVal ); + if( cType == 'F' ) + { + char buf; + rIn.read( &buf, 1 ); + switch( buf ) + { + case 'N': fVal = -NAN; break; + case 'n': fVal = NAN; break; + case 'I': fVal = -INFINITY; break; + case 'i': fVal = INFINITY; break; + case 'Z': fVal = -0.0; break; + case 'z': fVal = 0.0; break; + } + } + else if( cType == 'f' ) + { + int64_t iStr; + Gats::Integer::readPackedInt( rIn, iStr ); + bool bNeg = false; + if( iStr < 0 ) + { + bNeg = true; + iStr = -iStr; + } + Bu::String s( iStr ); + rIn.read( s.getStr(), iStr ); + fVal = 0.0; + for( int j = iStr-1; j > 0; j-- ) + { + fVal = (fVal+(uint8_t)s[j])*0x1p-8; + } + fVal += (uint8_t)s[0]; + int64_t iScale; + Gats::Integer::readPackedInt( rIn, iScale ); + if( iScale < 0 ) + { + for( int64_t j = 0; j > iScale; j-- ) + { + fVal *= 0x1p-8; + } + } + else + { + for( int64_t j = 0; j < iScale; j++ ) + { + fVal *= 256.0; + } + } + if( bNeg ) fVal = -fVal; + } } Bu::Formatter &operator<<( Bu::Formatter &f, const Gats::Float &flt ) -- cgit v1.2.3