2
* The contects of this file is in the Public Domain.
4
* Created by Gustav Hartivgsson.
7
[CCode (cname = "V", cprefix = "v_")]
1
namespace VQDR.Common {
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]
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.
27
[CCode (cname = "VFastNumber", cprefix = "v_fast_number_")]
28
public struct FastNumber {
30
/** Precision used to output values */
31
public const int PRECISION_DIGITS = 2;
33
/** Precision factor used to evaluate output */
34
public const int PRECISION_FACTOR = 100;
36
public const int MUL_FACTOR = PRECISION_FACTOR * 10;
38
public long raw_number;
40
public long leading_zeros;
43
* I'm not happy using getters/setters in this struct...
44
* But I tink it'll have to do for simplicity.
12
public const long MUL_FACTOR = 1000;
14
public long raw_number { public get; private set; }
46
16
public long number {
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
public FastNumber (long number = 0) {
67
this.raw_number = (number * MUL_FACTOR);
74
* Do a deep copy of a FastNumber.
17
get {return raw_number / MUL_FACTOR;}
18
set {raw_number = number * MUL_FACTOR;}
21
public FastNumber (long val = 0) {
76
25
public FastNumber.copy (FastNumber other) {
77
26
this.raw_number = other.raw_number;
81
* Initialises a FastNumber from a string.
83
* Can be a decimal representation.
85
29
public FastNumber.from_string (string str) {
86
parse_raw_number (str);
89
* Initialises a FastNumber with the internal representation of that number.
91
public FastNumber.raw (long raw) {
92
this.raw_number = raw;
95
public FastNumber.from_float (double float_number) {
96
// XXX Do we need a faster way of doing this?
97
parse_raw_number (float_number.to_string ());
101
* Add this to an other FastNumber.
104
* var f1 = FastNumber (3); // f1 = 3
105
* var f2 = FastNumber (2); // f2 = 2
106
* var f3 = f1.add (f2); // f3 = 5
109
* @return a newly initialised FastNumber.
111
* @param other The other fast number you want to add to this value.
113
public FastNumber add (FastNumber? other) {
115
return FastNumber.copy (this);
118
var v = FastNumber ();
119
v.raw_number = (this.raw_number + other.raw_number);
124
* Add this to an other FastNumber.
127
* var f1 = FastNumber (3); // f1 = 3
128
* var f2 = FastNumber (2); // f2 = 2
129
* var f3 = f1.subtract (f2); // f3 = 1
132
* @return a newly initialised FastNumber.
134
* @param other The other fast number you want to subtract from this
137
public FastNumber subtract (FastNumber? other) {
139
return FastNumber.copy (this);
142
var v = FastNumber ();
143
v.raw_number = (this.raw_number - other.raw_number);
148
* Multiply this FastNumber with another FastNumber.
151
* var f1 = FastNumber (3); // f1 = 3
152
* var f2 = FastNumber (2); // f2 = 2
153
* var f3 = f1.multiply (f2); // f3 = 6
156
* @return a newly initialised FastNumber.
158
* @param other The value you want to multiply this value with.
160
public FastNumber multiply (FastNumber? other) {
161
if (other == null || other.raw_number == 0 || this.raw_number == 0) {
162
return FastNumber ();
165
var ret = FastNumber ();
166
ret.raw_number = ((this.raw_number * other.raw_number) / MUL_FACTOR);
171
* Divide this FastNumbers with another FastNumber.
174
* var f1 = FastNumber (6); // f1 = 6
175
* var f2 = FastNumber (2); // f2 = 2
176
* var f3 = f1.multiply (f2); // f3 = 3
179
* @return a newly initialised FastNumber.
181
* @param other The value you want to multiply this value with.
183
public FastNumber divide (FastNumber other) throws MathError {
184
if (other.raw_number == 0) {
185
throw new MathError.DIVIDE_BY_ZERO ("trying to divide by zero");
187
var ret = FastNumber ();
188
ret.raw_number = ((this.raw_number * MUL_FACTOR) / other.raw_number);
192
[CCode (cname = "vqdr_common_fast_number_compare")]
193
public long compare (FastNumber other) {
194
return this.raw_number - other.raw_number;
198
* Round up this FastNumber and returns a new FastNumber.
200
* @return a rounded up FastNumber.
202
public FastNumber round_up () {
204
long decimal = raw_number % PRECISION_FACTOR;
206
ret = FastNumber.raw (raw_number + PRECISION_FACTOR - decimal);
208
ret = FastNumber.raw (raw_number - decimal);
214
* Round up this FastNumber and returns a new FastNumber.
216
* @return a rounded down FastNumber.
218
public FastNumber round_down () {
220
long decimal = raw_number % PRECISION_FACTOR;
222
// Is this ever reached?
223
ret = FastNumber.raw (raw_number - PRECISION_FACTOR - decimal);
225
ret = FastNumber.raw (raw_number - decimal);
231
* FastNumber to string.
235
* @param decimal whether to return the decimal portion of the number in
236
* the string. Default = false.
238
public string to_string (bool decimal = false) {
239
string ret_val = null;
241
ret_val = (this.raw_number / MUL_FACTOR).to_string ();
243
// Copy stuff so we don't accidentality stomp them.
244
long _raw_number = this.raw_number;
246
long _integer_part = (_raw_number / MUL_FACTOR);
247
long _decimal_part = (_raw_number - (_integer_part * MUL_FACTOR));
249
var strbldr = new GLib.StringBuilder ();
251
// normalise the decimal part.
252
// (XXX This is rather expensive, is there a better way of doing this?).
253
if (_decimal_part != 0) {
254
while ((_decimal_part % 10) == 0) {
255
_decimal_part = _decimal_part / 10;
259
strbldr.append (_integer_part.to_string ())
263
for ( var i = this.leading_zeros ; i > 0 ; i--) {
264
strbldr.append_c ('0');
267
strbldr.append (_decimal_part.to_string ());
269
ret_val = strbldr.str;
274
public double to_float () {
275
// XXX This probobly needs to something faster?
276
return double.parse (this.to_string (true));
279
public long to_int () {
280
return (this.raw_number / MUL_FACTOR);
284
* Check if two FastNumbers are equal.
286
* @return true if this is equal to the other.
287
* @return false if this is not equal to the other.
289
public bool equals (FastNumber other) {
290
return (this.raw_number == other.raw_number);
294
[CCode (cname = "vqdr_common_fast_number_compare")]
295
public static extern long static_compare (FastNumber a, FastNumber b);
297
private void parse_raw_number (string str) {
298
//debug (@"(parse_raw_number) str: $str");
30
this.raw_number = parse_raw_number (str);
33
private static long parse_raw_number (string str) {
300
35
int i_of_dot = str.index_of_char ('.');
301
36
if (i_of_dot >= 0) {
302
38
// Get the decimal number from the string, if such a thing exists.
303
39
if ((str.length - 1 > i_of_dot)) {
304
var intr_str = (str + "000").substring (i_of_dot + 1);
305
// count leading zeros.
307
for (i = 0; intr_str.@get (i) == '0'; i++){}
308
this.leading_zeros = i;
309
// remove leading zeros
310
intr_str = intr_str.substring (i);
311
//debug (@"(parse_raw_number) Intermediate string: $intr_str");
312
ret_val = long.parse (intr_str);
40
ret_val = long.parse ((str + "000").substring (i_of_dot + 1));
315
// debug (@"(parse_raw_number) i_of_dot: $i_of_dot, ret_val (decimal): $ret_val\n");
317
43
// Normalise the digits.
318
44
while (ret_val > MUL_FACTOR) {
319
45
ret_val = ret_val / 10;
320
// debug (@"(parse_raw_number) retval (loop): $ret_val");
323
for (var i = leading_zeros; i > 0; i--) {
324
ret_val = ret_val / 10;
325
// debug (@"(parse_raw_number) retval (loop2): $ret_val");
328
// debug (@"ret_val (normalised): $ret_val\n");
330
// get integer number
331
ret_val = ret_val + (long.parse (str.substring (0, i_of_dot))
49
ret_val = ret_val + (long.parse ("0" + str.substring (0, i_of_dot))
335
ret_val = (long.parse (str) * MUL_FACTOR);
337
//debug (@"(parse_raw_number) ret_val (finished): $ret_val\n");
338
this.raw_number = ret_val;
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);