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
|
/*
* The contects of this file is in the Public Domain.
*
* Created by Gustav Hartivgsson.
*/
using GLib;
namespace VQDR.Common {
/**
* Fast Numbers are a decimal representanion of numbers in the folm of
* a normal integer value. All internal nummbers are multiples of 1000, so the
* there is room for two three decimal ponts.
*
* Math done on these numbers are done using standard integer operations, and
* not floating point math.
*
* The decimal part of the FastNumber has a maximum of 3 decimals.
*
* How the value is devided internally is as follows:
* {{{
(base 10) [0 0 0 0 0 .... 0 | 0 0 0 ]
[non-decial part | decimal]
* }}}
*/
public struct FastNumber {
/** Precision used to output values */
public const int PRECISION_DIGITS = 2;
/** Precision factor used to evaluate output */
public const int PRECISION_FACTOR = 100;
public const int MUL_FACTOR = PRECISION_FACTOR * 10;
public long raw_number;
public long number {
public get {return (this.raw_number / MUL_FACTOR);}
public set {this.raw_number = (MUL_FACTOR * value);}
}
public long decimal {
public get {return mask_and_normalize_decimal (raw_number);}
public set {set_decimal_of_number (ref raw_number, value);}
}
public double float_rep {
public get {
long dec = this.decimal;
long nbr = this.number;
debug (@"(float_ret_get) Float str: $nbr.$dec");
return double.parse (@"$nbr.$dec");
} public set {
debug (@"(float_ret_set) set float: $value");
this.raw_number = parse_raw_number (value.to_string ());
}
}
/**
* Initialises a FastNumber.
*
* @param number The number that are to be set as the none-decimal part of
* the number. Defaults to 0.
*
* @param decimal The decimal part of the number. Defaults to 0.
*/
public FastNumber (long number = 0, int decimal = 0) {
this.number = number;
this.decimal = decimal;
}
/**
* Do a deep copy of a FastNumber.
*/
public FastNumber.copy (FastNumber other) {
this.raw_number = other.raw_number;
}
/**
* Initialises a FastNumber from a string.
*
* Can be a decimal representation.
*/
public FastNumber.from_string (string str) {
this.raw_number = parse_raw_number (str);
}
/**
* Initialises a FastNumber from a double floating point value.
*
* Due to how floatinng point numbers works this may not be the exact value
* you expect it to be.
*/
public FastNumber.from_float (double f) {
this.raw_number = parse_raw_number (f.to_string ());
}
/**
* Initialises a FastNumber with the internal representation of that number.
*/
public FastNumber.raw (long raw) {
this.raw_number = raw;
}
/**
* Sets the value of this FastNumber from a string,
*/
public void set_from_string (string str) {
this.raw_number = parse_raw_number (str);
}
/**
* Add this to an other FastNumber.
*
* {{{
* var f1 = FastNumber (3); // f1 = 3
* var f2 = FastNumber (2); // f2 = 2
* var f3 = f1.add (f2); // f3 = 5
* }}}
*
* @return a newly inisialised FastNumber.
*
* @param other The other fast number you want to add to this value.
*/
public FastNumber add (FastNumber? other) {
if (other == null) {
return FastNumber.copy (this);
}
var v = FastNumber ();
v.raw_number = (this.raw_number + other.raw_number);
return v;
}
/**
* Add this to an other FastNumber.
*
* {{{
* var f1 = FastNumber (3); // f1 = 3
* var f2 = FastNumber (2); // f2 = 2
* var f3 = f1.subtract (f2); // f3 = 1
* }}}
*
* @return a newly inisialised FastNumber.
*
* @param other The other fast number you want to subtract from this
* FastNumber.
*/
public FastNumber subtract (FastNumber? other) {
if (other == null) {
return FastNumber.copy (this);
}
var v = FastNumber ();
v.raw_number = (this.raw_number - other.raw_number);
return v;
}
/**
* Multiply this FastNumber with another FastNumber.
*
* {{{
* var f1 = FastNumber (3); // f1 = 3
* var f2 = FastNumber (2); // f2 = 2
* var f3 = f1.multiply (f2); // f3 = 6
* }}}
*
* @return a newly initalised FastNumber.
*
* @param other The value you want to multiply this value with.
*/
public FastNumber multiply (FastNumber? other) {
if (other == null || other.raw_number == 0 || this.raw_number == 0) {
return FastNumber ();
}
var ret = FastNumber ();
ret.raw_number = ((this.raw_number * other.raw_number) / MUL_FACTOR);
return ret;
}
/**
* Divide this FastNumbers with anothr FastNumber.
*
* {{{
* var f1 = FastNumber (6); // f1 = 6
* var f2 = FastNumber (2); // f2 = 2
* var f3 = f1.multiply (f2); // f3 = 3
* }}}
*
* @return a newly initalised FastNumber.
*
* @param other The value you want to multiply this value with.
*/
public FastNumber divide (FastNumber other) throws MathError {
if (other.raw_number == 0) {
throw new MathError.DIVIDE_BY_ZERO ("trying to divide by zero");
}
var ret = FastNumber ();
ret.raw_number = ((this.raw_number * MUL_FACTOR) / other.raw_number);
return ret;
}
[CCode (cname = "vqdr_common_fast_number_compare")]
public long compare (FastNumber other) {
return this.raw_number - other.raw_number;
}
/**
* Round up this FastNumber and retuns it.
*
* @return a rounded up FastNumber.
*/
public FastNumber round_up () {
FastNumber ret;
long decimal = raw_number % PRECISION_FACTOR;
if (decimal > 0) {
ret = FastNumber.raw (raw_number + PRECISION_FACTOR - decimal);
} else {
ret = FastNumber.raw (raw_number - decimal);
}
return ret;
}
/**
* Round up this FastNumber and retuns it.
*
* @return a rounded down FastNumber.
*/
public FastNumber round_down () {
FastNumber ret;
long decimal = raw_number % PRECISION_FACTOR;
if (decimal < 0) {
// Is this ever reached?
ret = FastNumber.raw (raw_number - PRECISION_FACTOR - decimal);
} else {
ret = FastNumber.raw (raw_number - decimal);
}
return ret;
}
/**
* FastNumber to string.
*
* @return a string
*
* @param decimal whether to return the decimal portion of the number in
* the string. Default = false.
*/
public string to_string (bool decimal = false) {
if (decimal) {
return @"$number.$decimal";
} else {
return number.to_string ();
}
}
/**
* Check if two FastNumbers are equal.
*
* @return true if this is equal to the other.
* @return false if this is not equal to the other.
*/
public bool equals (FastNumber other) {
return (this.raw_number == other.raw_number);
}
// ***** STATIC FUNCTIONS ****//
public static long parse_raw_number (string str) {
long ret_val = 0;
int i_of_dot = str.index_of_char ('.');
if (i_of_dot >= 0) {
debug (@"str: $str");
// Get the decimal number from the string, if such a thing exists.
if ((str.length - 1 > i_of_dot)) {
ret_val = long.parse ((str + "000").substring (i_of_dot + 1));
}
debug (@"(parse_raw_number) i_of_dot: $i_of_dot, ret_val (decimal): $ret_val\n");
// Normalise the digits.
while (ret_val > MUL_FACTOR) {
ret_val = ret_val / 10;
debug (@"(parse_raw_number) retval (loop): $ret_val");
}
debug (@"ret_val (normalised): $ret_val\n");
// get intiger number
ret_val = ret_val + (long.parse (str.substring (0, i_of_dot))
* MUL_FACTOR);
debug (@"(parse_raw_number) ret_val (finised): $ret_val\n");
} else {
ret_val = long.parse (str) * MUL_FACTOR;
}
return ret_val;
}
public static long mask_and_normalize_decimal (long number) {
debug (@"(mask_and_normalize_decimal) number: $number");
long mask = number / MUL_FACTOR;
debug (@"(mask_and_normalize_decimal) mask(1): $mask");
mask = mask * MUL_FACTOR;
debug (@"(mask_and_normalize_decimal) mask(2): $mask");
long ret = number - mask;
// normalise
// This is a rathor expensive operation.
if (ret != 0) {
while ((ret % 10) == 0) {
ret = ret / 10;
}
}
debug (@"(mask_and_normalize_decimal) ret: $ret");
return ret;
}
public static void set_decimal_of_number (ref long number, long decimal) {
debug (@"(set_decimal_of_number) number(0): $number, decimal(0): $decimal");
long masked = number / MUL_FACTOR;
debug (@"(set_decimal_of_number) masked(1): $masked");
masked = masked * MUL_FACTOR;
debug (@"(set_decimal_of_number) masked(2): $masked");
// Normalise didgits
if (decimal != 0) {
while (decimal < PRECISION_FACTOR) {
decimal = decimal * 10;
debug (@"(set_decimal_of_number) loop, decimal: $decimal");
}
}
number = masked + decimal;
debug (@"(set_decimal_of_number) number(1): $number");
}
[CCode (cname = "vqdr_common_fast_number_compare")]
public static extern long static_compare (FastNumber a, FastNumber b);
}
}
|