-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathRealEstimate.h
266 lines (210 loc) · 9.33 KB
/
RealEstimate.h
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
/*
RealEstimate.h
Error math and value+error container.
Classes:
Estimate - combines a LongFloat with its ErrorEstimate.
the error is absolute: |value - real| < error.
ErrorEstimate - a simple evaluation of error as 32-bit
mantissa and 32-bit exponent. Operations give results
that are always greater than or equal to the actual
result. Note the exponent in a ErrorEstimate is in
bits, not in words as in a LongFloat, and the mantissa
always has 1 in its most significant bit.
*/
#ifndef FILE_REAL_ESTIMATE_H
#define FILE_REAL_ESTIMATE_H
#include <stdlib.h>
#include <limits.h>
#include <exception>
#include "defs.h"
#include "LongFloat.h"
#include "ErrorEstimate.h"
#include "RealExceptions.h"
namespace RealLib {
// class Estimate's definitions start here
class Estimate;
// operations
Estimate operator - (const Estimate &arg);
Estimate recip(const Estimate &arg);
Estimate operator + (const Estimate &lhs, const Estimate &rhs);
Estimate operator - (const Estimate &lhs, const Estimate &rhs);
Estimate operator * (const Estimate &lhs, const Estimate &rhs);
Estimate operator / (const Estimate &lhs, const Estimate &rhs);
// fast multiplication
Estimate operator * (const Estimate &lhs, i32 rhs);
// and division
Estimate operator / (const Estimate &lhs, i32 rhs);
static inline
std::ostream& operator <<(std::ostream &os, const Estimate &e);
class Estimate {
private:
LongFloat m_Value;
ErrorEstimate m_Error; // error, |m_Value - real| < m_Error
Estimate(const LongFloat &val, const ErrorEstimate &err = ErrorEstimate());
void CorrectZero(); // 0 should not be used in calculations. Substitute (0, e) with (e, 2e)
// and (0, 0) with (2^-MAXINT, 2^-MAXINT * 2)
public:
Estimate(double v = 0.0);
// Estimate(const Estimate &rhs)
// : m_Value(rhs.m_Value), m_Error(rhs.m_Error) {}
Estimate(const char *val);
// error functions
Estimate GetError() const;
Estimate& SetError(const Estimate &err);
Estimate& AddError(const Estimate &err);
// a lower bound on the correct binary digits
// uses the exponents of the value and error to calculate it quickly
i32 GetRelativeError() const;
/*
Estimate& AddRoundingError()
{ m_Error = m_Error + RoundingError(m_Value, m_Value.AdditionRoundingError());
return *this; }
Estimate TheRoundingError() const // rounding error is assumed to be no more than
// one in the least significant bit of the mantissa
// Note! Newton-Raphson reciprocal is incorrect in the
// least significant word (handled by recip())
{ return RoundingError(m_Value); }
*/
// get a rough estimate of the precision
// used to determine the length of the approximations to functions
u32 GetPrecision() const
{ return m_Value.GetPrecision(); }
Estimate& SetPrecision(u32 prec)
{ m_Value.SetPrecision(prec);
return *this; }
// truncation
// used to make sure only arguments within the domain of the function
// are processed for the closed ends of the domain.
// To this end, truncates the approximation interval so that
// the indicated real numbers are thrown out. If nothing remains,
// raise a DomainException(origin).
// warning: an error in the approximation of the bound will be added to the
// error in the end result, i.e. if (center 0, error 3) is truncated below (c 1, e 0.5), the
// result will be (c 2, e 1.5) (i.e. the interval [0.5, 3.5]).
// To avoid problems, use double arguments
// removes the part of the approximation interval that is negative
Estimate TruncateNegative(const char *origin = "Truncate") const;
// removes the part of the approximation that is below a certain lower bound
Estimate TruncateBelow(const Estimate &l, const char *origin = "Truncate") const
{ return (*this - l).TruncateNegative(origin) + l; }
// removes the part of the approximation that is above a certain upper bound
Estimate TruncateAbove(const Estimate &h, const char *origin = "Truncate") const
{ return h - (h - *this).TruncateNegative(origin); }
// removes the part of the approximation outside the specified interval
Estimate TruncateTo(double l, double h, const char *origin = "Truncate") const
{ return (h - ((h-l) - (*this - l).TruncateNegative(origin)).TruncateNegative(origin)); }
Estimate TruncateTo(const Estimate &l, const Estimate &h, const char *origin = "Truncate") const
{ return (h - ((h-l) - (*this - l).TruncateNegative(origin)).TruncateNegative(origin)); }
// comparisons
// these come in two flavors, strong (true if real is in relation to rhs)
bool IsPositive() const;
bool IsNegative() const;
bool IsNonZero() const;
// equality test is undecidable (i.e. would yield false for any precision)
// thus ==, <= and >= are not included
// also !(x<y) does not mean y<=x
bool operator < (const Estimate &rhs) const
{ return (*this - rhs).IsNegative(); }
bool operator > (const Estimate &rhs) const
{ return (*this - rhs).IsPositive(); }
bool operator != (const Estimate &rhs) const
{ return (*this - rhs).IsNonZero(); }
// and weak (true if m_Value is in relation to rhs)
// should only be used if the transformation being aplied
// would not differentiate on the two cases, e.g. to choose
// whether to evaluate sin(x) and sin(pi - x)
bool weak_IsPositive() const;
bool weak_IsNegative() const;
bool weak_IsNonZero() const
{ return true; }
// an Estimate cannot be weakly zero -- see the remark for CorrectZero()
bool weak_lt(const Estimate &rhs) const;
bool weak_eq(const Estimate &rhs) const;
bool weak_gt(const Estimate &rhs) const
{ return rhs.weak_lt(*this); }
bool weak_le(const Estimate &rhs) const
{ return !weak_gt(rhs); }
bool weak_ne(const Estimate &rhs) const
{ return !weak_eq(rhs); }
bool weak_ge(const Estimate &rhs) const
{ return !weak_lt(rhs); }
// among the weak operations is also rounding
// the returned Estimate is assumed exact
// only to be used on periodic functions!
Estimate weak_round() const;
// weak normalize, i.e. return an exponent such that
// a >> a.weak_normalize()
// is in the range [0.5, 1).
i32 weak_normalize() const
{ return m_Value.normalize(); }
// weak conversion
double weak_AsDouble() const
{ return m_Value.AsDouble(); }
// output
char *weak_AsDecimal(char *buffer, u32 buflen) const
{ return m_Value.AsDecimal(buffer, buflen); }
Estimate weak_Center()
{ return Estimate(m_Value, ErrorEstimate()); }
/*
// exponent and mantissa operations
// needed to get initial approximations via double
double weak_MantissaAsDouble() const
{ return m_Value.MantissaAsDouble(); }
i32 weak_Exponent() const
{ return m_Value.Exponent(); }
Estimate& AddToExponent(i32 exp)
{ m_Value.AddToExponent(exp);
return *this; }
char *weak_MantissaAsDecimal(char *buf, u32 buflen) const
{ return m_Value.MantissaAsDecimal(buf, buflen); }
*/
// operations
friend Estimate operator - (const Estimate &arg);
friend Estimate recip(const Estimate &arg);
friend Estimate operator + (const Estimate &lhs, const Estimate &rhs);
friend Estimate operator - (const Estimate &lhs, const Estimate &rhs);
friend Estimate operator * (const Estimate &lhs, const Estimate &rhs);
friend Estimate operator / (const Estimate &lhs, const Estimate &rhs);
// fast multiplication
friend Estimate operator * (const Estimate &lhs, i32 rhs);
// and division
friend Estimate operator / (const Estimate &lhs, i32 rhs);
// binary shift
Estimate operator << (i32 howmuch) const;
Estimate operator >> (i32 howmuch) const
{ return *this << -howmuch; }
Estimate& operator += (const Estimate &rhs)
{ return *this = *this + rhs; }
Estimate& operator -= (const Estimate &rhs)
{ return *this = *this - rhs; }
Estimate& operator *= (const Estimate &rhs)
{ return *this = *this * rhs; }
Estimate& operator /= (const Estimate &rhs)
{ return *this = *this / rhs; }
Estimate& operator >>= (i32 rhs)
{ return *this = *this >> rhs; }
Estimate& operator <<= (i32 rhs)
{ return *this = *this << rhs; }
Estimate& operator *= (i32 rhs)
{ return *this = *this * rhs; }
Estimate& operator /= (i32 rhs)
{ return *this = *this / rhs; }
// should probably be somewhere else
// conversion to string
// char *AsDecimal(char *buffer, u32 buflen);
friend
std::ostream& operator <<(std::ostream &os, const Estimate &e);
};
// shorthands
static inline
Estimate operator * (i32 lhs, const Estimate &rhs)
{ return rhs * lhs; }
static inline
Estimate operator / (i32 lhs, const Estimate &rhs)
{ return recip(rhs) * lhs; }
// C++-style output
static inline
std::ostream& operator <<(std::ostream &os, const Estimate &e)
{ return os << e.m_Value; }
} // namespace
#endif