aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2011-03-08 17:49:23 +0000
committerMike Buland <eichlan@xagasoft.com>2011-03-08 17:49:23 +0000
commitcd210c95a5a429293aa5c88965d3526116ba8723 (patch)
tree0a3d42cbdfa9f47c735d5436adf129616105eb44 /src
parenta5009d2e8c0378180dd3aca39c10c1dc0af3a93e (diff)
downloadlibgats-cd210c95a5a429293aa5c88965d3526116ba8723.tar.gz
libgats-cd210c95a5a429293aa5c88965d3526116ba8723.tar.bz2
libgats-cd210c95a5a429293aa5c88965d3526116ba8723.tar.xz
libgats-cd210c95a5a429293aa5c88965d3526116ba8723.zip
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').
Diffstat (limited to 'src')
-rw-r--r--src/float.cpp130
-rw-r--r--src/object.cpp3
-rw-r--r--src/unit/basic.unit2
-rw-r--r--src/unit/float.unit75
4 files changed, 196 insertions, 14 deletions
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 @@
2#include "gats/integer.h" 2#include "gats/integer.h"
3 3
4#include <bu/formatter.h> 4#include <bu/formatter.h>
5#include <math.h>
5 6
7#include <bu/sio.h>
8using namespace Bu;
6Gats::Float::Float() : 9Gats::Float::Float() :
7 fVal( 0.0 ) 10 fVal( 0.0 )
8{ 11{
@@ -19,25 +22,128 @@ Gats::Float::~Float()
19 22
20void Gats::Float::write( Bu::Stream &rOut ) const 23void Gats::Float::write( Bu::Stream &rOut ) const
21{ 24{
22 if( sWriteCache.isEmpty() ) 25 if( fVal == 0.0 )
23 { 26 {
24 char buf[50]; 27 if( signbit( fVal ) )
28 rOut.write("FZ", 2 );
29 else
30 rOut.write("Fz", 2 );
31 }
32 else if( !isfinite( fVal ) )
33 {
34 if( isnan( fVal ) )
35 {
36 if( signbit( fVal ) )
37 rOut.write("FN", 2 );
38 else
39 rOut.write("Fn", 2 );
40 }
41 else
42 {
43 if( signbit( fVal ) )
44 rOut.write("FI", 2 );
45 else
46 rOut.write("Fi", 2 );
47 }
48 }
49 else
50 {
51 rOut.write("f", 1 );
52 double d = fVal;
53 bool bNeg = false;
54 int64_t iScale=0;
55 if( signbit( d ) )
56 {
57 bNeg = true;
58 d = -d;
59 }
25 60
26 int iSize = snprintf( buf, 50, "%la", fVal ); 61 if( d == 0.0 )
27 sWriteCache.set( buf, iSize ); 62 {
63 }
64 else if( d < 1.0 )
65 {
66 while( d < 1.0 )
67 {
68 d *= 256.0;
69 iScale--;
70 }
71 }
72 else
73 {
74 while( d >= 256.0 )
75 {
76 d *= 0x1p-8; // That's .00390625, or 1/256
77 iScale++;
78 }
79 }
80 Bu::String s;
81 s += (uint8_t)(d);
82 d -= (int)d;
83 for( int j = 0; j < 150 && d; j++ )
84 {
85 d = d*256.0;
86 s += (uint8_t)d;
87 d -= (int)d;
88 }
89 Gats::Integer::writePackedInt( rOut, bNeg?-s.getSize():s.getSize() );
90 rOut.write( s.getStr(), s.getSize() );
91 Gats::Integer::writePackedInt( rOut, iScale );
28 } 92 }
29 rOut.write("f", 1 );
30 Gats::Integer::writePackedInt( rOut, sWriteCache.getSize() );
31 rOut.write( sWriteCache.getStr(), sWriteCache.getSize() );
32} 93}
33 94
34void Gats::Float::read( Bu::Stream &rIn, char cType ) 95void Gats::Float::read( Bu::Stream &rIn, char cType )
35{ 96{
36 int iSize; 97 if( cType == 'F' )
37 Gats::Integer::readPackedInt( rIn, iSize ); 98 {
38 char buf[50]; 99 char buf;
39 buf[rIn.read( buf, iSize )] = '\0'; 100 rIn.read( &buf, 1 );
40 sscanf( buf, "%la", &fVal ); 101 switch( buf )
102 {
103 case 'N': fVal = -NAN; break;
104 case 'n': fVal = NAN; break;
105 case 'I': fVal = -INFINITY; break;
106 case 'i': fVal = INFINITY; break;
107 case 'Z': fVal = -0.0; break;
108 case 'z': fVal = 0.0; break;
109 }
110 }
111 else if( cType == 'f' )
112 {
113 int64_t iStr;
114 Gats::Integer::readPackedInt( rIn, iStr );
115 bool bNeg = false;
116 if( iStr < 0 )
117 {
118 bNeg = true;
119 iStr = -iStr;
120 }
121 Bu::String s( iStr );
122 rIn.read( s.getStr(), iStr );
123 fVal = 0.0;
124 for( int j = iStr-1; j > 0; j-- )
125 {
126 fVal = (fVal+(uint8_t)s[j])*0x1p-8;
127 }
128 fVal += (uint8_t)s[0];
129 int64_t iScale;
130 Gats::Integer::readPackedInt( rIn, iScale );
131 if( iScale < 0 )
132 {
133 for( int64_t j = 0; j > iScale; j-- )
134 {
135 fVal *= 0x1p-8;
136 }
137 }
138 else
139 {
140 for( int64_t j = 0; j < iScale; j++ )
141 {
142 fVal *= 256.0;
143 }
144 }
145 if( bNeg ) fVal = -fVal;
146 }
41} 147}
42 148
43Bu::Formatter &operator<<( Bu::Formatter &f, const Gats::Float &flt ) 149Bu::Formatter &operator<<( Bu::Formatter &f, const Gats::Float &flt )
diff --git a/src/object.cpp b/src/object.cpp
index 1908904..af81017 100644
--- a/src/object.cpp
+++ b/src/object.cpp
@@ -46,7 +46,8 @@ Gats::Object *Gats::Object::read( Bu::Stream &rIn )
46 pObj = new Gats::Dictionary(); 46 pObj = new Gats::Dictionary();
47 break; 47 break;
48 48
49 case 'f': 49 case 'f': // Normal floats
50 case 'F': // Special float values
50 pObj = new Gats::Float(); 51 pObj = new Gats::Float();
51 break; 52 break;
52 53
diff --git a/src/unit/basic.unit b/src/unit/basic.unit
index 369e095..3ab8dc2 100644
--- a/src/unit/basic.unit
+++ b/src/unit/basic.unit
@@ -145,7 +145,7 @@ suite Basic
145 145
146 { 146 {
147 Gats::Dictionary dict; 147 Gats::Dictionary dict;
148 dict.insert("bool", true ); 148 dict.insert("bool", new Gats::Boolean(true) );
149 dict.insert("int", 33403055 ); 149 dict.insert("int", 33403055 );
150 dict.insert("str", "Hey there" ); 150 dict.insert("str", "Hey there" );
151 dict.write( mb ); 151 dict.write( mb );
diff --git a/src/unit/float.unit b/src/unit/float.unit
new file mode 100644
index 0000000..0473ffb
--- /dev/null
+++ b/src/unit/float.unit
@@ -0,0 +1,75 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2010 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "gats/dictionary.h"
10#include "gats/float.h"
11#include "gats/string.h"
12
13#include "bu/membuf.h"
14#include "bu/list.h"
15#include "bu/sio.h"
16
17#include <stdlib.h>
18#include <math.h>
19
20using namespace Bu;
21
22suite Basic
23{
24 void rw( double dVal )
25 {
26 Bu::MemBuf mb;
27
28 Gats::Float( dVal ).write( mb );
29
30 mb.setPos( 0 );
31
32 Gats::Object *pObj = Gats::Object::read( mb );
33 unitTest( pObj != NULL );
34 unitTest( pObj->getType() == Gats::typeFloat );
35 Gats::Float *pFlt = dynamic_cast<Gats::Float *>(pObj);
36// printf("In: %a\nOut: %a\n", dVal, pFlt->getValue() );
37 if( isnan( dVal ) )
38 unitTest( isnan(pFlt->getValue()) == isnan(dVal) );
39 else
40 unitTest( pFlt->getValue() == dVal );
41 unitTest( signbit(pFlt->getValue()) == signbit(dVal) );
42
43 delete pObj;
44 }
45
46 test positive
47 {
48 rw( 8485738457.0 );
49 rw( 0.000000000000001928173 );
50 rw( 1.0 );
51 rw( 0.0 );
52 rw( M_PI );
53 }
54
55 test negitave
56 {
57 rw( -8485738457.0 );
58 rw( -0.000000000000001928173 );
59 rw( -1.0 );
60 rw( -0.0 );
61 rw( -M_PI );
62 }
63
64 test inf
65 {
66 rw( INFINITY );
67 rw( -INFINITY );
68 }
69
70 test nan
71 {
72 rw( NAN );
73 rw( -NAN );
74 }
75}