/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/common/fast_number.vala

  • Committer: Gustav Hartvigsson
  • Date: 2021-09-15 17:10:52 UTC
  • Revision ID: gustav.hartvigsson@gmail.com-20210915171052-yhdw16iyipyj5a5l
* Fixed Fastnumber's normalisation problem with the getters/setters

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * The contects of this file is in the Public Domain.
 
3
 *
 
4
 * Created by Gustav Hartivgsson.
 
5
 */
 
6
using GLib;
 
7
 
1
8
namespace VQDR.Common {
2
9
  
3
10
  /**
7
14
   * 
8
15
   * Math done on these numbers are done using standard integer operations, and
9
16
   * not floating point math.
 
17
   * 
 
18
   * The decimal part of the FastNumber has a maximum of 3 decimals.
 
19
   * 
 
20
   * How the value is devided internally is as follows:
 
21
   * {{{
 
22
     (base 10) [0 0 0 0 0 .... 0 | 0 0 0  ]
 
23
             [non-decial part  | decimal]
 
24
   * }}}
10
25
   */
11
 
  class FastNumber {
12
 
    public const long MUL_FACTOR = 1000;
13
 
    
14
 
    public long raw_number { public get; private set; }
 
26
  public struct FastNumber {
 
27
    /** Precision used to output values */
 
28
    public const int PRECISION_DIGITS = 2;
 
29
    
 
30
    /** Precision factor used to evaluate output */
 
31
    public const int PRECISION_FACTOR = 100;
 
32
    
 
33
    public const int MUL_FACTOR = PRECISION_FACTOR * 10;
 
34
    
 
35
 
 
36
    
 
37
    public long raw_number;
15
38
    
16
39
    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
 
    
 
40
      public get {return (this.raw_number / MUL_FACTOR);}
 
41
      public set {this.raw_number = (MUL_FACTOR * value);}
 
42
    }
 
43
    
 
44
    public long decimal {
 
45
      public get {return mask_and_normalize_decimal (raw_number);}
 
46
      public set {set_decimal_of_number (ref raw_number, value);}
 
47
    }
 
48
    
 
49
    public double float_rep {
 
50
      public get {
 
51
        long dec = this.decimal;
 
52
        long nbr = this.number;
 
53
        debug (@"(float_ret_get) Float str: $nbr.$dec");
 
54
        return double.parse (@"$nbr.$dec");
 
55
      } public set {
 
56
        debug (@"(float_ret_set) set float: $value");
 
57
        this.raw_number = parse_raw_number (value.to_string ());
 
58
      }
 
59
    }
 
60
    
 
61
    /**
 
62
     * Initialises a FastNumber.
 
63
     * 
 
64
     * @param number   The number that are to be set as the none-decimal part of
 
65
     *                 the number. Defaults to 0.
 
66
     * 
 
67
     * @param decimal  The decimal part of the number. Defaults to 0.
 
68
     */
 
69
    public FastNumber (long number = 0, int decimal = 0) {
 
70
      this.number = number;
 
71
      this.decimal = decimal;
 
72
    }
 
73
    
 
74
    /**
 
75
     * Do a deep copy of a FastNumber.
 
76
     */
25
77
    public FastNumber.copy (FastNumber other) {
26
78
      this.raw_number = other.raw_number;
27
79
    }
28
80
    
 
81
    /**
 
82
     * Initialises a FastNumber from a string.
 
83
     * 
 
84
     * Can be a decimal representation.
 
85
     */
29
86
    public FastNumber.from_string (string str) {
30
87
      this.raw_number = parse_raw_number (str);
31
88
    }
32
89
    
33
 
