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