/vqdr/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/vqdr/trunk

« back to all changes in this revision

Viewing changes to src/utils/fast_number.vala

  • Committer: Gustav Hartvigsson
  • Date: 2024-12-21 22:39:17 UTC
  • Revision ID: gustav.hartvigsson@gmail.com-20241221223917-jbt2ylyz9nxjss49
various changes
[utils/utils.vala]
* Removed uneeded int32_abs function

[utils/stack]
* more informative error when trying to pop an empty stack.

[utils/random.vala]
* added c_names to functions (probobly not needed).

[utils/pair.vala]
* Made compact
* made FreeFunc delegates unowned to fix error
* added constructor Pair.with_free_func ().

[utils/named_vector.vala]
* made class compact.

[utils/meson.build]
* Reordered files in list
* added logger.vala.

[utils/logger.vala]
* Added fast and easy logger class.

[utils/fast_number.vala]
* added a bunch of cname CCode attributes.

[general]
* Spelling in comments and functions.

[meson.build]
* Made dependancies easier to read
* added vala posix dependency

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
namespace VQDR.Common {
 
1
/*
 
2
 * The contects of this file is in the Public Domain.
 
3
 *
 
4
 * Created by Gustav Hartivgsson.
 
5
 */
 
6
using GLib;
 
7
[CCode (cname = "V", cprefix = "v_")]
 
8
namespace Utils {
2
9
  
3
10
  /**
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.
7
 
   * 
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.
 
14
   * 
 
15
   * Maths done on these numbers are done using standard integer operations, and
 
16
   * not floating point maths.
 
17
   * 
 
18
   * The decimal part of the FastNumber has a maximum of 3 decimals.
 
19
   * 
 
20
   * How the value is divided internally is as follows:
 
21
   * {{{
 
22
   *  (base 10) [0 0 0 0 0 .... 0 | 0 0 0  ]
 
23
   *            [non-decial part  | decimal]
 
24
   * }}}
 
25
   *
10
26
   */
11
 
  class FastNumber {
12
 
    public const long MUL_FACTOR = 1000;
13
 
    
14
 
    public long raw_number { public get; private set; }
15
 
    
16
 
    public long number {
17
 
      get {return raw_number / MUL_FACTOR;}
18
 
      set {raw_number = number * MUL_FACTOR;}
19
 
    }
20
 
    
21
 
    public FastNumber (long val = 0) {
22
 
      this.number = val;
23
 
    }
24
 
    
 
27
  [CCode (cname = "VFastNumber", cprefix = "v_fast_number_")]
 
28
  public struct FastNumber {
 
29
    
 
30
    /** Precision used to output values */
 
31
    public const int32 PRECISION_DIGITS = 2;
 
32
    
 
33
    /** Precision factor used to evaluate output */
 
34
    public const int32 PRECISION_FACTOR = 100;
 
35
    
 
36
    public const int32 MUL_FACTOR = PRECISION_FACTOR * 10;
 
37
    
 
38
    public int64 raw_number;
 
39
    
 
40
    public int64 leading_zeros;
 
41
    
 
42
    /* XXX
 
43
     * I'm not happy using getters/setters in this struct...
 
44
     * But I tink it'll have to do for simplicity.
 
45
     */
 
46
    public int64 number {
 
47
      public get {return (this.raw_number / MUL_FACTOR);}
 
48
      public set {
 
49
        this.raw_number = (MUL_FACTOR * value);
 
50
      }
 
51
    }
 
52
    
 
53
    /**
 
54
     * Initialises a FastNumber.
 
55
     *
 
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
 
58
     *       correct place.
 
59
     * 
 
60
     * @param number   The number that are to be set as the none-decimal part of
 
61
     *                 the number. Defaults to 0.
 
62
     * 
 
63
     * @param decimal  The decimal part of the number. Defaults to 0.
 
64
     */
 
65
    [CCode (cname = "v_fast_number_new")]
 
66
    public FastNumber (int64 number = 0) {
 
67
      if (number != 0) {
 
68
        this.raw_number = (number * MUL_FACTOR);
 
69
      } else {
 
70
        this.raw_number = 0;
 
71
      }
 
72
    }
 
73
    
 
74
    /**
 
75
     * Do a deep copy of a FastNumber.
 
76
     */
 
77
    [CCode (cname = "v_fast_number_copy")]
25
78
    public FastNumber.copy (FastNumber other) {
26
79
      this.raw_number = other.raw_number;
27
80
    }
28
81
    
 
82
    /**
 
83
     * Initialises a FastNumber from a string.
 
84
     * 
 
85
     * Can be a decimal representation.
 
86
     */
 
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);
31
 
    }
32
 
    
33
 
