-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathIcd.h
460 lines (390 loc) · 11.7 KB
/
Icd.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
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
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
// ICD = INTEGER CODED DECIMAL
// A class to work with large decimal numbers
// in exact precisions in decimals as opposed to
// the built in data types (float, double) that
// do a binary approximation
//
#pragma once
#include <sqltypes.h>
#include <ostream>
using std::ostream;
static const long icdBase = 100000000L; // Base per element of m_data
static const short icdDigits = 8; // Digits per element of m_data
static const short icdLength = 10; // Total storage length in m_data
static const short icdPointPosition = 5; // Implied position of the decimal '.'
static const short icdPrecision = 38; // Maximum allowed precision in ODBC
// icd now has the form of: 0 0 0 0 0. 0 0 0 0 0
// Example: 2.5 is stored: 0 0 0 0 5. 2 0 0 0 0
// Handy typedefs of used basic data types
using uchar = unsigned char;
using ushort = unsigned short;
using ulong = unsigned long;
// All internal registers are in 64 bits
#define int64 __int64
class icd
{
public:
// Default constructor.
icd();
// ICD of a long
icd(const long value, const long remainder = 0);
// ICD of an unsigned long
icd(const ulong value, const ulong remainder = 0);
// ICD of a 64bits int
icd(const int64 value,const int64 remainder = 0);
// ICD of a 64bits int
icd(const UINT64 value, const UINT64 remainder = 0);
// Copy constructor.
icd(const icd& icd);
// ICD of a double
icd(const double value);
// Assignment-constructor from a string.
icd(const CString& p_string);
// ICD of a signed byte/char
icd(const char value);
// ICD of a signed byte/char
icd(const uchar value);
// ICD of a short
icd(const short value);
// ICD of an unsigned short
icd(const ushort value);
// Assignment constructor from ODBC
icd(SQL_NUMERIC_STRUCT* p_numeric);
// Destructor of the icd
~icd();
// CONSTANTS
static icd PI(); // Ratio between radius and circumference of a circle
static icd LN2(); // Natural logarithm of 2
static icd LN10(); // Natural logarithm of 10
// OPERATORS
const icd& operator=( const icd& p_icd);
const icd& operator=( const long value);
const icd& operator=( const double value);
const icd& operator=( const CString& str);
const icd& operator+=(const icd& p_icd);
const icd& operator-=(const icd& p_icd);
const icd& operator*=(const icd& p_icd);
const icd& operator/=(const icd& p_icd);
const icd& operator%=(const icd& p_icd);
// Prefix unary minus (negation)
const icd operator-() const;
// Postfix increment
const icd operator++(int);
// Prefix increment
icd& operator++();
// Postfix decrement
const icd operator--(int);
// Prefix decrement
icd& operator--();
// Comparison operators
const bool operator==(const icd& p_icd) const;
const bool operator!=(const icd& p_icd) const;
const bool operator< (const icd& p_icd) const;
const bool operator> (const icd& p_icd) const;
const bool operator<=(const icd& p_icd) const;
const bool operator>=(const icd& p_icd) const;
// standard output operator
friend ostream& operator<<(ostream& os, const icd& p_icd);
// MATHEMATICAL FUNCTIONS
// Floor function
icd Floor() const;
// Ceiling function
icd Ceil() const;
// Square root
icd SquareRoot() const;
// To the power of
icd Power(const icd& macht) const;
// Absolute value (ABS)
icd AbsoluteValue() const;
// Reciproke / Inverse = 1/x
icd Reciproke() const;
// Natural logarithm
icd Log() const;
// Exponent e till the power of this number
icd Exp() const;
// Log with base 10
icd Log10() const;
// Ten Power
icd TenPower(int n);
// TRIGONOMETRICAL FUNCTIONS
// Sine of an angle
icd Sine() const;
// Cosine of an angle
icd Cosine() const;
// Tangent of an angle
icd Tangent() const;
// Arcsine (angle) of a Sine ratio
icd ArcSine() const;
// ArcCosine (angle) of a Cosine ratio
icd ArcCosine() const;
// Arctangent (angle) of a Tangent ratio
icd ArcTangent() const;
// Angle from 2 points
icd ArcTangent2Points(icd p_x) const;
// REQUEST AS SOMETHING DIFFERENT
// Part before the decimal point (floor if greater than 0)
icd ValueBeforePoint() const;
// Part behind the decimal point
icd ValueBehindPoint() const;
// Get as a converted double
double AsDouble() const;
// Get as a short
short AsShort() const;
// Get as an unsigned short
ushort AsUShort() const;
// Get as a converted long
long AsLong() const;
// Get as an unsigned long
ulong AsULong() const;
// Get as a converted int-64
int64 AsInt64() const;
// Get as a unsigned int64
unsigned int64 AsUInt64() const;
// Get as mathematical string
CString AsString() const;
// Get as a SQL string
CString AsSQLString(bool p_strip = false) const;
// Get as a display string (for UI purposes)
CString AsDisplayString() const;
// Get as an ODBC SQL NUMERIC
void AsNumeric(SQL_NUMERIC_STRUCT* p_numeric) const;
// CHANGE PRECISION
// Change length and precision
void SetLengthAndPrecision(int length = 80, int precision = 40);
// Rounding on decimals and precision
long RoundDecimals(long decimal,int precsion);
// Correct mathematical rounding
void Rounding(int p_length /*= 80*/,int p_precision /*= 40*/);
// GETTER FUNCTIES
// Is the value of the icd exactly 0.0 ?
// With no distinction between +0 en -0
bool IsNull() const;
// Getting the sign as 0 (= 0.0), 1 (greater than 0) or -1 (smaller than 0)
int GetSign() const;
// Change the sign
void Negate();
// Total length (before and after the decimal .)
int Length();
// Precision after the decimal '.'
int Precision();
// Get the max size of an icd
static int GetMaxSize(int precision = 0);
// See if the icd fits into a long
bool FitsInLong() const;
bool FitsInULong() const;
// See if the icd fits into a int64
bool FitsInInt64() const;
bool FitsInUInt64() const;
// See if the icd has decimals after the '.' (no scalar)
bool HasDecimals() const;
// Getting the exponent of the icd
int Exponent() const;
// Getting the 10th power mantissa of the icd
icd Mantissa() const;
// Nearly zero or zero
bool IsNearZero();
// BASIC OPERATIONS.
// Has to be public for the operators
// Make ZERO
void Zero();
// Add operation
icd Add(const icd& p_icd) const;
// Subtraction operation
icd Sub(const icd& p_icd) const;
// Multiply operation
icd Mul(const icd& p_icd) const;
// Dividing operation
icd Div(const icd& p_icd) const;
// Modulo operation
icd Mod(const icd& p_icd) const;
private:
enum Sign { Positive, Negative };
enum OperatorKind { Adding, Subtracting };
// Our own abs(long) function
long long_abs(const long value) const;
// Our own long to the power 1,2,3.. function
long long_pow(long base,int operand) const;
// Our own log10 function
long long_log10(long value) const;
// Put a long in the icd
void SetValueLong (const long value,const long remainder);
void SetValueULong (const ulong value,const ulong remainder);
// Put a double in the icd
void SetValueDouble(const double value);
// Convert a string in the icd
void SetValueString(CString value);
// Put an int64 in the icd
void SetValueInt64 (const int64 value,const int64 remainder);
void SetValueUInt64(const UINT64 value,const UINT64 remainder);
// Put a SQL_NUMERIC_STRUCT from the ODBC driver in the icd
void SetValueNumeric(SQL_NUMERIC_STRUCT* p_numeric);
// To the 10th power
void CalculateEFactor(int factor);
// Internal reformatting of m_data so that members are < icdBase
void Reformat();
// Empty icd to be 0.0
void MakeEmpty();
// Internal multiply icd with one icd m_data member
const icd Multi(const long multiplier) const;
// Corner case where the round brings icd outside the precision
const bool IsCornerCase() const;
// Getting the sign and alignments for a basic operation
static void PositionArguments(icd& arg1,
icd& arg2,
Sign& signResult,
OperatorKind& kindOfOperator);
// Adds two icd's without taking the sign into account
static const icd AddPositive(const icd& arg1, const icd& arg2);
// Subtracts two icd's without taking the sign into account
static const icd SubtractPositive(const icd& arg1, const icd& arg2);
// Multiplies two icd's without taking the sign into account
static const icd MultiplyPositive(const icd& arg1, const icd& arg2);
// Divide an icd by another icd without taking the sign into account
static const icd DividePositive(const icd& arg1, const icd& arg2);
// Getting the sign of a multiplication or a division
static const Sign CalculateSign(const icd& arg1, const icd& arg2);
// Bringing sides to the same exponent
static const icd BringTogether(const icd& arg1, const long verschil);
// Divide the mantissa by 10 (shift operation)
void Div10();
// Multiply the mantissa by 10 (shift operation)
void Mult10();
// String <-> Long conversions
CString LongToString(long p_number) const;
long StringToLong(CString& p_string) const;
// Breaking criterion for internal iterations
icd& Epsilon(long p_fraction) const;
//
// Data members: Storing the number
//
Sign m_sign;
int m_length;
int m_precision;
unsigned long m_data[icdLength];
};
// Getters
inline int
icd::Length()
{
return m_length;
}
inline int
icd::Precision()
{
return m_precision;
}
inline int
icd::GetMaxSize(int precisie)
{
return (icdLength * icdDigits);
}
// Overloaded basic operators
inline icd operator + (const icd& lhs, const icd& rhs)
{
return lhs.Add(rhs);
}
inline icd operator - (const icd& lhs, const icd& rhs)
{
return lhs.Sub(rhs);
}
inline icd operator * (const icd& lhs, const icd& rhs)
{
return lhs.Mul(rhs);
}
inline icd operator / (const icd& lhs, const icd& rhs)
{
return lhs.Div(rhs);
}
inline icd operator % (const icd& lhs, const icd& rhs)
{
return lhs.Mod(rhs);
}
// Overloaded math precision floating point functions equivalent with the std C functions
// Overloaded to work with the ICD number class, always yielding a icd number.
inline icd modf(icd p_number, icd* p_intpart)
{
*p_intpart = p_number.ValueBeforePoint();
return p_number.ValueBehindPoint();
}
inline icd fmod(icd p_number,icd p_divisor)
{
return p_number.Mod(p_divisor);
}
inline icd floor(icd p_number)
{
return p_number.Floor();
}
inline icd ceil(icd p_number)
{
return p_number.Ceil();
}
inline icd fabs(icd p_number)
{
return p_number.AbsoluteValue();
}
inline icd sqrt(icd p_number)
{
return p_number.SquareRoot();
}
inline icd log10(icd p_number)
{
return p_number.Log10();
}
inline icd log(icd p_number)
{
return p_number.Log();
}
inline icd exp(icd p_number)
{
return p_number.Exp();
}
inline icd pow(icd p_number,icd p_power)
{
return p_number.Power(p_power);
}
inline icd frexp(icd p_number,int* p_exponent)
{
*p_exponent = p_number.Exponent();
return p_number.Mantissa();
}
inline icd ldexp(icd p_number,int p_power)
{
if(p_power == 0)
{
return p_number;
}
if(p_power > 0 && p_power <= 31)
{
return p_number * icd((long) (1 << p_power));
}
return p_number * pow(icd(2L),icd((long)p_power));
}
// Overloaded trigonometric functions on a icd number
inline icd atan (icd p_number)
{
return p_number.ArcTangent();
}
inline icd atan2(icd p_y,icd p_x)
{
return p_y.ArcTangent2Points(p_x);
}
inline icd asin(icd p_number)
{
return p_number.ArcSine();
}
inline icd acos(icd p_number)
{
return p_number.ArcCosine();
}
inline icd sin(icd p_number)
{
return p_number.Sine();
}
inline icd cos(icd p_number)
{
return p_number.Cosine();
}
inline icd tan(icd p_number)
{
return p_number.Tangent();
}