Augustus 3.4.0
Loading...
Searching...
No Matches
lldouble.hh
1/*
2 * lldouble.hh
3 *
4 * License: Artistic License, see file LICENSE.TXT or
5 * https://opensource.org/licenses/artistic-license-1.0
6 */
7
8#ifndef _LL_DOUBLE_HH
9#define _LL_DOUBLE_HH
10
11// standard C/C++ includes
12#include <cmath>
13#include <sstream>
14#ifdef DEBUG
15#include <iostream>
16#endif
17
18using namespace std;
19typedef ios_base::fmtflags fmtflags;
20
32 typedef int exponent_type;
33
34 /* class constants follow
35 *
36 * NOTE:
37 * This procedure can lead to problems when LLDoubles are initialized
38 * BEFORE the class constants, giving undefined results running testPrecision
39 *
40 * Current solution: ensure that all object files initializing LLDoubles are
41 * mentioned before lldouble.o when calling the linker
42 */
43
44 static const double dbl_inf;
45
46 static const double max_val; // = 2^500
47 static const double min_val; // = 2^(-500)
48
49 static const double base; // = 2^1000
50 static const double baseinv; // = 2^(-1000)
51 static const double logbase; // = log(base) = 693.15
52
53 static const exponent_type max_exponent;
54 static const exponent_type min_exponent;
55
56 static unsigned temperature; // for "heating", heat = (8-temperature)/8, will later often need to compute pow(d,heat) for LLDoubles d
57 static double rest[7]; // precomputed values for heating
58 public:
59 LLDouble(float x=0.0) : value(x), exponent(0) {} // called when no argument is provided
60 LLDouble(double d) : value(d), exponent(0) {
61 testPrecision();
62 }
63 LLDouble(long double d);
64 LLDouble(int i) : value((double)i), exponent(0) {}
65 LLDouble(long i) : value((double)i), exponent(0) {}
66
67 /*
68 * conversion to other types
69 */
70 long double doubleValue() {
71 return (long double)value * std::exp((long double)(exponent) * logbase);
72 }
73 string toString(int precision=output_precision,
74 fmtflags flags=ios::dec) const;
75
76 /*
77 * arithmetic operators
78 */
79 LLDouble& operator+=(const LLDouble& other);
80 LLDouble& operator-=(const LLDouble& other) {
81 return operator+=(-other);
82 }
83 LLDouble& operator*=( const LLDouble& other ){
84 value *= other.value;
85 exponent += other.exponent;
86 testPrecision();
87 return *this;
88 }
89 LLDouble& operator/=(const LLDouble& other){
90 value /= other.value;
91 exponent -= other.exponent;
92 testPrecision();
93 return *this;
94 }
95
96 LLDouble operator+( const LLDouble& other ) const {
97 return LLDouble(*this) += other;
98 }
99 LLDouble operator-( const LLDouble& other ) const {
100 return LLDouble(*this) -= other;
101 }
102 LLDouble operator*( const LLDouble& other ) const {
103 return LLDouble(*this) *= other;
104 }
105 LLDouble operator/( const LLDouble& other ) const {
106 return LLDouble(*this) /= other;
107 }
108
109 friend LLDouble operator-( const LLDouble& dbl ) {
110 return LLDouble(-dbl.value, dbl.exponent);
111 }
112 LLDouble abs() const {
113 return LLDouble(std::abs(value), exponent);
114 }
115 friend LLDouble abs( const LLDouble& dbl ) {
116 return dbl.abs();
117 }
118
119 /*
120 * comparative operators
121 */
122 bool operator==(const LLDouble& other) const;
123 bool operator>(const LLDouble& other) const;
124 bool operator!=(const LLDouble& other) const {
125 return !(*this == other);
126 }
127 bool operator<(const LLDouble& other) const {
128 return other > (*this);
129 }
130 bool operator<=(const LLDouble& other) const {
131 return !((*this) > other);
132 }
133 bool operator>=(const LLDouble& other) const {
134 return !(other > (*this));
135 }
136
137 /*
138 * root and exponential functions
139 */
140 LLDouble pow(double x) const;
141 LLDouble getRoot(int r) const {
142 if (value < 0 && r%2)
143 return -pow(-*this,1.0/r);
144 return pow(1.0/r);
145 }
146 double log() const {
147 return std::log(value) + exponent*logbase;
148 }
149 double log(int otherbase) const {
150 return log()/std::log((double) otherbase);
151 }
152 friend double log(const LLDouble& lld) {
153 return lld.log();
154 }
155 friend double log(int otherbase, const LLDouble& lld) {
156 return lld.log(otherbase);
157 }
158 static LLDouble exp(double x);
159 static LLDouble pow(const LLDouble& lld, double x) {
160 return lld.pow(x);
161 }
162 LLDouble heated();
163
164 /*
165 * I/O stream operators
166 */
167 friend istream& operator>>( istream& in, LLDouble& lld ){
168 lld.read( in );
169 return in;
170 }
171 friend ostream& operator<<( ostream& out, const LLDouble& lld ){
172 int precision = output_precision > 0 ? output_precision : out.precision();
173 return out << lld.toString(precision, out.flags());
174 }
175
176 /*
177 * class functions
178 */
179 static LLDouble getMaxDouble() {
180 return LLDouble(max_val, max_exponent);
181 }
182 static LLDouble getMinDouble() {
183 return LLDouble(min_val, min_exponent);
184 }
185 static void setOutputPrecision(int p){
186 output_precision = p;
187 };
188 static int getOutputPrecision(){
189 return output_precision;
190 };
191 static LLDouble infinity() {
192 return LLDouble(dbl_inf, max_exponent);
193 }
194 static void setTemperature(unsigned t);
195
196private:
197 // for internal use: directly set the data fields
198 LLDouble(double v, exponent_type e) :
199 value(v), exponent(e) {}
200// void print( ostream& out ) const;
201 void read( istream& in );
202 void testPrecision( ) {
203 // value is 0, or NaN: keep and set exponent=0
204 if (value == 0.0 || std::isnan((double) value)) {
205 exponent = 0;
206 return;
207 } // value is infinity: set exponent = max_exponent
208 else if (std::abs(value) == dbl_inf) {
209 exponent = max_exponent;
210 return;
211 }
212 // value is too small
213 while( std::abs(value) < min_val) {
214 if (exponent == min_exponent) {
215 value = 0; exponent = 0; return;
216 }
217 value *= base;
218 exponent--;
219 }
220 // value is too large
221 while( std::abs(value) > max_val) {
222 if (exponent >= max_exponent) {
223 value = value>0? dbl_inf : -dbl_inf;
224 exponent = max_exponent; return;
225 }
226 value *= baseinv;
227 exponent++;
228 }
229 }
230 static int output_precision;
231 double value; // long double : 40% more time, 32% more memory than double, probably no difference
232 exponent_type exponent;
233};
234
235/*
236 * arithmetic operators for double and LLDouble
237 */
238inline LLDouble operator/(long double i, const LLDouble& lld ) {
239 return LLDouble(i)/lld;
240}
241
242inline LLDouble operator*(long double i, const LLDouble& lld) {
243 return LLDouble(i)*lld;
244}
245
246inline LLDouble operator+(long double i, const LLDouble& lld) {
247 return LLDouble(i)+lld;
248}
249
250inline LLDouble operator-(long double i, const LLDouble& lld) {
251 return LLDouble(i)-lld;
252}
253
254#ifdef DEBUG
255inline LLDouble relative_error(const LLDouble& d1, const LLDouble& d2) {
256 return abs((d1/d2).doubleValue()-1);
257}
258
259inline bool relerror_lessthan(const LLDouble& d1, const LLDouble& d2, double rel_error) {
260 if (relative_error(d1, d2) >= rel_error) {
261 cerr << "relative error: " << relative_error(d1, d2) << "\n";
262 return false;
263 }
264 return true;
265}
266
267inline bool almost_equal(const LLDouble& d1, const LLDouble& d2) {
268 return relerror_lessthan(d1,d2,0.01);
269}
270#endif
271
280public:
281 LogDouble( double d=0.0 );
282 LogDouble( const LogDouble& other ){
283 logvalue = other.logvalue;
284 }
285
286 LogDouble operator*( const LogDouble& other ) const;
287 LogDouble& operator*=( const LogDouble& other );
288
289 // Assignment operator
290 LogDouble& operator=( const LogDouble& other ){
291 logvalue = other.logvalue;
292 return *this;
293 }
294 void print( ostream& out ) const;
295private:
296 static int outputprecision;
297 double logvalue;
298};
299
300ostream& operator<<( ostream& out, const LogDouble& logd );
301
302#endif // _LL_DOUBLE_HH
This class implements a double object with a very large range.
Definition lldouble.hh:31
internally stores floating point numbers using their logarithm.
Definition lldouble.hh:279