    private static long parse_raw_number (string str) {
34
 
      long ret_val = 0;
 
89
      parse_raw_number (str);
 
90
    }
 
91
    /**
 
92
     * Initialises a FastNumber with the internal representation of that number.
 
93
     */
 
94
    [CCode (cname = "v_fast_number_new_raw")]
 
95
    public FastNumber.raw (int64 raw) {
 
96
      this.raw_number = raw;
 
97
    }
 
98
    
 
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 ()); 
 
103
    }
 
104
    
 
105
    /**
 
106
     * Add this to an other FastNumber.
 
107
     * 
 
108
     * {{{
 
109
     * var f1 = FastNumber (3);   // f1 = 3
 
110
     * var f2 = FastNumber (2);   // f2 = 2
 
111
     * var f3 = f1.add (f2);      // f3 = 5
 
112
     * }}}
 
113
     * 
 
114
     * @return a newly initialised FastNumber.
 
115
     * 
 
116
     * @param other The other fast number you want to add to this value.
 
117
     */
 
118
    [CCode (cname = "v_fast_number_add")]
 
119
    public FastNumber add (FastNumber? other) {
 
120
      if (other == null) {
 
121
        return  FastNumber.copy (this);
 
122
      }
 
123
      
 
124
      var v = FastNumber ();
 
125
      v.raw_number = (this.raw_number + other.raw_number);
 
126
      return v;
 
127
    }
 
128
    
 
129
    /**
 
130
     * Add this to an other FastNumber.
 
131
     * 
 
132
     * {{{
 
133
     * var f1 = FastNumber (3);   // f1 = 3
 
134
     * var f2 = FastNumber (2);   // f2 = 2
 
135
     * var f3 = f1.subtract (f2); // f3 = 1
 
136
     * }}}
 
137
     * 
 
138
     * @return a newly initialised FastNumber.
 
139
     * 
 
140
     * @param other  The other fast number you want to subtract from this 
 
141
     *               FastNumber.
 
142
     */
 
143
    [CCode (cname = "v_fast_number_subtract")]
 
144
    public FastNumber subtract (FastNumber? other) {
 
145
      if (other == null) {
 
146
        return  FastNumber.copy (this);
 
147
      }
 
148
      
 
149
      var v = FastNumber ();
 
150
      v.raw_number = (this.raw_number - other.raw_number);
 
151
      return v;
 
152
    }
 
153
    
 
154
    /**
 
155
     * Multiply this FastNumber with another FastNumber.
 
156
     * 
 
157
     * {{{
 
158
     * var f1 = FastNumber (3);   // f1 = 3
 
159
     * var f2 = FastNumber (2);   // f2 = 2
 
160
     * var f3 = f1.multiply (f2); // f3 = 6
 
161
     * }}}
 
162
     * 
 
163
     * @return a newly initialised FastNumber.
 
164
     * 
 
165
     * @param other The value you want to multiply this value with.
 
166
     */
 
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 ();
 
171
      }
 
172
      
 
173
      var ret = FastNumber ();
 
174
      ret.raw_number = ((this.raw_number * other.raw_number) / MUL_FACTOR);
 
