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
|
/*
* The contects of this file is in the Public Domain.
*
* Created by Gustav Hartivgsson.
*/
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.
*/
public struct FastNumber {
public const long MUL_FACTOR = 1000;
/** Precision used to output values */
public const int PRECISION_DIGITS = 2;
/** Precision factor used to evaluate output */
public const int PRECISION_FACTOR = 100;
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 {return double.parse (@"$number" + "." + @"$decimal");}
public set {this.raw_number = parse_raw_number (value.to_string ());}
}
public FastNumber (long val = 0) {
this.number = val;
}
public FastNumber.copy (FastNumber other) {
this.raw_number = other.raw_number;
}
public FastNumber.from_string (string str) {
this.raw_number = parse_raw_number (str);
}
public FastNumber.from_float (double f) {
this.raw_number = parse_raw_number (f.to_string ());
}
public FastNumber.raw (long raw) {
this.raw_number = raw;
}
public void set_from_string (string str) {
this.raw_number = parse_raw_number (str);
}
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;
}
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;
}
public FastNumber multiply (FastNumber? other) {
if (other == null || other.raw_number == 0) {
return FastNumber ();
}
var ret = FastNumber ();
ret.raw_number = ((this.raw_number * other.raw_number) / MUL_FACTOR);
return ret;
}
public FastNumber divide (FastNumber other) throws MathError {
if (other.raw_number == 0) {
throw new MathError.DIVIDE_BY_ZERO
("FantNumber - 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;
}
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;
}
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;
}
public string to_string (bool decimal = false) {
if (decimal) {
return number.to_string () + "." + decimal.to_string ();
} else {
return number.to_string ();
}
}
// ***** 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 (@"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 (@"ret_val (normalised): $ret_val\n");
// Add intiger number
ret_val = ret_val + (long.parse (str.substring (0, i_of_dot))
* MUL_FACTOR);
debug (@"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) {
var mask = number / MUL_FACTOR;
mask = mask * MUL_FACTOR;
return number - mask;
}
public static void set_decimal_of_number (ref long number, long decimal) {
var masked = number / MUL_FACTOR;
masked = masked * MUL_FACTOR;
number = masked + decimal;
}
[CCode (cname = "vqdr_common_fast_number_compare")]
public static extern long static_compare (FastNumber a, FastNumber b);
}
}
|