/vqdr/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/vqdr/trunk
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
346
347
348
349
350
351
352
353
354
355
/*
 * The contects of this file is in the Public Domain.
 *
 * Created by Gustav Hartivgsson.
 */
using GLib;

namespace Vee {
  
  /**
   * Fast Numbers are a decimal representation of numbers in the form of
   * a normal integer value. All internal numbers are multiples of 1000, so the
   * there is room for two three decimal points.
   * 
   * Maths done on these numbers are done using standard integer operations, and
   * not floating point maths.
   * 
   * The decimal part of the FastNumber has a maximum of 3 decimals.
   * 
   * How the value is divided internally is as follows:
   * {{{
   *  (base 10) [0 0 0 0 0 .... 0 | 0 0 0  ]
   *            [non-decial part  | decimal]
   * }}}
   *
   */
  
  public errordomain MathError {
    DIVIDE_BY_ZERO;
  }
  
  public struct FastNumber {
    
    
    /** Precision used to output values */
    public const int32 PRECISION_DIGITS = 2;
    
    /** Precision factor used to evaluate output */
    public const int32 PRECISION_FACTOR = 100;
    
    public const int32 MUL_FACTOR = PRECISION_FACTOR * 10;
    
    public int64 raw_number;
    
    public int64 leading_zeros;
    
    /* XXX
     * I'm not happy using getters/setters in this struct...
     * But I tink it'll have to do for simplicity.
     */
    public int64 number {
      public get {return (this.raw_number / MUL_FACTOR);}
      public set {
        this.raw_number = (MUL_FACTOR * value);
      }
    }
    
    /**
     * Initialises a FastNumber.
     *
     * Note: Due to implementation details, you can't pass a decimal part that
     *       is less than .1, as we are normalising decimal values to the
     *       correct place.
     * 
     * @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 (int64 number = 0) {
      if (number != 0) {
        this.raw_number = (number * MUL_FACTOR);
      } else {
        this.raw_number = 0;
      }
    }
    
    /**
     * 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) {
      parse_raw_number (str);
    }
    /**
     * Initialises a FastNumber with the internal representation of that number.
     */
    
    public FastNumber.raw (int64 raw) {
      this.raw_number = raw;
    }
    
    
    public FastNumber.from_float (double float_number) {
      // XXX Do we need a faster way of doing this?
      parse_raw_number (float_number.to_string ()); 
    }
    
    /**
     * 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 initialised 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 initialised 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 initialised 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 another FastNumber.
     * 
     * {{{
     * var f1 = FastNumber (6);   // f1 = 6
     * var f2 = FastNumber (2);   // f2 = 2
     * var f3 = f1.multiply (f2); // f3 = 3
     * }}}
     * 
     * @return a newly initialised 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;
    }
    
    
    public int64 compare (FastNumber other) {
      return this.raw_number - other.raw_number;
    }
    
    /**
     * Round up this FastNumber and returns a new FastNumber.
     * 
     * @return a rounded up FastNumber.
     */
    
    public FastNumber round_up () {
      FastNumber ret;
      int64 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 returns a new FastNumber.
     * 
     * @return a rounded down FastNumber.
     */
    public FastNumber round_down () {
      FastNumber ret;
      int64 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) {
      string ret_val = null;
      if (!decimal) {
        ret_val = (this.raw_number / MUL_FACTOR).to_string ();
      } else {
        // Copy stuff so we don't accidentality stomp them.
        int64 _raw_number = this.raw_number;
        
        int64 _integer_part = (_raw_number / MUL_FACTOR);
        int64 _decimal_part = (_raw_number - (_integer_part * MUL_FACTOR));
        
        var strbldr = new GLib.StringBuilder ();
        
        // normalise the decimal part.
        // (XXX This is rather expensive, is there a better way of doing this?).
        if (_decimal_part != 0) {
          while ((_decimal_part % 10) == 0) {
            _decimal_part = _decimal_part / 10;
          }
        }
        
        strbldr.append (_integer_part.to_string ())
               .append_c ('.');
        
        
        for ( var i = this.leading_zeros ; i > 0 ; i--) {
          strbldr.append_c ('0');
        }
        
        strbldr.append (_decimal_part.to_string ());
        
        ret_val = strbldr.str;
      }
      return ret_val;
    }
    
    
    public double to_float () {
      // XXX This probobly needs to something faster?
      return double.parse (this.to_string (true));
    }
    
    
    public int64 to_int () {
       return (this.raw_number / MUL_FACTOR);
    }
    
    /**
     * 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);
    }
    
    
    
    public static extern int64 static_compare (FastNumber a, FastNumber b);
    
    
    private void parse_raw_number (string str) {
      int64 ret_val = 0;
      int i_of_dot = str.index_of_char ('.');
      if (i_of_dot >= 0) {
        // Get the decimal number from the string, if such a thing exists.
        if ((str.length - 1 > i_of_dot)) {
          var intr_str = (str + "000").substring (i_of_dot + 1);
          // count leading zeros.
          // (Must be type long, as that is what string.substring () expects.)
          long i;
          for (i = 0; intr_str.@get (i) == '0'; i++){}
          this.leading_zeros = i;
          // remove leading zeros
          intr_str = intr_str.substring (i);
          
          ret_val = int64.parse (intr_str);
        }
        
        // Normalise the digits.
        while (ret_val > MUL_FACTOR) {
          ret_val = ret_val / 10;
        }
        
        for (var i = leading_zeros; i > 0; i--) {
          ret_val = ret_val / 10;
        }
        
        
        // get integer number
        ret_val = ret_val + (int64.parse (str.substring (0, i_of_dot))
                            * MUL_FACTOR);
        
      } else {
        ret_val = (int64.parse (str) * MUL_FACTOR);
      }
      this.raw_number = ret_val;
    }
  }
}