/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-16 18:17:41 UTC
  • Revision ID: gustav.hartvigsson@gmail.com-20210916181741-9t8ba6lmbxty621o
EOF
Re-Wrote FastNumber

Dealinng with users being able to set their own decmial
part of the number is not viable. So don't let the user
do it.

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
   *            [non-decial part  | decimal]
24
24
   * }}}
25
25
   *
26
 
   * Due to how some things work here, we can't reliably use the decimal part
27
 
   * that referents a value less than 0.1. That is, like 5.05 will not work
28
 
   * reliably.
29
26
   */
30
27
  public struct FastNumber {
31
 
    /* FIXME
32
 
     *
33
 
     * The limitations in the comment above is something
34
 
     * that needs to be fixed.
35
 
     *
36
 
     * Look into a different representation?
37
 
     *
38
 
     * Perhaps only use  raw_number ?
39
 
     *
40
 
     * Perhaps ripping out the things that are not needed?
41
 
     *
42
 
     * Implement BCD?
43
 
     */
44
28
    
45
29
    /** Precision used to output values */
46
30
    public const int PRECISION_DIGITS = 2;
52
36
    
53
37
    public long raw_number;
54
38
    
 
39
    public long leading_zeros;
 
40
    
 
41
    /* XXX
 
42
     * I'm not happy using getters/setters in this struct...
 
43
     * But I tink it'll have to do for simplicity.
 
44
     */
55
45
    public long number {
56
46
      public get {return (this.raw_number / MUL_FACTOR);}
57
 
      public set {this.raw_number = (MUL_FACTOR * value);}
58
 
    }
59
 
    
60
 
    /**
61
 
     * Due to implementation details, and how the numbers are normalised,
62
 
     * this value might be wrong.
63
 
     */
64
 
    public long decimal {
65
 
      public get {return mask_and_normalize_decimal (raw_number);}
66
 
      public set {set_decimal_of_number (ref raw_number, value);}
67
 
    }
68
 
    
69
 
    public double float_rep {
70
 
      public get {
71
 
        long dec = this.decimal;
72
 
        long nbr = this.number;
73
 
        // debug (@"(float_ret_get) Float str: $nbr.$dec");
74
 
        return double.parse (@"$nbr.$dec");
75
 
      } public set {
76
 
        // debug (@"(float_ret_set) set float: $value");
77
 
        this.raw_number = parse_raw_number (value.to_string ());
 
47
      public set {
 
48
        this.raw_number = (MUL_FACTOR * value);
78
49
      }
79
50
    }
80
51
    
90
61
     * 
91
62
     * @param decimal  The decimal part of the number. Defaults to 0.
92
63
     */
93
 
    public FastNumber (long number = 0, int decimal = 0) {
94
 
      if (! (number == 0))  this.number = number;
95
 
      if (! (decimal == 0)) this.decimal = decimal;
 
64
    public FastNumber (long number = 0) {
 
65
      if (number != 0) {
 
66
        this.raw_number = (number * MUL_FACTOR);
 
67
      } else {
 
68
        this.raw_number = 0;
 
69
      }
96
70
    }
97
71
    
98
72
    /**
108
82
     * Can be a decimal representation.
109
83
     */
110
84
    public FastNumber.from_string (string str) {
111
 
      this.raw_number = parse_raw_number (str);
112
 
    }
113
 
    
114
 
    /**
115
 
     * Initialises a FastNumber from a double floating point value.
116
 
     * 
117
 
     * Due to how floating point numbers works this may not be the exact value
118
 
     * you expect it to be.
119
 
     */
120
 
    public FastNumber.from_float (double f) {
121
 
      this.raw_number = parse_raw_number (f.to_string ());
122
 
    }
123
 
    
 
85
      parse_raw_number (str);
 
86
    }
124
87
    /**
125
88
     * Initialises a FastNumber with the internal representation of that number.
126
89
     */
128
91
      this.raw_number = raw;
129
92
    }
130
93
    
131
 
    /**
132
 
     * Sets the value of this FastNumber from a string, 
133
 
     */
134
 
    public void set_from_string (string str) {
135
 
      this.raw_number = parse_raw_number (str);
 
94
    public FastNumber.from_float (double float_number) {
 
95
      // XXX Do we need a faster way of doing this?
 
96
      parse_raw_number (float_number.to_string ()); 
136
97
    }
137
98
    
138
99
    /**
274
235
     *                the string. Default = false.
275
236
     */
276
237
    public string to_string (bool decimal = false) {
277
 
      if (decimal) {
278
 
        // FIXME: This will fail with decimal part less than 0.1..?
279
 
        return @"$number.$decimal";
 
238
      string ret_val = null;
 
239
      if (!decimal) {
 
240
        ret_val = (this.raw_number / MUL_FACTOR).to_string ();
280
241
      } else {
281
 
        return number.to_string ();
 
242
        // Copy stuff so we don't accidentality stomp them.
 
243
        long _raw_number = this.raw_number;
 
244
        
 
245
        long _integer_part = (_raw_number / MUL_FACTOR);
 
246
        long _decimal_part = (_raw_number - (_integer_part * MUL_FACTOR));
 
247
        
 
248
        var strbldr = new GLib.StringBuilder ();
 
249
        
 
250
        // normalise the decimal part.
 
251
        // (XXX This is rather expensive, is there a better way of doing this?).
 
252
        if (_decimal_part != 0) {
 
253
          while ((_decimal_part % 10) == 0) {
 
254
            _decimal_part = _decimal_part / 10;
 
255
          }
 
256
        }
 
257
        
 
258
        strbldr.append (_integer_part.to_string ())
 
259
               .append_c ('.');
 
260
        
 
261
        
 
262
        for ( var i = this.leading_zeros ; i > 0 ; i--) {
 
263
          strbldr.append_c ('0');
 
264
        }
 
265
        
 
266
        strbldr.append (_decimal_part.to_string ());
 
267
        
 
268
        ret_val = strbldr.str;
282
269
      }
283
 
    } 
 
270
      return ret_val;
 
271
    }
 
272
    
 
273
    public double to_float () {
 
274
      // XXX This probobly needs to something faster?
 
275
      return double.parse (this.to_string (true));
 
276
    }
 
277
    
 
278
    public long to_int () {
 
279
       return (this.raw_number / MUL_FACTOR);
 
280
    }
284
281
    
285
282
    /**
286
283
     * Check if two FastNumbers are equal.
292
289
      return (this.raw_number == other.raw_number);
293
290
    }
294
291
    
295
 
    // ***** STATIC FUNCTIONS ****//
296
 
    public static long parse_raw_number (string str) {
 
292
    
 
293
    [CCode (cname = "vqdr_common_fast_number_compare")]
 
294
    public static extern long static_compare (FastNumber a, FastNumber b);
 
295
    
 
296
    private void parse_raw_number (string str) {
 
297
      debug (@"(parse_raw_number) str: $str");
297
298
      long ret_val = 0;
298
299
      int i_of_dot = str.index_of_char ('.');
299
300
      if (i_of_dot >= 0) {
300
 
        
301
 
        // debug (@"str: $str");
302
301
        // Get the decimal number from the string, if such a thing exists.
303
302
        if ((str.length - 1 > i_of_dot)) {
304
 
          ret_val = long.parse ((str + "000").substring (i_of_dot + 1));
 
303
          var intr_str = (str + "000").substring (i_of_dot + 1);
 
304
          // count leading zeros.
 
305
          long i;
 
306
          for (i = 0; intr_str.@get (i) == '0'; i++){}
 
307
          this.leading_zeros = i;
 
308
          // remove leading zeros
 
309
          intr_str = intr_str.substring (i);
 
310
          debug (@"(parse_raw_number) Intermediate string: $intr_str");
 
311
          ret_val = long.parse (intr_str);
305
312
        }
306
313
        
307
314
        // debug (@"(parse_raw_number) i_of_dot: $i_of_dot, ret_val (decimal): $ret_val\n");
312
319
          // debug (@"(parse_raw_number) retval (loop): $ret_val");
313
320
        }
314
321
        
 
322
        for (var i = leading_zeros; i > 0; i--) {
 
323
          ret_val = ret_val / 10;
 
324
          // debug (@"(parse_raw_number) retval (loop2): $ret_val");
 
325
        }
 
326
        
315
327
        // debug (@"ret_val (normalised): $ret_val\n");
316
328
        
317
 
        // get intiger number
 
329
        // get integer number
318
330
        ret_val = ret_val + (long.parse (str.substring (0, i_of_dot))
319
331
                            * MUL_FACTOR);
320
332
        
321
 
        // debug (@"(parse_raw_number) ret_val (finished): $ret_val\n");
322
 
        
323
333
      } else {
324
 
        ret_val = long.parse (str) * MUL_FACTOR;
325
 
      }
326
 
      return ret_val;
327
 
    }
328
 
    
329
 
    public static long mask_and_normalize_decimal (long number) {
330
 
      // debug (@"(mask_and_normalize_decimal) number: $number");
331
 
      long mask = number / MUL_FACTOR;
332
 
      // debug (@"(mask_and_normalize_decimal) mask(1): $mask");
333
 
      mask = mask * MUL_FACTOR;
334
 
      // debug (@"(mask_and_normalize_decimal) mask(2): $mask");
335
 
      long ret = number - mask;
336
 
      // normalise
337
 
      // This is a rathor expensive operation.
338
 
      if (ret != 0) {
339
 
        while ((ret % 10) == 0) {
340
 
          ret = ret / 10;
341
 
        }
342
 
      }
343
 
      // debug (@"(mask_and_normalize_decimal) ret: $ret");
344
 
      return ret;
345
 
    }
346
 
    
347
 
    public static void set_decimal_of_number (ref long number, long decimal) {
348
 
      // debug (@"(set_decimal_of_number) number(0): $number, decimal(0): $decimal");
349
 
      long masked = number / MUL_FACTOR;
350
 
      // debug (@"(set_decimal_of_number) masked(1): $masked");
351
 
      masked = masked * MUL_FACTOR;
352
 
      // debug (@"(set_decimal_of_number) masked(2): $masked");
353
 
      
354
 
      // Normalise digits
355
 
      if (decimal != 0) {
356
 
        while (decimal < PRECISION_FACTOR) {
357
 
          decimal = decimal * 10;
358
 
          // debug (@"(set_decimal_of_number) loop, decimal: $decimal");
359
 
        }
360
 
      }
361
 
      
362
 
      number = masked + decimal;
363
 
      // debug (@"(set_decimal_of_number) number(1): $number");
364
 
      
365
 
    }
366
 
      
367
 
    [CCode (cname = "vqdr_common_fast_number_compare")]
368
 
    public static extern long static_compare (FastNumber a, FastNumber b);
 
334
        ret_val = (long.parse (str) * MUL_FACTOR);
 
335
      }
 
336
      debug (@"(parse_raw_number) ret_val (finished): $ret_val\n");
 
337
      this.raw_number = ret_val;
 
338
    }
369
339
  }
370
340
}