175
      return ret;
 
176
    }
 
177
    
 
178
    /**
 
179
     * Divide this FastNumbers with another FastNumber.
 
180
     * 
 
181
     * {{{
 
182
     * var f1 = FastNumber (6);   // f1 = 6
 
183
     * var f2 = FastNumber (2);   // f2 = 2
 
184
     * var f3 = f1.multiply (f2); // f3 = 3
 
185
     * }}}
 
186
     * 
 
187
     * @return a newly initialised FastNumber.
 
188
     * 
 
189
     * @param other The value you want to multiply this value with.
 
190
     */
 
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");
 
195
      }
 
196
      var ret =  FastNumber ();
 
197
      ret.raw_number = ((this.raw_number * MUL_FACTOR) / other.raw_number);
 
198
      return ret;
 
199
    }
 
200
    
 
201
    [CCode (cname = "v_fast_number_compare")]
 
202
    public int64 compare (FastNumber other) {
 
203
      return this.raw_number - other.raw_number;
 
204
    }
 
205
    
 
206
    /**
 
207
     * Round up this FastNumber and returns a new FastNumber.
 
208
     * 
 
209
     * @return a rounded up FastNumber.
 
210
     */
 
211
    [CCode (cname = "v_fast_number_round_up")]
 
212
    public FastNumber round_up () {
 
213
      FastNumber ret;
 
214
      int64 decimal = raw_number % PRECISION_FACTOR;
 
215
      if (decimal > 0) {
 
216
        ret = FastNumber.raw (raw_number + PRECISION_FACTOR - decimal);
 
217
      } else {
 
218
        ret = FastNumber.raw (raw_number - decimal);
 
219
      }
 
220
      return ret;
 
221
    }
 
222
    
 
223
    /**
 
224
     * Round up this FastNumber and returns a new FastNumber.
 
225
     * 
 
226
     * @return a rounded down FastNumber.
 
227
     */
 
228
    public FastNumber round_down () {
 
229
      FastNumber ret;
 
230
      int64 decimal = raw_number % PRECISION_FACTOR;
 
231
      if (decimal < 0) {
 
232
        // Is this ever reached?
 
233
        ret = FastNumber.raw (raw_number - PRECISION_FACTOR - decimal);
 
234
      } else {
 
235
        ret = FastNumber.raw (raw_number - decimal);
 
236
      }
 
237
      return ret;
 
238
    }
 
239
    
 
240
    /**
 
241
     * FastNumber to string.
 
242
     * 
 
243
     * @return a string
 
244
     * 
 
245
     * @param decimal whether to return the decimal portion of the number in 
 
246
     *                the string. Default = false.
 
247
     */
 
248
    [CCode (cname = "v_fast_number_to_string")]
 
249
    public string to_string (bool decimal = false) {
 
250
      string ret_val = null;
 
251
      if (!decimal) {
 
252
        ret_val = (this.raw_number / MUL_FACTOR).to_string ();
 
253
      } else {
 
254
        // Copy stuff so we don't accidentality stomp them.
 
255
        int64 _raw_number = this.raw_number;
 
256
        
 
257
        int64 _integer_part = (_raw_number / MUL_FACTOR);
 
258
        int64 _decimal_part = (_raw_number - (_integer_part * MUL_FACTOR));
 
259
        
 
260
        var strbldr = new GLib.StringBuilder ();
 
261
        
 
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;
 
267
          }
 
268
        }
 
269
        
 
270
        strbldr.append (_integer_part.to_string ())
 
271
               .append_c ('.');
 
272
        
 
273
        
 
274
        for ( var i = this.leading_zeros ; i > 0 ; i--) {
 
275
          strbldr.append_c ('0');
 
276
        }
 
277
        
 
278
        strbldr.append (_decimal_part.to_string ());
 
279
        
 
280
        ret_val = strbldr.str;
 
281
      }
 
282
      return ret_val;
 
283
    }
 
284
    
 
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));
 
