diff options
author | Mike Buland <eichlan@xagasoft.com> | 2011-03-08 17:49:23 +0000 |
---|---|---|
committer | Mike Buland <eichlan@xagasoft.com> | 2011-03-08 17:49:23 +0000 |
commit | cd210c95a5a429293aa5c88965d3526116ba8723 (patch) | |
tree | 0a3d42cbdfa9f47c735d5436adf129616105eb44 | |
parent | a5009d2e8c0378180dd3aca39c10c1dc0af3a93e (diff) | |
download | libgats-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').
-rw-r--r-- | src/float.cpp | 130 | ||||
-rw-r--r-- | src/object.cpp | 3 | ||||
-rw-r--r-- | src/unit/basic.unit | 2 | ||||
-rw-r--r-- | src/unit/float.unit | 75 |
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> | ||
8 | using namespace Bu; | ||
6 | Gats::Float::Float() : | 9 | Gats::Float::Float() : |
7 | fVal( 0.0 ) | 10 | fVal( 0.0 ) |
8 | { | 11 | { |
@@ -19,25 +22,128 @@ Gats::Float::~Float() | |||
19 | 22 | ||
20 | void Gats::Float::write( Bu::Stream &rOut ) const | 23 | void 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 | ||
34 | void Gats::Float::read( Bu::Stream &rIn, char cType ) | 95 | void 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 | ||
43 | Bu::Formatter &operator<<( Bu::Formatter &f, const Gats::Float &flt ) | 149 | Bu::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 | |||
20 | using namespace Bu; | ||
21 | |||
22 | suite 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 | } | ||