1
namespace VQDR.Common {
2
* The contects of this file is in the Public Domain.
4
* Created by Gustav Hartivgsson.
7
[CCode (cname = "V", cprefix = "v_")]
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) {
27
[CCode (cname = "VFastNumber", cprefix = "v_fast_number_")]
28
public struct FastNumber {
30
/** Precision used to output values */
31
public const int32 PRECISION_DIGITS = 2;
33
/** Precision factor used to evaluate output */
34
public const int32 PRECISION_FACTOR = 100;
36
public const int32 MUL_FACTOR = PRECISION_FACTOR * 10;
38
public int64 raw_number;
40
public int64 leading_zeros;
43
* I'm not happy using getters/setters in this struct...
44
* But I tink it'll have to do for simplicity.
47
public get {return (this.raw_number / MUL_FACTOR);}
49
this.raw_number = (MUL_FACTOR * value);
54
* Initialises a FastNumber.
56
* Note: Due to implementation details, you can't pass a decimal part that
57
* is less than .1, as we are normalising decimal values to the
60
* @param number The number that are to be set as the none-decimal part of
61
* the number. Defaults to 0.
63
* @param decimal The decimal part of the number. Defaults to 0.
65
[CCode (cname = "v_fast_number_new")]
66
public FastNumber (int64 number = 0) {
68
this.raw_number = (number * MUL_FACTOR);
75
* Do a deep copy of a FastNumber.
77
[CCode (cname = "v_fast_number_copy")]
25
78
public FastNumber.copy (FastNumber other) {
26
79
this.raw_number = other.raw_number;
83
* Initialises a FastNumber from a string.
85
* Can be a decimal representation.
87
[CCode (cname = "v_fast_number_new_from_string")]
29
88
public FastNumber.from_string (string str) {
30
this.raw_number = parse_raw_number (str);
33
private static long parse_raw_number (string str) {
89
parse_raw_number (str);
92
* Initialises a FastNumber with the internal representation of that number.
94
[CCode (cname = "v_fast_number_new_raw")]
95
public FastNumber.raw (int64 raw) {
96
this.raw_number = raw;
99
[CCode (cname = "v_fast_number_new_from_float")]
100
public FastNumber.from_float (double float_number) {
101
// XXX Do we need a faster way of doing this?
102
parse_raw_number (float_number.to_string ());
106
* Add this to an other FastNumber.
109
* var f1 = FastNumber (3); // f1 = 3
110
* var f2 = FastNumber (2); // f2 = 2
111
* var f3 = f1.add (f2); // f3 = 5
114
* @return a newly initialised FastNumber.
116
* @param other The other fast number you want to add to this value.
118
[CCode (cname = "v_fast_number_add")]
119
public FastNumber add (FastNumber? other) {
121
return FastNumber.copy (this);
124
var v = FastNumber ();
125
v.raw_number = (this.raw_number + other.raw_number);
130
* Add this to an other FastNumber.
133
* var f1 = FastNumber (3); // f1 = 3
134
* var f2 = FastNumber (2); // f2 = 2
135
* var f3 = f1.subtract (f2); // f3 = 1
138
* @return a newly initialised FastNumber.
140
* @param other The other fast number you want to subtract from this
143
[CCode (cname = "v_fast_number_subtract")]
144
public FastNumber subtract (FastNumber? other) {
146
return FastNumber.copy (this);
149
var v = FastNumber ();
150
v.raw_number = (this.raw_number - other.raw_number);
155
* Multiply this FastNumber with another FastNumber.
158
* var f1 = FastNumber (3); // f1 = 3
159
* var f2 = FastNumber (2); // f2 = 2
160
* var f3 = f1.multiply (f2); // f3 = 6
163
* @return a newly initialised FastNumber.
165
* @param other The value you want to multiply this value with.
167
[CCode (cname = "v_fast_number_multiply")]
168
public FastNumber multiply (FastNumber? other) {
169
if (other == null || other.raw_number == 0 || this.raw_number == 0) {
170
return FastNumber ();
173
var ret = FastNumber ();
174
ret.raw_number = ((this.raw_number * other.raw_number) / MUL_FACTOR);
179
* Divide this FastNumbers with another FastNumber.
182
* var f1 = FastNumber (6); // f1 = 6
183
* var f2 = FastNumber (2); // f2 = 2
184
* var f3 = f1.multiply (f2); // f3 = 3
187
* @return a newly initialised FastNumber.
189
* @param other The value you want to multiply this value with.
191
[CCode (cname = "v_fast_number_divide")]
192
public FastNumber divide (FastNumber other) throws MathError {
193
if (other.raw_number == 0) {
194
throw new MathError.DIVIDE_BY_ZERO ("trying to divide by zero");
196
var ret = FastNumber ();
197
ret.raw_number = ((this.raw_number * MUL_FACTOR) / other.raw_number);
201
[CCode (cname = "v_fast_number_compare")]
202
public int64 compare (FastNumber other) {
203
return this.raw_number - other.raw_number;
207
* Round up this FastNumber and returns a new FastNumber.
209
* @return a rounded up FastNumber.
211
[CCode (cname = "v_fast_number_round_up")]
212
public FastNumber round_up () {
214
int64 decimal = raw_number % PRECISION_FACTOR;
216
ret = FastNumber.raw (raw_number + PRECISION_FACTOR - decimal);
218
ret = FastNumber.raw (raw_number - decimal);
224
* Round up this FastNumber and returns a new FastNumber.
226
* @return a rounded down FastNumber.
228
public FastNumber round_down () {
230
int64 decimal = raw_number % PRECISION_FACTOR;
232
// Is this ever reached?
233
ret = FastNumber.raw (raw_number - PRECISION_FACTOR - decimal);
235
ret = FastNumber.raw (raw_number - decimal);
241
* FastNumber to string.
245
* @param decimal whether to return the decimal portion of the number in
246
* the string. Default = false.
248
[CCode (cname = "v_fast_number_to_string")]
249
public string to_string (bool decimal = false) {
250
string ret_val = null;
252
ret_val = (this.raw_number / MUL_FACTOR).to_string ();
254
// Copy stuff so we don't accidentality stomp them.
255
int64 _raw_number = this.raw_number;
257
int64 _integer_part = (_raw_number / MUL_FACTOR);
258
int64 _decimal_part = (_raw_number - (_integer_part * MUL_FACTOR));
260
var strbldr = new GLib.StringBuilder ();
262
// normalise the decimal part.
263
// (XXX This is rather expensive, is there a better way of doing this?).
264
if (_decimal_part != 0) {
265
while ((_decimal_part % 10) == 0) {
266
_decimal_part = _decimal_part / 10;
270
strbldr.append (_integer_part.to_string ())
274
for ( var i = this.leading_zeros ; i > 0 ; i--) {
275
strbldr.append_c ('0');
278
strbldr.append (_decimal_part.to_string ());
280
ret_val = strbldr.str;
285
[CCode (cname = "v_fast_number_to_float")]
286
public double to_float () {
287
// XXX This probobly needs to something faster?
288
return double.parse (this.to_string (true));
291
[CCode (cname = "v_fast_number_to_int")]
292
public int64 to_int () {
293
return (this.raw_number / MUL_FACTOR);
297
* Check if two FastNumbers are equal.
299
* @return true if this is equal to the other.
300
* @return false if this is not equal to the other.
302
public bool equals (FastNumber other) {
303
return (this.raw_number == other.raw_number);
307
[CCode (cname = "v_fast_number_compare")]
308
public static extern int64 static_compare (FastNumber a, FastNumber b);
310
[CCode (cname = "v_fast_number_private_parse_raw")]
311
private void parse_raw_number (string str) {
312
//debug (@"(parse_raw_number) str: $str");
35
314
int i_of_dot = str.index_of_char ('.');
36
315
if (i_of_dot >= 0) {
38
316
// Get the decimal number from the string, if such a thing exists.
39
317
if ((str.length - 1 > i_of_dot)) {
40
ret_val = long.parse ((str + "000").substring (i_of_dot + 1));
318
var intr_str = (str + "000").substring (i_of_dot + 1);
319
// count leading zeros.
320
// (Must be type long, as that is what string.substring () expects.)
322
for (i = 0; intr_str.@get (i) == '0'; i++){}
323
this.leading_zeros = i;
324
// remove leading zeros
325
intr_str = intr_str.substring (i);
326
//debug (@"(parse_raw_number) Intermediate string: $intr_str");
327
ret_val = int64.parse (intr_str);
330
// debug (@"(parse_raw_number) i_of_dot: $i_of_dot, ret_val (decimal): $ret_val\n");
43
332
// Normalise the digits.
44
333
while (ret_val > MUL_FACTOR) {
45
334
ret_val = ret_val / 10;
49
ret_val = ret_val + (long.parse ("0" + str.substring (0, i_of_dot))
335
// debug (@"(parse_raw_number) retval (loop): $ret_val");
338
for (var i = leading_zeros; i > 0; i--) {
339
ret_val = ret_val / 10;
340
// debug (@"(parse_raw_number) retval (loop2): $ret_val");
343
// debug (@"ret_val (normalised): $ret_val\n");
345
// get integer number
346
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);
350
ret_val = (int64.parse (str) * MUL_FACTOR);
352
//debug (@"(parse_raw_number) ret_val (finished): $ret_val\n");
353
this.raw_number = ret_val;