File: lldouble.hh

package info (click to toggle)
augustus 3.2.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 289,676 kB
  • sloc: cpp: 48,711; perl: 13,339; ansic: 1,251; makefile: 859; sh: 58
file content (308 lines) | stat: -rw-r--r-- 8,614 bytes parent folder | download | duplicates (2)
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
/*****************************************************************************\
 * Filename : lldouble.hh
 * Author   : Emmanouil Stafilarakis
 * Project  : HMM
 * Version  : 0.1
 *
 * authors: Emmanouil Stafilarakis, Mario Stanke, mario@gobics.de
 *
 * Description: This class implements a double object with a very large
 *              range. It is designed to handle very small (or high) floating
 *              point numbers that would otherwise become zero when multiplied
 *              to each other.
 *
 *
 * Date       |   Author              |  Changes
 *------------|-----------------------|----------------------------------------
 * 17.01.2002 | E. Stafilarakis       | Creation of the file.
 * 06.11.2002 | Mario Stanke          | simplify
 * 19.4.2006  | Mario Stanke          | root
 * 20.9.2007  | Oliver Keller         | partial rewrite
 * 26.7.2008  | Oliver Keller         | exponential
 \*****************************************************************************/

#ifndef _LL_DOUBLE_HH
#define _LL_DOUBLE_HH

// standard C/C++ includes
#include <cmath>
#include <sstream>
#ifdef DEBUG
#include <iostream>
#endif

using namespace std;
typedef ios_base::fmtflags fmtflags;

class LLDouble{
    typedef int exponent_type;

    /* class constants follow
     *
     * NOTE:
     * This procedure can lead to problems when LLDoubles are initialized
     * BEFORE the class constants, giving undefined results running testPrecision
     * 
     * Current solution: ensure that all object files initializing LLDoubles are
     *                   mentioned before lldouble.o when calling the linker
     */

    static const double dbl_inf;

    static const double max_val; // = 2^500
    static const double min_val; // = 2^(-500)

    static const double base;    // = 2^1000
    static const double baseinv; // = 2^(-1000)
    static const double logbase; // = log(base) = 693.15

    static const exponent_type max_exponent; 
    static const exponent_type min_exponent;

    static unsigned temperature; // for "heating", heat = (8-temperature)/8, will later often need to compute pow(d,heat) for LLDoubles d
    static double rest[7]; // precomputed values for heating
 public:
    LLDouble(float x=0.0) : value(x), exponent(0) {} // called when no argument is provided
    LLDouble(double d) : value(d), exponent(0) {
	testPrecision();
    }
    LLDouble(long double d);
    LLDouble(int i) : value((double)i), exponent(0) {}
    LLDouble(long i) : value((double)i), exponent(0) {}

    /*
     * conversion to other types
     */
    long double doubleValue() {
	return (long double)value * std::exp((long double)(exponent) * logbase); 
    }
    string toString(int precision=output_precision, 
 		    fmtflags flags=ios::dec) const;
 
    /*
     * arithmetic operators
     */
    LLDouble& operator+=(const LLDouble& other);
    LLDouble& operator-=(const LLDouble& other) {
	return operator+=(-other);
    }
    LLDouble& operator*=( const LLDouble& other ){
	value *= other.value;
	exponent += other.exponent;
	testPrecision();
	return *this;
    }
    LLDouble& operator/=(const LLDouble& other){
	value /= other.value;
	exponent -= other.exponent;
	testPrecision();
	return *this;
    }

    LLDouble operator+( const LLDouble& other ) const {
	return LLDouble(*this) += other;
    }
    LLDouble operator-( const LLDouble& other ) const {
	return LLDouble(*this) -= other;
    }
    LLDouble operator*( const LLDouble& other ) const {
	return LLDouble(*this) *= other;
    }
    LLDouble operator/( const LLDouble& other ) const {
	return LLDouble(*this) /= other;
    }

    friend LLDouble operator-( const LLDouble& dbl ) {
	return LLDouble(-dbl.value, dbl.exponent);
    }
    LLDouble abs() const {
	return LLDouble(std::abs(value), exponent);
    }
    friend LLDouble abs( const LLDouble& dbl ) {
	return dbl.abs();
    }

    /*
     * comparative operators 
     */
    bool operator==(const LLDouble& other) const;
    bool operator>(const LLDouble& other) const;
    bool operator!=(const LLDouble& other) const {
	return !(*this == other);
    }
    bool operator<(const LLDouble& other) const {
	return other > (*this);
    }
    bool operator<=(const LLDouble& other) const {
	return !((*this) > other);
    }
    bool operator>=(const LLDouble& other) const {
	return !(other > (*this));
    }

