Project

General

Profile

Statistics
| Branch: | Revision:

root / src / common / bigdecimal.h @ e1750c09

History | View | Annotate | Download (8.94 KB)

1
//==========================================================================
2
//  BIGDECIMAL.H  - part of
3
//                     OMNeT++/OMNEST
4
//            Discrete System Simulation in C++
5
//
6
//  Author: Tamas Borbely
7
//
8
//==========================================================================
9

    
10
/*--------------------------------------------------------------*
11
  Copyright (C) 2006-2008 OpenSim Ltd.
12

13
  This file is distributed WITHOUT ANY WARRANTY. See the file
14
  `license' for details on this and other legal matters.
15
*--------------------------------------------------------------*/
16

    
17
#ifndef __BIGDECIMAL_H
18
#define __BIGDECIMAL_H
19

    
20
#include <string>
21
#include <iostream>
22
#include <math.h>
23
#include <limits.h>
24
#include "commondefs.h"
25
#include "exception.h"
26
#include "intxtypes.h"
27

    
28
NAMESPACE_BEGIN
29

    
30
// maximum number of digits in an int64 number, i.e. number of digits in INT64_MAX.
31
#define INT64_MAX_DIGITS 19
32

    
33
/**
34
 * BigDecimal stores a decimal value as a 64-bit integer and a scale.
35
 * Arithmetic operations are performed by converting the values
36
 * to double and converting the result to BigDecimal, so they
37
 * may lose precision.
38
 */
39
class COMMON_API BigDecimal
40
{
41
  private:
42
    /*
43
     * The value of the number is intVal * 10^scale.
44
     * If two decimal is equal then they have the same intVal and scale (see normalize()).
45
     * Special values (NaN, +-infinity, Nil) use the scale INT_MAX.
46
     */
47
    int64 intVal; // stores digits of the decimal number (up to 18 digits can be stored)
48
    int scale;    // stores the position of the decimal point, must be in the [0,-18] range
49

    
50
    static const int minScale = -18; // XXX the range length must be <= 18, see buffer allocation in ttoa()
51
    static const int maxScale = 0;
52

    
53
    void checkScale(int scale) const
54
    {
55
        if (scale < minScale || scale > maxScale)
56
            throw opp_runtime_error("Scale must be between %d and %d.", minScale, maxScale);
57
    }
58

    
59
    /*
60
     * Sets scale between minScale and maxScale and strips trailing zeros when scale<maxScale.
61
     * 0.0 always has scale=0.
62
     * If x and y equal decimals, then x.intVal==y.intVal and x.scale==y.scale after normalization.
63
     */
64
    void normalize();
65

    
66
    /*
67
     * Returns digits of the decimal number from place-values in [scale,scale+numDigits) as an int64.
68
     */
69
    int64 getDigits(int scale, int numDigits) const;
70

    
71
  public:
72
    /** @name Constants */
73
    //@{
74
    static BigDecimal Zero;
75
    static BigDecimal One;
76
    static BigDecimal MinusOne;
77
    static BigDecimal NaN;
78
    static BigDecimal PositiveInfinity;
79
    static BigDecimal NegativeInfinity;
80
    static BigDecimal Nil;
81
    //@}
82

    
83
    /** @name Constructors. */
84
    //@{
85
    BigDecimal() {intVal=INT64_MAX; scale=INT_MAX;} // == Nil
86
    explicit BigDecimal(int64 intVal, int scale=0) : intVal(intVal), scale(scale) { normalize(); }
87
    BigDecimal(const BigDecimal &x) {operator=(x);}
88
    BigDecimal(double d) {operator=(d);}
89
    //@}
90

    
91
    /** @name Testing for special values */
92
    //@{
93
    bool isNaN() const { return scale == INT_MAX && intVal == 0; }
94
    bool isNil() const { return *this == Nil; }
95
    bool isPositiveInfinity() const {return *this==PositiveInfinity;}
96
    bool isNegativeInfinity() const {return *this==NegativeInfinity;}
97
    bool isInfinity() const {return isPositiveInfinity() || isNegativeInfinity();}
98
    bool isSpecial() const { return scale == INT_MAX; }
99
    //@}
100

    
101
    /** @name Assignments */
102
    //@{
103
    const BigDecimal& operator=(double d);
104
    const BigDecimal& operator=(const BigDecimal& x) {intVal=x.intVal; scale=x.scale; return *this;}
105
    //@}
106

    
107
    /** @name Arithmetic operations */
108
    //@{
109
    const BigDecimal& operator+=(const BigDecimal& x) {*this=*this+x; return *this;}
110
    const BigDecimal& operator-=(const BigDecimal& x) {*this=*this-x; return *this;}
111
    const BigDecimal& operator*=(double d) {*this=BigDecimal(dbl()*d); return *this;}
112
    const BigDecimal& operator/=(double d) {*this=BigDecimal(dbl()/d); return *this;}
113

    
114
#define CHK(a,b) { if ((a).isNaN() || (b).isNaN()) return false; }
115

    
116
    bool operator==(const BigDecimal& x) const  {CHK(*this,x); return intVal == x.intVal && scale == x.scale;}
117
    bool operator!=(const BigDecimal& x) const  {CHK(*this, x); return intVal != x.intVal || scale != x.scale;}
118
    bool operator< (const BigDecimal& x) const;
119
    bool operator> (const BigDecimal& x) const  {CHK(*this, x); return x < *this;}
120
    bool operator<=(const BigDecimal& x) const  {CHK(*this, x); return *this == x || *this < x;}
121
    bool operator>=(const BigDecimal& x) const  {CHK(*this, x); return *this == x || *this > x;}
122

    
123
    COMMON_API friend const BigDecimal operator+(const BigDecimal& x, const BigDecimal& y);
124
    COMMON_API friend const BigDecimal operator-(const BigDecimal& x, const BigDecimal& y);
125

    
126
    friend const BigDecimal operator*(const BigDecimal& x, double d);
127
    friend const BigDecimal operator*(double d, const BigDecimal& x);
128
    friend const BigDecimal operator/(const BigDecimal& x, double d);
129
    friend const BigDecimal operator/(const BigDecimal& x, const BigDecimal& y);
130
    //@}
131

    
132
    /** @name Conversions */
133
    //@{
134
    /**
135
     * Converts big decimal to double. Note that conversion to and from
136
     * double may lose precision.
137
     */
138
    double dbl() const;
139

    
140
    /**
141
     * Converts to string.
142
     */
143
    std::string str() const;
144

    
145
    /**
146
     * Converts to a string. Use this variant over str() where performance is
147
     * critical. The result is placed somewhere in the given buffer (pointer
148
     * is returned), but for performance reasons, not necessarily at the buffer's
149
     * beginning. Please read the documentation of ttoa() for the minimum
150
     * required buffer size.
151
     */
152
    char *str(char *buf) const {char *endp; return BigDecimal::ttoa(buf, *this, endp);}
153

    
154
    /**
155
     * Returns the underlying 64-bit integer.
156
     */
157
    int64 getIntValue() const  {return intVal;}
158

    
159
    /**
160
     * Directly sets the underlying 64-bit integer.
161
     */
162
    const BigDecimal& setIntValue(int64 l) {intVal = l; return *this;}
163

    
164
    /**
165
     * Returns the scale exponent.
166
     */
167
    int getScale() const {return scale;}
168

    
169
    /**
170
     * Sets the scale exponent.
171
     */
172
    void setScale(int s) { checkScale(s); scale = s; normalize(); };
173

    
174
    /**
175
     * Returns the mantissa as if scale was the given value;
176
     */
177
    int64 getMantissaForScale(int scale) const;
178

    
179
    /**
180
     * Converts the given string to big decimal. Throws an error if
181
     * there is an error during conversion.
182
     */
183
    static const BigDecimal parse(const char *s);
184

    
185
    /**
186
     * Converts a prefix of the given string to big decimal, up to the
187
     * first character that cannot occur in big decimal strings:
188
     * not (digit or letter or "." or "+" or "-" or whitespace).
189
     */
190
    static const BigDecimal parse(const char *s, const char *&endp);
191

    
192
    /**
193
     * Utility function to convert a big decimal into a string
194
     * buffer. scaleexp must be in the -18..0 range, and the buffer must be
195
     * at least 64 bytes long. A pointer to the result string will be
196
     * returned. A pointer to the terminating '\0' will be returned in endp.
197
     *
198
     * ATTENTION: For performance reasons, the returned pointer will point
199
     * *somewhere* into the buffer, but NOT necessarily at the beginning.
200
     */
201
    static char *ttoa(char *buf, const BigDecimal &x, char *&endp);
202
    //@}
203
};
204

    
205
inline bool haveSameSign(int64 a, int64 b) { return (a^b) >= 0; }
206

    
207
inline const BigDecimal operator*(const BigDecimal& x, double d)
208
{
209
    return BigDecimal(x.dbl()*d);
210
}
211

    
212
inline const BigDecimal operator*(double d, const BigDecimal& x)
213
{
214
    return BigDecimal(d*x.dbl());
215
}
216

    
217
inline const BigDecimal operator/(const BigDecimal& x, double d)
218
{
219
    return BigDecimal(x.dbl()/d);
220
}
221

    
222
inline const BigDecimal operator/(const BigDecimal& x, const BigDecimal& y)
223
{
224
    return BigDecimal(x.dbl()/y.dbl());
225
}
226

    
227
inline std::ostream& operator<<(std::ostream& os, const BigDecimal& x)
228
{
229
    char buf[64]; char *endp;
230
    return os << BigDecimal::ttoa(buf, x, endp);
231
}
232

    
233
NAMESPACE_END
234

    
235
/**
236
 * BigDecimal version of floor(double) from math.h.
237
 */
