reactos/rosapps/roscalc/utl_mpfr.c
Timo Kreuzer ca60bdfbe8 New version of calc written by Carlo Bramini (carlo(dot)bramix AT libero.it)
Better than the one we currently have. For now in rosapps, so we can test it, if it's all working fine, we should replace the wine one.
Changes by me: use pow() instead of cbrt(), as cbrt doesn't work in our tree.
I imported the whole codebase, although the mpfr files are not used.
I moved the localizations to "lang" and the icons to "res" subfolder.

svn path=/trunk/; revision=31512
2007-12-31 05:51:52 +00:00

132 lines
3.6 KiB
C

#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;
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:
#define 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';
}
#undef MAX_LD_WIDTH
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] = TEXT('0');
temp[1] = TEXT('\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; q<n; q++)
buffer[n-q-1] = (temp[q] == '1') ? TEXT('1') : TEXT('0');
buffer[n] = TEXT('\0');
mpz_clear(zz);
mpf_clear(ff);
return;
}
mpz_clear(zz);
mpf_clear(ff);
_sntprintf(buffer, SIZEOF(calc.buffer), TEXT("%s"), temp);
}
void convert_text2number_2(calc_number_t *a)
{
int base;
#ifdef UNICODE
int sz;
char *temp;
#endif
switch (calc.base) {
case IDC_RADIO_HEX: base = 16; break;
case IDC_RADIO_DEC: base = 10; break;
case IDC_RADIO_OCT: base = 8; break;
case IDC_RADIO_BIN: base = 2; break;
default: return;
}
#ifdef UNICODE
/*
* libmpfr and libgmp accept only ascii chars.
*/
sz = WideCharToMultiByte(CP_ACP, 0, calc.buffer, -1, NULL, 0, NULL, NULL);
if (!sz)
return;
temp = (char *)_alloca(sz);
sz = WideCharToMultiByte(CP_ACP, 0, calc.buffer, -1, temp, sz, NULL, NULL);
mpfr_strtofr(a->mf, 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;
}
}