sync with trunk r46493
[reactos.git] / base / applications / calc / utl_mpfr.c
1 #include "calc.h"
2
3 void prepare_rpn_result_2(calc_number_t *rpn, TCHAR *buffer, int size, int base)
4 {
5 char temp[1024];
6 char *ptr, *dst;
7 int width, max_ld_width;
8 unsigned long int n, q;
9 mpz_t zz;
10 mpf_t ff;
11
12 mpz_init(zz);
13 mpf_init(ff);
14 mpfr_get_z(zz, rpn->mf, MPFR_DEFAULT_RND);
15 mpfr_get_f(ff, rpn->mf, MPFR_DEFAULT_RND);
16
17 switch (base) {
18 case IDC_RADIO_HEX:
19 gmp_sprintf(temp, "%ZX", zz);
20 break;
21 case IDC_RADIO_DEC:
22 /*
23 * The output display is much shorter in standard mode,
24 * so I'm forced to reduce the precision here :(
25 */
26 if (calc.layout == CALC_LAYOUT_STANDARD)
27 max_ld_width = 16;
28 else
29 max_ld_width = 64;
30
31 /* calculate the width of integer number */
32 if (mpf_sgn(ff) == 0)
33 width = 1;
34 else {
35 mpfr_t t;
36 mpfr_init(t);
37 mpfr_abs(t, rpn->mf, MPFR_DEFAULT_RND);
38 mpfr_log10(t, t, MPFR_DEFAULT_RND);
39 width = 1 + mpfr_get_si(t, MPFR_DEFAULT_RND);
40 mpfr_clear(t);
41 }
42 if (calc.sci_out == TRUE || width > max_ld_width || width < -max_ld_width)
43 ptr = temp + gmp_sprintf(temp, "%*.*#Fe", 1, max_ld_width, ff);
44 else {
45 ptr = temp + gmp_sprintf(temp, "%#*.*Ff", width, ((max_ld_width-width-1)>=0) ? max_ld_width-width-1 : 0, ff);
46 dst = strchr(temp, '.');
47 while (--ptr > dst)
48 if (*ptr != '0')
49 break;
50
51 /* put the string terminator for removing the final '0' (if any) */
52 ptr[1] = '\0';
53 /* check if the number finishes with '.' */
54 if (ptr == dst)
55 /* remove the dot (it will be re-added later) */
56 ptr[0] = '\0';
57 }
58 break;
59 case IDC_RADIO_OCT:
60 gmp_sprintf(temp, "%Zo", zz);
61 break;
62 case IDC_RADIO_BIN:
63 /* if the number is zero, just write 0 ;) */
64 if (rpn_is_zero(rpn)) {
65 temp[0] = TEXT('0');
66 temp[1] = TEXT('\0');
67 break;
68 }
69 /* repeat until a bit set to '1' is found */
70 n = 0;
71 do {
72 q = mpz_scan1(zz, n);
73 if (q == ULONG_MAX)
74 break;
75 while (n < q)
76 temp[n++] = '0';
77 temp[n++] = '1';
78 } while (1);
79 /* now revert the string into TCHAR buffer */
80 for (q=0; q<n; q++)
81 buffer[n-q-1] = (temp[q] == '1') ? TEXT('1') : TEXT('0');
82 buffer[n] = TEXT('\0');
83
84 mpz_clear(zz);
85 mpf_clear(ff);
86 return;
87 }
88 mpz_clear(zz);
89 mpf_clear(ff);
90 _sntprintf(buffer, SIZEOF(calc.buffer), TEXT("%s"), temp);
91 }
92
93 void convert_text2number_2(calc_number_t *a)
94 {
95 int base;
96 #ifdef UNICODE
97 int sz;
98 char *temp;
99 #endif
100
101 switch (calc.base) {
102 case IDC_RADIO_HEX: base = 16; break;
103 case IDC_RADIO_DEC: base = 10; break;
104 case IDC_RADIO_OCT: base = 8; break;
105 case IDC_RADIO_BIN: base = 2; break;
106 default: return;
107 }
108 #ifdef UNICODE
109 /*
110 * libmpfr and libgmp accept only ascii chars.
111 */
112 sz = WideCharToMultiByte(CP_ACP, 0, calc.buffer, -1, NULL, 0, NULL, NULL);
113 if (!sz)
114 return;
115 temp = (char *)_alloca(sz);
116 sz = WideCharToMultiByte(CP_ACP, 0, calc.buffer, -1, temp, sz, NULL, NULL);
117 mpfr_strtofr(a->mf, temp, NULL, base, MPFR_DEFAULT_RND);
118 #else
119 mpfr_strtofr(a->mf, calc.buffer, NULL, base, MPFR_DEFAULT_RND);
120 #endif
121 }
122
123 void convert_real_integer(unsigned int base)
124 {
125 switch (base) {
126 case IDC_RADIO_DEC:
127 break;
128 case IDC_RADIO_OCT:
129 case IDC_RADIO_BIN:
130 case IDC_RADIO_HEX:
131 if (calc.base == IDC_RADIO_DEC) {
132 mpfr_trunc(calc.code.mf, calc.code.mf);
133 apply_int_mask(&calc.code);
134 }
135 break;
136 }
137 }
138