diff options
-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 | } | ||