    /*
     * root and exponential functions
     */
    LLDouble pow(double x) const;
    LLDouble getRoot(int r) const {
	if (value < 0 && r%2)
	    return -pow(-*this,1.0/r);
	return pow(1.0/r);
    }
    double log() const { 
	return std::log(value) + exponent*logbase; 
    }
    double log(int otherbase) const { 
        return log()/std::log((double) otherbase);
    }
    friend double log(const LLDouble& lld) {
	return lld.log();
    }
    friend double log(int otherbase, const LLDouble& lld) {
	return lld.log(otherbase);
    }
    static LLDouble exp(double x);
    static LLDouble pow(const LLDouble& lld, double x) {
	return lld.pow(x);
    }
    LLDouble heated();

    /*
     * I/O stream operators 
     */
    friend istream& operator>>( istream& in, LLDouble& lld ){
	lld.read( in );
	return in;
    }
    friend ostream& operator<<( ostream& out, const LLDouble& lld ){
	int precision = output_precision > 0 ? output_precision : out.precision();
	return out << lld.toString(precision, out.flags());
    }
    
    /*
     * class functions
     */
    static LLDouble getMaxDouble() {
	return LLDouble(max_val, max_exponent);
    }
    static LLDouble getMinDouble() {
	return LLDouble(min_val, min_exponent);
    }
    static void setOutputPrecision(int p){
	output_precision = p;
    };
    static int getOutputPrecision(){
	return output_precision;
    };
    static LLDouble infinity() {
	return LLDouble(dbl_inf, max_exponent);
    }
    static void setTemperature(unsigned t);

private:
    // for internal use: directly set the data fields
    LLDouble(double v, exponent_type e) : 
	value(v), exponent(e) {}
//     void print( ostream& out ) const;
    void read( istream& in );
    void testPrecision( ) {
	// value is 0, or NaN: keep and set exponent=0
	if (value == 0.0 || std::isnan((double) value)) {
	    exponent = 0;
	    return;
	} // value is infinity: set exponent = max_exponent
	else if (std::abs(value) == dbl_inf) {
	    exponent = max_exponent;
	    return;
	}
	// value is too small 
	while( std::abs(value) < min_val) {
	    if (exponent == min_exponent) {
		value = 0; exponent = 0; return;
	    }
	    value *= base;
	    exponent--;
	}
	// value is too large
	while( std::abs(value) > max_val) {
	    if (exponent >= max_exponent) {
		value = value>0? dbl_inf : -dbl_inf; 
		exponent = max_exponent; return;
	    }
	    value *= baseinv;
	    exponent++;
	}
    }
    static int output_precision;
    double       value; // long double : 40% more time, 32% more memory than double, probably no difference
    exponent_type         exponent;
};

/*
 * arithmetic operators for double and LLDouble
 */
inline LLDouble operator/(long double i, const LLDouble& lld ) {
    return LLDouble(i)/lld;
}

inline LLDouble operator*(long double i, const LLDouble& lld) {
    return LLDouble(i)*lld;
}

inline LLDouble operator+(long double i, const LLDouble& lld) {
    return LLDouble(i)+lld;
}

inline LLDouble operator-(long double i, const LLDouble& lld) {
    return LLDouble(i)-lld;
}

#ifdef DEBUG
inline LLDouble relative_error(const LLDouble& d1, const LLDouble& d2) {
    return abs((d1/d2).doubleValue()-1);
}

inline bool relerror_lessthan(const LLDouble& d1, const LLDouble& d2, double rel_error) {
    if (relative_error(d1, d2) >= rel_error) {
	cerr << "relative error: " << relative_error(d1, d2) << "\n";
	return false;
    }
    return true;
}

inline bool almost_equal(const LLDouble& d1, const LLDouble& d2) {
    return relerror_lessthan(d1,d2,0.01);
}
#endif

/*
 * class LogDouble
 *
 * internally stores floating point numbers using their logarithm
 * this saves time when multiplication and division is a frequent operation
 */

class LogDouble{
public:
    LogDouble( double d=0.0 );
    LogDouble( const LogDouble& other ){
	logvalue    = other.logvalue;
    }

    LogDouble operator*( const LogDouble& other ) const;
    LogDouble& operator*=( const LogDouble& other );

    // Assignment operator
    LogDouble& operator=( const LogDouble& other ){
	logvalue    = other.logvalue;
	return *this;
    }
    void print( ostream& out ) const;
private:
    static int outputprecision;
    double  logvalue;
};

ostream& operator<<( ostream& out, const LogDouble& logd );

#endif   //  _LL_DOUBLE_HH