xref: /reactos/base/applications/calc/utl_ieee.c (revision 5140a990)
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         StringCchPrintf(buffer, size, _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             StringCchPrintf(buffer, size, _T("%#.*e"), MAX_LD_WIDTH-1, rpn->f);
44         else {
45             TCHAR *ptr, *dst;
46 
47             StringCchPrintfEx(buffer, size, &ptr, NULL, 0, _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         StringCchPrintf(buffer, size, _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 }
128