1
namespace VQDR.Common {
2
* The contects of this file is in the Public Domain.
4
* Created by Gustav Hartivgsson.
4
* Fast Numbers are a decimal representanion of numbers in the folm of
5
* a normal integer value. All internal nummbers are multiples of 1000, so the
6
* there is room for two three decimal ponts.
8
* Math done on these numbers are done using standard integer operations, and
9
* not floating point math.
11
* Fast Numbers are a decimal representation of numbers in the form of
12
* a normal integer value. All internal numbers are multiples of 1000, so the
13
* there is room for two three decimal points.
15
* Maths done on these numbers are done using standard integer operations, and
16
* not floating point maths.
18
* The decimal part of the FastNumber has a maximum of 3 decimals.
20
* How the value is divided internally is as follows:
22
* (base 10) [0 0 0 0 0 .... 0 | 0 0 0 ]
23
* [non-decial part | decimal]
12
public const long MUL_FACTOR = 1000;
14
public long raw_number { public get; private set; }
17
get {return raw_number / MUL_FACTOR;}
18
set {raw_number = number * MUL_FACTOR;}
21
public FastNumber (long val = 0) {
28
public errordomain MathError {
32
public struct FastNumber {
35
/** Precision used to output values */
36
public const int32 PRECISION_DIGITS = 2;
38
/** Precision factor used to evaluate output */
39
public const int32 PRECISION_FACTOR = 100;
41
public const int32 MUL_FACTOR = PRECISION_FACTOR * 10;
43
public int64 raw_number;
45
public int64 leading_zeros;
48
* I'm not happy using getters/setters in this struct...
49
* But I tink it'll have to do for simplicity.
52
public get {return (this.raw_number / MUL_FACTOR);}
54
this.raw_number = (MUL_FACTOR * value);
59
* Initialises a FastNumber.
61
* Note: Due to implementation details, you can't pass a decimal part that
62
* is less than .1, as we are normalising decimal values to the
65
* @param number The number that are to be set as the none-decimal part of
66
* the number. Defaults to 0.
68
* @param decimal The decimal part of the number. Defaults to 0.
71
public FastNumber (int64 number = 0) {
73
this.raw_number = (number * MUL_FACTOR);
80
* Do a deep copy of a FastNumber.
25
83
public FastNumber.copy (FastNumber other) {
26
84
this.raw_number = other.raw_number;
88
* Initialises a FastNumber from a string.
90
* Can be a decimal representation.
29
93
public FastNumber.from_string (string str) {
30
this.raw_number = parse_raw_number (str);
33
private static long parse_raw_number (string str) {
94
parse_raw_number (str);
97
* Initialises a FastNumber with the internal representation of that number.
100
public FastNumber.raw (int64 raw) {
101
this.raw_number = raw;
105
public FastNumber.from_float (double float_number) {
106
// XXX Do we need a faster way of doing this?
107
parse_raw_number (float_number.to_string ());
111
* Add this to an other FastNumber.
114
* var f1 = FastNumber (3); // f1 = 3
115
* var f2 = FastNumber (2); // f2 = 2
116
* var f3 = f1.add (f2); // f3 = 5
119
* @return a newly initialised FastNumber.
121
* @param other The other fast number you want to add to this value.
124
public FastNumber add (FastNumber? other) {
126
return FastNumber.copy (this);
129
var v = FastNumber ();
130
v.raw_number = (this.raw_number + other.raw_number);
135
* Add this to an other FastNumber.
138
* var f1 = FastNumber (3); // f1 = 3
139
* var f2 = FastNumber (2); // f2 = 2
140
* var f3 = f1.subtract (f2); // f3 = 1
143
* @return a newly initialised FastNumber.
145
* @param other The other fast number you want to subtract from this
149
public FastNumber subtract (FastNumber? other) {
151
return FastNumber.copy (this);
154
var v = FastNumber ();
155
v.raw_number = (this.raw_number - other.raw_number);
160
* Multiply this FastNumber with another FastNumber.
163
* var f1 = FastNumber (3); // f1 = 3
164
* var f2 = FastNumber (2); // f2 = 2
165
* var f3 = f1.multiply (f2); // f3 = 6
168
* @return a newly initialised FastNumber.
170
* @param other The value you want to multiply this value with.
173
public FastNumber multiply (FastNumber? other) {
174
if (other == null || other.raw_number == 0 || this.raw_number == 0) {
175
return FastNumber ();
178
var ret = FastNumber ();
179
ret.raw_number = ((this.raw_number * other.raw_number) / MUL_FACTOR);
184
* Divide this FastNumbers with another FastNumber.
187
* var f1 = FastNumber (6); // f1 = 6
188
* var f2 = FastNumber (2); // f2 = 2
189
* var f3 = f1.multiply (f2); // f3 = 3
192
* @return a newly initialised FastNumber.
194
* @param other The value you want to multiply this value with.
197
public FastNumber divide (FastNumber other) throws MathError {
198
if (other.raw_number == 0) {
199
throw new MathError.DIVIDE_BY_ZERO ("trying to divide by zero");
201
var ret = FastNumber ();
202
ret.raw_number = ((this.raw_number * MUL_FACTOR) / other.raw_number);
207
public int64 compare (FastNumber other) {
208
return this.raw_number - other.raw_number;
212
* Round up this FastNumber and returns a new FastNumber.
214
* @return a rounded up FastNumber.
217
public FastNumber round_up () {
219
int64 decimal = raw_number % PRECISION_FACTOR;
221
ret = FastNumber.raw (raw_number + PRECISION_FACTOR - decimal);
223
ret = FastNumber.raw (raw_number - decimal);
229
* Round up this FastNumber and returns a new FastNumber.
231
* @return a rounded down FastNumber.
233
public FastNumber round_down () {
235
int64 decimal = raw_number % PRECISION_FACTOR;
237
// Is this ever reached?
238
ret = FastNumber.raw (raw_number - PRECISION_FACTOR - decimal);
240
ret = FastNumber.raw (raw_number - decimal);
246
* FastNumber to string.
250
* @param decimal whether to return the decimal portion of the number in
251
* the string. Default = false.
254
public string to_string (bool decimal = false) {
255
string ret_val = null;
257
ret_val = (this.raw_number / MUL_FACTOR).to_string ();
259
// Copy stuff so we don't accidentality stomp them.
260
int64 _raw_number = this.raw_number;
262
int64 _integer_part = (_raw_number / MUL_FACTOR);
263
int64 _decimal_part = (_raw_number - (_integer_part * MUL_FACTOR));
265
var strbldr = new GLib.StringBuilder ();
267
// normalise the decimal part.
268
// (XXX This is rather expensive, is there a better way of doing this?).
269
if (_decimal_part != 0) {
270
while ((_decimal_part % 10) == 0) {
271
_decimal_part = _decimal_part / 10;
275
strbldr.append (_integer_part.to_string ())
279
for ( var i = this.leading_zeros ; i > 0 ; i--) {
280
strbldr.append_c ('0');
283
strbldr.append (_decimal_part.to_string ());
285
ret_val = strbldr.str;
291
public double to_float () {
292
// XXX This probobly needs to something faster?
293
return double.parse (this.to_string (true));
297
public int64 to_int () {
298
return (this.raw_number / MUL_FACTOR);
302
* Check if two FastNumbers are equal.
304
* @return true if this is equal to the other.
305
* @return false if this is not equal to the other.
307
public bool equals (FastNumber other) {
308
return (this.raw_number == other.raw_number);
313
public static extern int64 static_compare (FastNumber a, FastNumber b);
316
private void parse_raw_number (string str) {
317
//debug (@"(parse_raw_number) str: $str");
35
319
int i_of_dot = str.index_of_char ('.');
36
320
if (i_of_dot >= 0) {
38
321
// Get the decimal number from the string, if such a thing exists.
39
322
if ((str.length - 1 > i_of_dot)) {
40
ret_val = long.parse ((str + "000").substring (i_of_dot + 1));
323
var intr_str = (str + "000").substring (i_of_dot + 1);
324
// count leading zeros.
325
// (Must be type long, as that is what string.substring () expects.)
327
for (i = 0; intr_str.@get (i) == '0'; i++){}
328
this.leading_zeros = i;
329
// remove leading zeros
330
intr_str = intr_str.substring (i);
331
//debug (@"(parse_raw_number) Intermediate string: $intr_str");
332
ret_val = int64.parse (intr_str);
335
// debug (@"(parse_raw_number) i_of_dot: $i_of_dot, ret_val (decimal): $ret_val\n");
43
337
// Normalise the digits.
44
338
while (ret_val > MUL_FACTOR) {
45
339
ret_val = ret_val / 10;
49
ret_val = ret_val + (long.parse ("0" + str.substring (0, i_of_dot))
340
// debug (@"(parse_raw_number) retval (loop): $ret_val");
343
for (var i = leading_zeros; i > 0; i--) {
344
ret_val = ret_val / 10;
345
// debug (@"(parse_raw_number) retval (loop2): $ret_val");
348
// debug (@"ret_val (normalised): $ret_val\n");
350
// get integer number
351
ret_val = ret_val + (int64.parse (str.substring (0, i_of_dot))
52
ret_val = long.parse (str) * MUL_FACTOR;
58
public FastNumber add (FastNumber? other) {
60
return new FastNumber.copy (this);
63
var v = new FastNumber (this.raw_number + other.raw_number);
68
public FastNumber subtract (FastNumber? other) {
70
return new FastNumber.copy (this);
73
var v = new FastNumber (this.raw_number - other.raw_number);
78
public FastNumber multiply (FastNumber? other) {
79
if (other == null || other.raw_value == 0) {
80
return new FastNumber ();
83
return new FastNumber ((this.raw_number * other.raw_number) / MUL_FACTOR);
86
public FastNumber divide (FastNumber? other) throws MathError {
87
if (other.raw_number == 0) {
88
throw new MathError.DIVIDE_BY_ZERO
89
("FantNumber - trying to divide by zero");
92
return new FastNumber ((this.raw_number * MUL_FACTOR) / other.raw_number);
355
ret_val = (int64.parse (str) * MUL_FACTOR);
357
//debug (@"(parse_raw_number) ret_val (finished): $ret_val\n");
358
this.raw_number = ret_val;