238
inline const OPP::BigDecimal floor(const OPP::BigDecimal& x)
239
{
240
    return OPP::BigDecimal(floor(x.dbl()));
241
}
242

    
243
/**
244
 * BigDecimal version of ceil(double) from math.h.
245
 */
246
inline const OPP::BigDecimal ceil(const OPP::BigDecimal& x)
247
{
248
    return OPP::BigDecimal(ceil(x.dbl()));
249
}
250

    
251
/**
252
 * BigDecimal version of fabs(double) from math.h.
253
 */
254
inline const OPP::BigDecimal fabs(const OPP::BigDecimal& x)
255
{
256
    return x.getIntValue()<0 ? OPP::BigDecimal(x).setIntValue(-x.getIntValue()) : x;
257
}
258

    
259
/**
260
 * BigDecimal version of fmod(double,double) from math.h.
261
 */
262
inline const OPP::BigDecimal fmod(const OPP::BigDecimal& x, const OPP::BigDecimal& y)
263
{
264
    return OPP::BigDecimal(fmod(x.dbl(), y.dbl()));
265
}
266

    
267
/**
268
 * Returns the greater of the two arguments.
269
 */
270
inline const OPP::BigDecimal max(const OPP::BigDecimal& x, const OPP::BigDecimal& y)
271
{
272
    return x > y ? x : y;
273
}
274

    
275
/**
276
 * Returns the smaller of the two arguments.
277
 */
278
inline const OPP::BigDecimal min(const OPP::BigDecimal& x, const OPP::BigDecimal& y)
279
{
280
    return x < y ? x : y;
281
}
282

    
283
#endif
284

    
285