/* Copyright (C) 2015 Fredrik Johansson This file is part of Arb. Arb is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include #include #include "arb.h" static int arb_set_float_str(arb_t res, const char * inp, slong prec) { char * emarker; char * buf; int error; slong i; fmpz_t exp; fmpz_t man; slong num_int, num_frac; int after_radix; if (inp[0] == '+') { return arb_set_float_str(res, inp + 1, prec); } if (inp[0] == '-') { error = arb_set_float_str(res, inp + 1, prec); arb_neg(res, res); return error; } if (strcmp(inp, "inf") == 0) { arb_pos_inf(res); return 0; } if (strcmp(inp, "nan") == 0) { arb_indeterminate(res); return 0; } error = 0; fmpz_init(exp); fmpz_init(man); buf = flint_malloc(strlen(inp) + 1); emarker = strchr(inp, 'e'); /* parse exponent (0 by default) */ if (emarker != NULL) { /* allow e+42 as well as e42 */ if (emarker[1] == '+') { if (!(emarker[2] >= '0' && emarker[2] <= '9')) error = 1; else error = fmpz_set_str(exp, emarker + 2, 10); } else error = fmpz_set_str(exp, emarker + 1, 10); if (error) goto cleanup; } /* parse floating-point part */ { num_int = 0; num_frac = 0; after_radix = 0; for (i = 0; inp + i != emarker && inp[i] != '\0'; i++) { if (inp[i] == '.' && !after_radix) { after_radix = 1; } else if (inp[i] >= '0' && inp[i] <= '9') { buf[num_int + num_frac] = inp[i]; num_frac += after_radix; num_int += !after_radix; } else { error = 1; goto cleanup; } } buf[num_int + num_frac] = '\0'; /* put trailing zeros into the exponent */ while (num_int + num_frac > 1 && buf[num_int + num_frac - 1] == '0') { buf[num_int + num_frac - 1] = '\0'; num_frac--; } fmpz_sub_si(exp, exp, num_frac); error = fmpz_set_str(man, buf, 10); if (error) goto cleanup; } if (fmpz_is_zero(man)) { arb_zero(res); } else if (fmpz_is_zero(exp)) { arb_set_round_fmpz(res, man, prec); } else { arb_t t; arb_init(t); arb_set_ui(t, 10); arb_set_fmpz(res, man); if (fmpz_sgn(exp) > 0) { arb_pow_fmpz_binexp(t, t, exp, prec + 4); arb_mul(res, res, t, prec); } else { fmpz_neg(exp, exp); arb_pow_fmpz_binexp(t, t, exp, prec + 4); arb_div(res, res, t, prec); } arb_clear(t); } cleanup: fmpz_clear(exp); fmpz_clear(man); flint_free(buf); if (error) arb_indeterminate(res); return error; } int arb_set_str(arb_t res, const char * inp, slong prec) { char * buf; char * split; char * first; char * last; slong i, len; int error; error = 0; len = strlen(inp); buf = flint_malloc(len + 1); for (i = 0; i <= len; i++) buf[i] = tolower(inp[i]); split = strstr(buf, "+/-"); if (split == NULL) { /* strip whitespace and brackets */ first = buf; while (isspace(first[0]) || first[0] == '[') first++; last = buf + len; while (last - first > 0 && (isspace(last[-1]) || last[-1] == ']')) last--; last[0] = '\0'; error = arb_set_float_str(res, first, prec); } else { arb_t rad; arb_init(rad); /* strip whitespace and brackets */ first = buf; while (isspace(first[0]) || first[0] == '[') first++; last = split; while (last - first > 0 && (isspace(last[-1]) || last[-1] == ']')) last--; last[0] = '\0'; if (first == last) arb_zero(res); else error = arb_set_float_str(res, first, prec); if (!error) { /* strip whitespace and brackets */ first = split + 3; while (isspace(first[0]) || first[0] == '[') first++; last = buf + len; while (last - first > 0 && (isspace(last[-1]) || last[-1] == ']')) last--; last[0] = '\0'; error = arb_set_float_str(rad, first, prec); arb_abs(rad, rad); arb_add_error(res, rad); } arb_clear(rad); } flint_free(buf); return error; }