    private static long parse_raw_number (string str) {
 
90
    /**
 
91
     * Initialises a FastNumber from a double floating point value.
 
92
     * 
 
93
     * Due to how floatinng point numbers works this may not be the exact value
 
94
     * you expect it to be.
 
95
     */
 
96
    public FastNumber.from_float (double f) {
 
97
      this.raw_number = parse_raw_number (f.to_string ());
 
98
    }
 
99
    
 
100
    /**
 
101
     * Initialises a FastNumber with the internal representation of that number.
 
102
     */
 
103
    public FastNumber.raw (long raw) {
 
104
      this.raw_number = raw;
 
105
    }
 
106
    
 
107
    /**
 
108
     * Sets the value of this FastNumber from a string, 
 
109
     */
 
110
    public void set_from_string (string str) {
 
111
      this.raw_number = parse_raw_number (str);
 
112
    }
 
113
    
 
114
    /**
 
115
     * Add this to an other FastNumber.
 
116
     * 
 
117
     * {{{
 
118
     * var f1 = FastNumber (3);   // f1 = 3
 
119
     * var f2 = FastNumber (2);   // f2 = 2
 
120
     * var f3 = f1.add (f2);      // f3 = 5
 
121
     * }}}
 
122
     * 
 
123
     * @return a newly inisialised FastNumber.
 
124
     * 
 
125
     * @param other The other fast number you want to add to this value.
 
126
     */
 
127
    public FastNumber add (FastNumber? other) {
 
128
      if (other == null) {
 
129
        return  FastNumber.copy (this);
 
130
      }
 
131
      
 
132
      var v = FastNumber ();
 
133
      v.raw_number = (this.raw_number + other.raw_number);
 
134
      return v;
 
135
    }
 
136
    
 
137
    /**
 
138
     * Add this to an other FastNumber.
 
139
     * 
 
140
     * {{{
 
141
     * var f1 = FastNumber (3);   // f1 = 3
 
142
     * var f2 = FastNumber (2);   // f2 = 2
 
143
     * var f3 = f1.subtract (f2); // f3 = 1
 
144
     * }}}
 
145
     * 
 
146
     * @return a newly inisialised FastNumber.
 
147
     * 
 
148
     * @param other  The other fast number you want to subtract from this 
 
149
     *               FastNumber.
 
150
     */
 
151
    public FastNumber subtract (FastNumber? other) {
 
152
      if (other == null) {
 
153
        return  FastNumber.copy (this);
 
154
      }
 
155
      
 
156
      var v = FastNumber ();
 
157
      v.raw_number = (this.raw_number - other.raw_number);
 
158
      return v;
 
159
    }
 
160
    
 
161
    /**
 
162
     * Multiply this FastNumber with another FastNumber.
 
163
     * 
 
164
     * {{{
 
165
     * var f1 = FastNumber (3);   // f1 = 3
 
166
     * var f2 = FastNumber (2);   // f2 = 2
 
167
     * var f3 = f1.multiply (f2); // f3 = 6
 
168
     * }}}
 
169
     * 
 
170
     * @return a newly initalised FastNumber.
 
171
     * 
 
172
     * @param other The value you want to multiply this value with.
 
173
     */
 
174
    public FastNumber multiply (FastNumber? other) {
 
175
      if (other == null || other.raw_number == 0 || this.raw_number == 0) {
 
176
        return  FastNumber ();
 
177
      }
 
178
      
 
179
      var ret = FastNumber ();
 
180
      ret.raw_number = ((this.raw_number * other.raw_number) / MUL_FACTOR);
 
181
      return ret;
 
182
    }
 
183
    
 
184
    /**
 
185
     * Divide this FastNumbers with anothr FastNumber.
 
186
     * 
 
187
     * {{{
 
188
     * var f1 = FastNumber (6);   // f1 = 6
 
189
     * var f2 = FastNumber (2);   // f2 = 2
 
190
     * var f3 = f1.multiply (f2); // f3 = 3
 
191
     * }}}
 
192
     * 
 
193
     * @return a newly initalised FastNumber.
 
194
     * 
 
195
     * @param other The value you want to multiply this value with.
 
196
     */
 
197
    public FastNumber divide (FastNumber other) throws MathError {
 
198
      if (other.raw_number == 0) {
 
199
        throw new MathError.DIVIDE_BY_ZERO ("trying to divide by zero");
 
200
      }
 
201
      var ret =  FastNumber ();
 
202
      ret.raw_number = ((this.raw_number * MUL_FACTOR) / other.raw_number);
 
203
      return ret;
 
204
    }
 
205
    
 
206
    [CCode (cname = "vqdr_common_fast_number_compare")]
 
207
    public long compare (FastNumber other) {
 
208
      return this.raw_number - other.raw_number;
 
209
    }
 
210
    
 
211
    /**
 
212
     * Round up this FastNumber and retuns it.
 
213
     * 
 
214
     * @return a rounded up FastNumber.
 
215
     */
 
216
    public FastNumber round_up () {
 
217
      FastNumber ret;
 
218
      long decimal = raw_number % PRECISION_FACTOR;
 
219
      if (decimal > 0) {
 
220
        ret = FastNumber.raw (raw_number + PRECISION_FACTOR - decimal);
 
221
      } else {
 
222
        ret = FastNumber.raw (raw_number - decimal);
 
223
      }
 
224
      return ret;
 
225
    }
 
226
    
 
227
    /**
 
228
     * Round up this FastNumber and retuns it.
 
229
     * 
 
230
     * @return a rounded down FastNumber.
 
231
     */
 
232
    public FastNumber round_down () {
 
233
      FastNumber ret;
 
234
      long decimal = raw_number % PRECISION_FACTOR;
 
235
      if (decimal < 0) {
 
236
        // Is this ever reached?
 
237
        ret = FastNumber.raw (raw_number - PRECISION_FACTOR - decimal);
 
238
      } else {
 
239
        ret = FastNumber.raw (raw_number - decimal);
 
240
      }
 
241
      return ret;
 
242
    }
 
243
    
 
244
    /**
 
245
     * FastNumber to string.
 
246
     * 
 
247
     * @return a string
 
248
     * 
 
249
     * @param decimal whether to return the decimal portion of the number in 
 
250
     *                the string. Default = false.
 
251
     */
 
252
    public string to_string (bool decimal = false) {
 
253
      if (decimal) {
 
254
        return @"$number.$decimal";
 
255
      } else {
 
256
        return number.to_string ();
 
257
      }
 
258
    } 
 
259
    
 
260
    /**
 
261
     * Check if two FastNumbers are equal.
 
262
     * 
 
263
     * @return true if this is equal to the other.
 
264
     * @return false if this is not equal to the other.
 
265
     */
 
266
    public bool equals (FastNumber other) {
 
267
      return (this.raw_number == other.raw_number);
 
268
    }
 
269
    
 
270
    // ***** STATIC FUNCTIONS ****//
 
271
    public static long parse_raw_number (string str) {
34
272
      long ret_val = 0;
35
273
      int i_of_dot = str.index_of_char ('.');
36
274
      if (i_of_dot >= 0) {
37
 
      
 
275
        
 
276
        debug (@"str: $str");
38
277
        // Get the decimal number from the string, if such a thing exists.
39
278
        if ((str.length - 1 > i_of_dot)) {
40
279
          ret_val = long.parse ((str + "000").substring (i_of_dot + 1));
41
280
        }
42
281
        
 
282
        debug (@"(parse_raw_number) i_of_dot: $i_of_dot, ret_val (decimal): $ret_val\n");
 
283
        
43
284
        // Normalise the digits.
44
285
        while (ret_val > MUL_FACTOR) {
45
286
          ret_val = ret_val / 10;
 
287
          debug (@"(parse_raw_number) retval (loop): $ret_val");
46
288
        }
47
289
        
48
 
        // Add intiger number
49
 
        ret_val = ret_val + (long.parse ("0" + str.substring (0, i_of_dot))
 
290
        debug (@"ret_val (normalised): $ret_val\n");
 
291
        
 
292
        // get intiger number
 
293
        ret_val = ret_val + (long.parse (str.substring (0, i_of_dot))
50
294
                            * MUL_FACTOR);
 
295
        
 
296
        debug (@"(parse_raw_number) ret_val (finised): $ret_val\n");
 
297
        
51
298
      } else {
52
299
        ret_val = long.parse (str) * MUL_FACTOR;
53
300
      }
54
301
      return ret_val;
55
302
    }
56
303
    
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
 
    
 
304
    public static long mask_and_normalize_decimal (long number) {
 
305
      debug (@"(mask_and_normalize_decimal) number: $number");
 
306
      long mask = number / MUL_FACTOR;
 
307
      debug (@"(mask_and_normalize_decimal) mask(1): $mask");
 
308
      mask = mask * MUL_FACTOR;
 
309
      debug (@"(mask_and_normalize_decimal) mask(2): $mask");
 
310
      long ret = number - mask;
 
311
      // normalise
 
312
      // This is a rathor expensive operation.
 
313
      if (ret != 0) {
 
314
        while ((ret % 10) == 0) {
 
315
          ret = ret / 10;
 
316
        }
 
317
      }
 
318
      debug (@"(mask_and_normalize_decimal) ret: $ret");
 
319
      return ret;
 
320
    }
 
321
    
 
322
    public static void set_decimal_of_number (ref long number, long decimal) {
 
323
      debug (@"(set_decimal_of_number) number(0): $number, decimal(0): $decimal");
 
324
      long masked = number / MUL_FACTOR;
 
325
      debug (@"(set_decimal_of_number) masked(1): $masked");
 
326
      masked = masked * MUL_FACTOR;
 
327
      debug (@"(set_decimal_of_number) masked(2): $masked");
 
328
      
 
329
      // Normalise didgits
 
330
      if (decimal != 0) {
 
331
        while (decimal < PRECISION_FACTOR) {
 
332
          decimal = decimal * 10;
 
333
          debug (@"(set_decimal_of_number) loop, decimal: $decimal");
 
334
        }
 
335
      }
 
336
      
 
337
      number = masked + decimal;
 
338
      debug (@"(set_decimal_of_number) number(1): $number");
 
339
      
 
340
    }
 
341
      
 
342
    [CCode (cname = "vqdr_common_fast_number_compare")]
 
343
    public static extern long static_compare (FastNumber a, FastNumber b);
95
344
  }
96
 
  
97
345
}