Updated kn translations
[gcalctool.git] / src / serializer.vala
blobfc389df6194a9951e654ffdf1c7e51e0cd7e1199
1 /*
2 * Copyright (C) 2010 Robin Sonefors
3 * Copyright (C) 2008-2012 Robert Ancell.
5 * This program is free software: you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation, either version 2 of the License, or (at your option) any later
8 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9 * license.
12 public enum DisplayFormat
14 AUTOMATIC,
15 FIXED,
16 SCIENTIFIC,
17 ENGINEERING
20 public class Serializer : Object
22 private int leading_digits; /* Number of digits to show before radix */
23 private int trailing_digits; /* Number of digits to show after radix */
24 private DisplayFormat format; /* Number display mode. */
25 private bool show_tsep; /* Set if the thousands separator should be shown. */
26 private bool show_zeroes; /* Set if trailing zeroes should be shown. */
28 private int number_base; /* Numeric base */
30 private unichar radix; /* Locale specific radix string. */
31 private unichar tsep; /* Locale specific thousands separator. */
32 private int tsep_count; /* Number of digits between separator. */
34 public Serializer (DisplayFormat format, int number_base, int trailing_digits)
36 var radix_string = nl_langinfo (NLItem.RADIXCHAR);
37 if (radix_string != null && radix_string != "")
38 radix = radix_string.locale_to_utf8 (-1, null, null).get_char (0);
39 else
40 radix = '.';
41 var tsep_string = nl_langinfo (NLItem.THOUSEP);
42 if (tsep_string != null && tsep_string != "")
43 tsep = tsep_string.locale_to_utf8 (-1, null, null).get_char (0);
44 else
45 tsep = ' ';
46 tsep_count = 3;
48 this.number_base = number_base;
49 leading_digits = 12;
50 this.trailing_digits = trailing_digits;
51 show_zeroes = false;
52 show_tsep = false;
53 this.format = format;
56 public string to_string (Number x)
58 switch (format)
60 default:
61 case DisplayFormat.AUTOMATIC:
62 int n_digits = 0;
63 var s0 = cast_to_string (x, ref n_digits);
64 if (n_digits <= leading_digits)
65 return s0;
66 else
67 return cast_to_exponential_string (x, false, ref n_digits);
68 case DisplayFormat.FIXED:
69 int n_digits = 0;
70 return cast_to_string (x, ref n_digits);
71 case DisplayFormat.SCIENTIFIC:
72 int n_digits = 0;
73 return cast_to_exponential_string (x, false, ref n_digits);
74 case DisplayFormat.ENGINEERING:
75 int n_digits = 0;
76 return cast_to_exponential_string (x, true, ref n_digits);
80 public Number? from_string (string str)
82 // FIXME: Move mp_set_from_string into here
83 return mp_set_from_string (str, number_base);
86 public void set_base (int number_base)
88 this.number_base = number_base;
91 public int get_base ()
93 return number_base;
96 public void set_radix (unichar radix)
98 this.radix = radix;
101 public unichar get_radix ()
103 return radix;
106 public void set_thousands_separator (unichar separator)
108 tsep = separator;
111 public unichar get_thousands_separator ()
113 return tsep;
116 public int get_thousands_separator_count ()
118 return tsep_count;
121 public void set_show_thousands_separators (bool visible)
123 show_tsep = visible;
126 public bool get_show_thousands_separators ()
128 return show_tsep;
131 public void set_show_trailing_zeroes (bool visible)
133 show_zeroes = visible;
136 public bool get_show_trailing_zeroes ()
138 return show_zeroes;
141 public int get_leading_digits ()
143 return leading_digits;
146 public void set_leading_digits (int leading_digits)
148 this.leading_digits = leading_digits;
151 public int get_trailing_digits ()
153 return trailing_digits;
156 public void set_trailing_digits (int trailing_digits)
158 this.trailing_digits = trailing_digits;
161 public DisplayFormat get_number_format ()
163 return format;
166 public void set_number_format (DisplayFormat format)
168 this.format = format;
171 private string cast_to_string (Number x, ref int n_digits)
173 var string = new StringBuilder.sized (1024);
175 var x_real = x.real_component ();
176 cast_to_string_real (x_real, number_base, false, ref n_digits, string);
177 if (x.is_complex ())
179 var x_im = x.imaginary_component ();
181 var force_sign = true;
182 if (string.str == "0")
184 string.assign ("");
185 force_sign = false;
188 var s = new StringBuilder.sized (1024);
189 int n_complex_digits = 0;
190 cast_to_string_real (x_im, 10, force_sign, ref n_complex_digits, s);
191 if (n_complex_digits > n_digits)
192 n_digits = n_complex_digits;
193 if (s.str == "0" || s.str == "+0" || s.str == "−0")
195 /* Ignore */
197 else if (s.str == "1")
199 string.append ("i");
201 else if (s.str == "+1")
203 string.append ("+i");
205 else if (s.str == "−1")
207 string.append ("−i");
209 else
211 if (s.str == "+0")
212 string.append ("+");
213 else if (s.str != "0")
214 string.append (s.str);
216 string.append ("i");
220 return string.str;
223 private void cast_to_string_real (Number x, int number_base, bool force_sign, ref int n_digits, StringBuilder string)
225 const char digits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
227 var number = x;
228 if (number.is_negative ())
229 number = number.abs ();
231 /* Add rounding factor */
232 var temp = new Number.integer (number_base);
233 temp = temp.xpowy_integer (-(trailing_digits+1));
234 temp = temp.multiply_integer (number_base);
235 temp = temp.divide_integer (2);
236 var rounded_number = number.add (temp);
238 /* Write out the integer component least significant digit to most */
239 temp = rounded_number.floor ();
240 var i = 0;
243 if (this.number_base == 10 && show_tsep && i == tsep_count)
245 string.prepend_unichar (tsep);
246 i = 0;
248 i++;
250 var t = temp.divide_integer (number_base);
251 t = t.floor ();
252 var t2 = t.multiply_integer (number_base);
254 var t3 = temp.subtract (t2);
256 var d = t3.to_integer ();
257 string.prepend_c (d < 16 ? digits[d] : '?');
258 n_digits++;
260 temp = t;
261 } while (!temp.is_zero ());
263 var last_non_zero = string.len;
265 string.append_unichar (radix);
267 /* Write out the fractional component */
268 temp = rounded_number.fractional_component ();
269 for (i = 0; i < trailing_digits; i++)
271 if (temp.is_zero ())
272 break;
274 temp = temp.multiply_integer (number_base);
275 var digit = temp.floor ();
276 var d = digit.to_integer ();
278 string.append_c (digits[d]);
280 if (d != 0)
281 last_non_zero = string.len;
282 temp = temp.subtract (digit);
285 /* Strip trailing zeroes */
286 if (!show_zeroes || trailing_digits == 0)
287 string.truncate (last_non_zero);
289 /* Add sign on non-zero values */
290 if (string.str != "0" || force_sign)
292 if (x.is_negative ())
293 string.prepend ("−");
294 else if (force_sign)
295 string.prepend ("+");
298 /* Append base suffix if not in default base */
299 if (number_base != this.number_base)
301 const string sub_digits[] = {"₀", "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉"};
302 int multiplier = 1;
303 int b = number_base;
305 while (number_base / multiplier != 0)
306 multiplier *= 10;
307 while (multiplier != 1)
309 int d;
310 multiplier /= 10;
311 d = b / multiplier;
312 string.append (sub_digits[d]);
313 b -= d * multiplier;
318 private int cast_to_exponential_string_real (Number x, StringBuilder string, bool eng_format, ref int n_digits)
320 if (x.is_negative ())
321 string.append ("−");
323 var mantissa = x.abs ();
325 var base_ = new Number.integer (number_base);
326 var base3 = base_.xpowy_integer (3);
327 var base10 = base_.xpowy_integer (10);
328 var t = new Number.integer (1);
329 var base10inv = t.divide (base10);
331 var exponent = 0;
332 if (!mantissa.is_zero ())
334 while (!eng_format && mantissa.compare (base10) >= 0)
336 exponent += 10;
337 mantissa = mantissa.multiply (base10inv);
340 while ((!eng_format && mantissa.compare (base_) >= 0) ||
341 (eng_format && (mantissa.compare (base3) >= 0 || exponent % 3 != 0)))
343 exponent += 1;
344 mantissa = mantissa.divide (base_);
347 while (!eng_format && mantissa.compare (base10inv) < 0)
349 exponent -= 10;
350 mantissa = mantissa.multiply (base10);
353 t = new Number.integer (1);
354 while (mantissa.compare (t) < 0 || (eng_format && exponent % 3 != 0))
356 exponent -= 1;
357 mantissa = mantissa.multiply (base_);
361 string.append (cast_to_string (mantissa, ref n_digits));
363 return exponent;
366 private string cast_to_exponential_string (Number x, bool eng_format, ref int n_digits)
368 var string = new StringBuilder.sized (1024);
370 var x_real = x.real_component ();
371 var exponent = cast_to_exponential_string_real (x_real, string, eng_format, ref n_digits);
372 append_exponent (string, exponent);
374 if (x.is_complex ())
376 var x_im = x.imaginary_component ();
378 if (string.str == "0")
379 string.assign ("");
381 var s = new StringBuilder.sized (1024);
382 int n_complex_digits = 0;
383 exponent = cast_to_exponential_string_real (x_im, s, eng_format, ref n_complex_digits);
384 if (n_complex_digits > n_digits)
385 n_digits = n_complex_digits;
386 if (s.str == "0" || s.str == "+0" || s.str == "−0")
388 /* Ignore */
390 else if (s.str == "1")
392 string.append ("i");
394 else if (s.str == "+1")
396 string.append ("+i");
398 else if (s.str == "−1")
400 string.append ("−i");
402 else
404 if (s.str == "+0")
405 string.append ("+");
406 else if (s.str != "0")
407 string.append (s.str);
409 string.append ("i");
411 append_exponent (string, exponent);
414 return string.str;
417 private void append_exponent (StringBuilder string, int exponent)
419 const unichar super_digits[] = {'⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹'};
421 if (exponent == 0)
422 return;
424 string.append ("×10"); // FIXME: Use the current base
425 if (exponent < 0)
427 exponent = -exponent;
428 string.append_unichar ('⁻');
431 var super_value = "%d".printf (exponent);
432 for (var i = 0; i < super_value.length; i++)
433 string.append_unichar (super_digits[super_value[i] - '0']);