aboutsummaryrefslogtreecommitdiff
path: root/src/float.cpp
blob: 1b4ebae6697e9d11c17f5e7ea27f35702a014c5d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include "gats/float.h"
#include "gats/integer.h"

#include <bu/formatter.h>
#include <math.h>

#include <bu/sio.h>
using namespace Bu;
Gats::Float::Float() :
	fVal( 0.0 )
{
}

Gats::Float::Float( double f ) :
	fVal( f )
{
}

Gats::Float::~Float()
{
}

void Gats::Float::write( Bu::Stream &rOut ) const
{
	if( fVal == 0.0 )
	{
		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;
		}

		iScale = log( d ) / 0x1.62e42fefa39efp+2; // log( 256.0 )
		if( iScale < 0 ) iScale--;
		d /= pow( 256.0, 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 );
	}
}

void Gats::Float::read( Bu::Stream &rIn, char cType )
{
	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 );
		fVal *= pow( 256.0, iScale );
		if( bNeg ) fVal = -fVal;
	}
}

Bu::Formatter &operator<<( Bu::Formatter &f, const Gats::Float &flt )
{
	return f << "(float) " << flt.getValue();
}