diff options
author | zimmerma <zimmerma@280ebfd0-de03-0410-8827-d642c229c3f4> | 2000-05-25 15:28:50 +0000 |
---|---|---|
committer | zimmerma <zimmerma@280ebfd0-de03-0410-8827-d642c229c3f4> | 2000-05-25 15:28:50 +0000 |
commit | 80f6cfc62657e7e4c5df6128476546503e615fbc (patch) | |
tree | f6f09a36bce5e7c1a330f3bb27be2e3b34042e2e /set_str.c | |
parent | f523fc19ff465108328380c9b5b6fcf73e432e3f (diff) | |
download | mpfr-80f6cfc62657e7e4c5df6128476546503e615fbc.tar.gz |
initial version
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@560 280ebfd0-de03-0410-8827-d642c229c3f4
Diffstat (limited to 'set_str.c')
-rw-r--r-- | set_str.c | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/set_str.c b/set_str.c new file mode 100644 index 000000000..97c6a95d1 --- /dev/null +++ b/set_str.c @@ -0,0 +1,154 @@ +/* mpfr_set_str -- set a floating-point number from a string + +Copyright (C) 2000 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#ifdef HAS_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" + +int +#if __STDC__ +mpfr_set_str(mpfr_ptr x, char *str, int base, mp_rnd_t rnd_mode) +#else +mpfr_set_str_raw(x, str, base, rnd_mode) + mpfr_ptr x; + char *str; + int base; + mp_rnd_t rnd_mode; +#endif +{ + char negative = 0, *endptr; + unsigned long k = 0, l, q; + long expn = 0, e; + mpz_t mantissa; + mpfr_t y, z; + + mpz_init(mantissa); mpz_set_ui(mantissa, 0); + l = strlen(str); + if (*str == '-') { negative = 1; str++; l--; } + else if (*str == '+') { str++; l--; } + + while (*str == '0') { str++; l--; } /* skip initial zeros */ + + /* allowed characters are '0' to '0'+base-1 if base <= 10, + and '0' to '9' plus 'a' to 'a'+base-11 if 10 < base <= 36 */ + while ((isdigit(*str) && *str < '0'+base) + || (islower(*str) && *str < 'a'+base-10)) + { + mpz_mul_ui(mantissa, mantissa, base); + mpz_add_ui(mantissa, mantissa, (isdigit(*str)) ? (*str)-'0' + : (*str)-'a'+10); + str++; l--; + } + + /* k is the number of non-zero digits before the decimal point */ + + if (*str == '.') + { + str++; l--; + while ((isdigit(*str) && *str < '0'+base) + || (islower(*str) && *str < 'a'+base-10)) + { + mpz_mul_ui(mantissa, mantissa, base); + mpz_add_ui(mantissa, mantissa, (isdigit(*str)) ? (*str)-'0' + : (*str)-'a'+10); + str++; l--; + k++; + } + } + + if ((base <= 10 && (*str == 'e' || *str == 'E')) || *str == '@') + { + str++; l--; + e = strtol(str, &endptr, 10); /* signed exponent after 'e', 'E' or '@' */ + expn = e - k; + if (expn > e) + fprintf(stderr, "Warning: exponent underflow in mpfr_set_str\n"); + } + else if (l) { + fprintf(stderr, "Unexpected end of string in mpfr_set_str: %s\n", str); + return -1; + } + else { + expn = -k; + endptr = str; + } + + /* the number is mantissa*base^expn */ + + q = (PREC(x)/BITS_PER_MP_LIMB)*BITS_PER_MP_LIMB; + mpfr_init(y); + mpfr_init(z); + + do { + q += BITS_PER_MP_LIMB; + mpfr_set_prec(y, q); + mpfr_set_z(y, mantissa, GMP_RNDN); /* error <= 1/2*ulp(y) */ + + mpfr_set_prec(z, q); + if (expn>0) { + e = mpfr_ui_pow_ui(z, base, expn, GMP_RNDN); + mpfr_mul(y, y, z, GMP_RNDN); + } + else if (expn<0) { + e = mpfr_ui_pow_ui(z, base, -expn, GMP_RNDN); + mpfr_div(y, y, z, GMP_RNDN); + } + else e=1; + if (negative) mpfr_neg(y, y, GMP_RNDN); + + /* now y is an approximation of mantissa*base^expn with error at most + 2^e*ulp(y) */ + + } while (mpfr_can_round(y, q-e, GMP_RNDN, rnd_mode, PREC(x))==0 + && q<=2*PREC(x)); + + mpfr_set(x, y, rnd_mode); + + mpz_clear(mantissa); + mpfr_clear(y); + mpfr_clear(z); + return ((*endptr=='\0') ? 0 : -1); +} + +int +#if __STDC__ +mpfr_init_set_str(mpfr_ptr x, char *str, int base, mp_rnd_t rnd_mode) +#else +mpfr_init_set_str_raw(x, str, base, rnd_mode) + mpfr_ptr x; + char *str; + int base; + mp_rnd_t rnd_mode; +#endif +{ + mpfr_init(x); + return mpfr_set_str(x, str, base, rnd_mode); +} + |