289
    }
 
290
    
 
291
    [CCode (cname = "v_fast_number_to_int")]
 
292
    public int64 to_int () {
 
293
       return (this.raw_number / MUL_FACTOR);
 
294
    }
 
295
    
 
296
    /**
 
297
     * Check if two FastNumbers are equal.
 
298
     * 
 
299
     * @return true if this is equal to the other.
 
300
     * @return false if this is not equal to the other.
 
301
     */
 
302
    public bool equals (FastNumber other) {
 
303
      return (this.raw_number == other.raw_number);
 
304
    }
 
305
    
 
306
    
 
307
    [CCode (cname = "v_fast_number_compare")]
 
308
    public static extern int64 static_compare (FastNumber a, FastNumber b);
 
309
    
 
310
    [CCode (cname = "v_fast_number_private_parse_raw")]
 
311
    private void parse_raw_number (string str) {
 
312
      //debug (@"(parse_raw_number) str: $str");
 
313
      int64 ret_val = 0;
35
314
      int i_of_dot = str.index_of_char ('.');
36
315
      if (i_of_dot >= 0) {
37
 
      
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.)
 
321
          long i;
 
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);
41
328
        }
42
329
        
 
330
        // debug (@"(parse_raw_number) i_of_dot: $i_of_dot, ret_val (decimal): $ret_val\n");
 
331
        
43
332
        // Normalise the digits.
44
333
        while (ret_val > MUL_FACTOR) {
45
334
          ret_val = ret_val / 10;
46
 
        }
47
 
        
48
 
        // Add intiger number
49
 
        ret_val = ret_val + (long.parse ("0" + str.substring (0, i_of_dot))
 
335
          // debug (@"(parse_raw_number) retval (loop): $ret_val");
 
336
        }
 
337
        
 
338
        for (var i = leading_zeros; i > 0; i--) {
 
339
          ret_val = ret_val / 10;
 
340
          // debug (@"(parse_raw_number) retval (loop2): $ret_val");
 
341
        }
 
342
        
 
343
        // debug (@"ret_val (normalised): $ret_val\n");
 
344
        
 
345
        // get integer number
 
346
        ret_val = ret_val + (int64.parse (str.substring (0, i_of_dot))
50
347
                            * MUL_FACTOR);
 
348
        
51
349
      } else {
52
 
        ret_val = long.parse (str) * MUL_FACTOR;
53
 
      }
54
 
      return ret_val;
55
 
    }
56
 
    
57
 
    
58
 
    public FastNumber add (FastNumber? other) {
59
 
      if (other == null) {
60
 
        return new FastNumber.copy (this);
61
 
      }
62
 
      
63
 
      var v = new FastNumber (this.raw_number + other.raw_number);
64
 
      
65
 
      return v;
66
 
    }
67
 
    
68
 
    public FastNumber subtract (FastNumber? other) {
69
 
      if (other == null) {
70
 
        return new FastNumber.copy (this);
71
 
      }
72
 
      
73
 
      var v = new FastNumber (this.raw_number - other.raw_number);
74
 
      
75
 
      return v;
76
 
    }
77
 
    
78
 
    public FastNumber multiply (FastNumber? other) {
79
 
      if (other == null || other.raw_value == 0) {
80
 
        return new FastNumber ();
81
 
      }
82
 
      
83
 
      return new FastNumber ((this.raw_number * other.raw_number) / MUL_FACTOR);
84
 
    }
85
 
    
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");
90
 
      }
91
 
      
92
 
      return new FastNumber ((this.raw_number * MUL_FACTOR) / other.raw_number);
93
 
    }
94
 
    
 
350
        ret_val = (int64.parse (str) * MUL_FACTOR);
 
351
      }
 
352
      //debug (@"(parse_raw_number) ret_val (finished): $ret_val\n");
 
353
      this.raw_number = ret_val;
 
354
    }
95
355
  }
96
 
  
97
356
}