/* * ReactOS Calc (Utility functions for GMP/MPFR engine) * * Copyright 2007-2017, Carlo Bramini * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "calc.h" void prepare_rpn_result_2(calc_number_t *rpn, TCHAR *buffer, int size, int base) { char temp[1024]; char *ptr, *dst; int width, max_ld_width; unsigned long int n, q; mpz_t zz; mpf_t ff; mpz_init(zz); mpf_init(ff); mpfr_get_z(zz, rpn->mf, MPFR_DEFAULT_RND); mpfr_get_f(ff, rpn->mf, MPFR_DEFAULT_RND); switch (base) { case IDC_RADIO_HEX: gmp_sprintf(temp, "%ZX", zz); break; case IDC_RADIO_DEC: /* * The output display is much shorter in standard mode, * so I'm forced to reduce the precision here :( */ if (calc.layout == CALC_LAYOUT_STANDARD) max_ld_width = 16; else max_ld_width = 64; /* calculate the width of integer number */ if (mpf_sgn(ff) == 0) width = 1; else { mpfr_t t; mpfr_init(t); mpfr_abs(t, rpn->mf, MPFR_DEFAULT_RND); mpfr_log10(t, t, MPFR_DEFAULT_RND); width = 1 + mpfr_get_si(t, MPFR_DEFAULT_RND); mpfr_clear(t); } if (calc.sci_out == TRUE || width > max_ld_width || width < -max_ld_width) ptr = temp + gmp_sprintf(temp, "%*.*#Fe", 1, max_ld_width, ff); else { ptr = temp + gmp_sprintf(temp, "%#*.*Ff", width, ((max_ld_width-width-1)>=0) ? max_ld_width-width-1 : 0, ff); dst = strchr(temp, '.'); while (--ptr > dst) if (*ptr != '0') break; /* put the string terminator for removing the final '0' (if any) */ ptr[1] = '\0'; /* check if the number finishes with '.' */ if (ptr == dst) /* remove the dot (it will be re-added later) */ ptr[0] = '\0'; } break; case IDC_RADIO_OCT: gmp_sprintf(temp, "%Zo", zz); break; case IDC_RADIO_BIN: /* if the number is zero, just write 0 ;) */ if (rpn_is_zero(rpn)) { temp[0] = _T('0'); temp[1] = _T('\0'); break; } /* repeat until a bit set to '1' is found */ n = 0; do { q = mpz_scan1(zz, n); if (q == ULONG_MAX) break; while (n < q) temp[n++] = '0'; temp[n++] = '1'; } while (1); /* now revert the string into TCHAR buffer */ for (q=0; qmf, temp, NULL, base, MPFR_DEFAULT_RND); #else mpfr_strtofr(a->mf, calc.buffer, NULL, base, MPFR_DEFAULT_RND); #endif } void convert_real_integer(unsigned int base) { switch (base) { case IDC_RADIO_DEC: break; case IDC_RADIO_OCT: case IDC_RADIO_BIN: case IDC_RADIO_HEX: if (calc.base == IDC_RADIO_DEC) { mpfr_trunc(calc.code.mf, calc.code.mf); apply_int_mask(&calc.code); } break; } }