[CALC] Improve multi-precision support, and powers/roots. CORE-8486
[reactos.git] / base / applications / calc / utl_ieee.c
1 /*
2 * ReactOS Calc (Utility functions for IEEE-754 engine)
3 *
4 * Copyright 2007-2017, Carlo Bramini
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "calc.h"
22
23 void prepare_rpn_result_2(calc_number_t *rpn, TCHAR *buffer, int size, int base)
24 {
25 calc_number_t tmp;
26 int width;
27
28 switch (base) {
29 case IDC_RADIO_HEX:
30 _stprintf(buffer, _T("%I64X"), rpn->i);
31 break;
32 case IDC_RADIO_DEC:
33 /*
34 * Modified from 17 to 16 for fixing this bug:
35 * 14+14+6.3+6.3= 40.5999999 instead of 40.6
36 * So, it's probably better to leave the least
37 * significant digit out of the display.
38 */
39 #define MAX_LD_WIDTH 16
40 /* calculate the width of integer number */
41 width = (rpn->f==0) ? 1 : (int)log10(fabs(rpn->f))+1;
42 if (calc.sci_out == TRUE || width > MAX_LD_WIDTH || width < -MAX_LD_WIDTH)
43 _stprintf(buffer, _T("%#.*e"), MAX_LD_WIDTH-1, rpn->f);
44 else {
45 TCHAR *ptr, *dst;
46
47 ptr = buffer + _stprintf(buffer, _T("%#*.*f"), width, ((MAX_LD_WIDTH-width-1)>=0) ? MAX_LD_WIDTH-width-1 : 0, rpn->f);
48 /* format string ensures there is a '.': */
49 dst = _tcschr(buffer, _T('.'));
50 while (--ptr > dst)
51 if (*ptr != _T('0'))
52 break;
53
54 /* put the string terminator for removing the final '0' (if any) */
55 ptr[1] = _T('\0');
56 /* check if the number finishes with '.' */
57 if (ptr == dst)
58 /* remove the dot (it will be re-added later) */
59 ptr[0] = _T('\0');
60 }
61 #undef MAX_LD_WIDTH
62 break;
63 case IDC_RADIO_OCT:
64 _stprintf(buffer, _T("%I64o"), rpn->i);
65 break;
66 case IDC_RADIO_BIN:
67 if (rpn->i == 0) {
68 buffer[0] = _T('0');
69 buffer[1] = _T('\0');
70 break;
71 }
72 tmp = *rpn;
73 buffer[0] = _T('\0');
74 while (tmp.u) {
75 memmove(buffer+1, buffer, (size-1)*sizeof(TCHAR));
76 if (tmp.u & 1)
77 buffer[0] = _T('1');
78 else
79 buffer[0] = _T('0');
80 tmp.u >>= 1;
81 }
82 break;
83 }
84 }
85
86 void convert_text2number_2(calc_number_t *a)
87 {
88 TCHAR *ptr;
89
90 switch (calc.base) {
91 case IDC_RADIO_HEX:
92 _stscanf(calc.buffer, _T("%I64X"), &(a->i));
93 break;
94 case IDC_RADIO_DEC:
95 _stscanf(calc.buffer, _T("%lf"), &(a->f));
96 break;
97 case IDC_RADIO_OCT:
98 _stscanf(calc.buffer, _T("%I64o"), &(a->i));
99 break;
100 case IDC_RADIO_BIN:
101 ptr = calc.buffer;
102 a->i = 0;
103 while (*ptr != _T('\0')) {
104 a->i <<= 1;
105 if (*ptr++ == _T('1'))
106 a->i |= 1;
107 }
108 break;
109 }
110 }
111
112 void convert_real_integer(unsigned int base)
113 {
114 switch (base) {
115 case IDC_RADIO_DEC:
116 calc.code.f = (double)calc.code.i;
117 break;
118 case IDC_RADIO_OCT:
119 case IDC_RADIO_BIN:
120 case IDC_RADIO_HEX:
121 if (calc.base == IDC_RADIO_DEC) {
122 calc.code.i = (__int64)calc.code.f;
123 apply_int_mask(&calc.code);
124 }
125 break;
126 }
127 }