#ifdef HAVE_CONFIG_H #include "config.h" #else #define HAVE_MPFR_22 #endif #include #include #include #include /* for HUGE_VAL */ #include /* for DBL_EPSILON */ #include /* for isalpha() */ #if ! defined(HAVE_CONFIG_H) || HAVE_STRING_H # include /* for memset() */ #else # if !HAVE_STRCHR # define strchr index # define strrchr rindex # endif char *strchr(), *strrchr(); #endif #if ! defined(HAVE_CONFIG_H) || TIME_WITH_SYS_TIME /* for time() */ # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #include "number.h" #include "uint32_max.h" #include "calculator.h" #include "variables.h" #include "string_manip.h" #include "files.h" #include "number_formatting.h" #include "add_commas.h" #include "list.h" #include "extract_vars.h" #ifdef MEMWATCH #include "memwatch.h" #endif /* variables everyone needs to get to */ Number last_answer; char *pretty_answer = NULL; /* communication with the parser */ char compute = 1; unsigned int sig_figs = UINT32_MAX; /* communication with the frontend */ char standard_output = 1; char not_all_displayed = 0; char *pa = NULL; struct _conf conf; /* * These are declared here because they're not in any header files. * yyparse() is declared with an empty argument list so that it is * compatible with the generated C code from yacc/bison. * These two lines are taken from http://www.bgw.org/tutorials/programming/c/lex_yacc/main.c */ struct yy_buffer_state; extern int yyparse(); extern void *yy_scan_string(const char *); extern void yy_delete_buffer(struct yy_buffer_state *); static int recursion(char *str); static int find_recursion(char *); static int find_recursion_core(List); static char *flatten(char *str); void parseme(const char *pthis) { /*{{{ */ extern int synerrors; short numbers = 0; char *sanitized; extern char *open_file; synerrors = 0; compute = 1; sig_figs = UINT32_MAX; Dprintf("parsing: %s\n", pthis); sanitized = (char *)strdup(pthis); /* Convert to standard notation (american comma and period) if there are * numbers */ // are there numbers? { unsigned int i; for (i = 0; i < strlen(sanitized); ++i) { if (isdigit((int)(sanitized[i]))) { numbers = 1; break; } } } if (numbers) { unsigned int i; for (i = 0; i < strlen(sanitized); ++i) { if ((conf.thou_delimiter != '.' && conf.dec_delimiter != '.' && sanitized[i] == '.') || (conf.thou_delimiter != ',' && conf.dec_delimiter != ',' && sanitized[i] == ',')) { // throw an error report_error("Improperly formatted numbers! (%c,%c)\n", conf.thou_delimiter, conf.dec_delimiter); synerrors = 1; break; } else if (sanitized[i] == conf.thou_delimiter) sanitized[i] = ','; else if (sanitized[i] == conf.dec_delimiter) sanitized[i] = '.'; // sanitized[i] = conf.charkey[(int)sanitized[i]]; } } /* Now, check for recursion */ if (recursion(sanitized)) { goto exiting; } /* now resolve the variables */ sanitized = flatten(sanitized); Dprintf("flattened: '%s'\n", sanitized); /* Sanitize the input (add a newline) */ { char *temp; unsigned int len = strlen(sanitized) + 3; temp = calloc(sizeof(char), len); if (!temp) { perror("resizing buffer"); goto exiting; } snprintf(temp, len, "%s\n", sanitized); free(sanitized); sanitized = temp; } /* reset the position tracker */ { extern int column; column = 0; } /* Evaluate the Expression * These two lines borrowed from: * http://www.bgw.org/tutorials/programming/c/lex_yacc/main.c * and are here strictly for readline suppport */ { struct yy_buffer_state *yy = yy_scan_string(sanitized); yyparse(); yy_delete_buffer(yy); } if (open_file) { char *filename = open_file; int retval; open_file = NULL; Dprintf("open_file\n"); retval = loadState(filename, 1); if (retval) { report_error("Could not load file (%s).", (char *)strerror(retval)); } } exiting: /* exiting */ free(sanitized); return; } /*}}} */ /* this function should probably stop flattening if it sees a comment, but * that's so rare (and hardly processor intensive) that it's not worth digging * at the moment */ static char *flatten(char *str) { /*{{{ */ char *curs = str, *eov, *nstr; char *varname, *varvalue; size_t olen, nlen, changedlen, varnamelen = 100; struct answer a; char standard_output_save = standard_output; standard_output = 0; if (*str == '\\') { standard_output = standard_output_save; return str; } curs = strchr(str, '='); if (!curs || !*curs || *(curs + 1) == '=') curs = str; while (curs && *curs) { // search for the first letter of a possible variable while (curs && *curs && !isalpha((int)(*curs))) { if (*curs == '\\') { curs++; while (curs && *curs && isalpha((int)(*curs))) curs++; } if (*curs == '\'') { curs++; while (curs && *curs && *curs != '\'') curs++; } curs++; } if (!curs || !*curs) { break; } // pull out that variable eov = curs; { size_t i = 0; varname = malloc(varnamelen * sizeof(char)); while (eov && *eov && (isalpha((int)(*eov)) || *eov == '_' || *eov == ':' || isdigit((int)(*eov)))) { if (i == varnamelen - 1) { varnamelen += 100; varname = realloc(varname, varnamelen * sizeof(char)); if (varname == NULL) { perror("flatten: "); exit(EXIT_FAILURE); } } varname[i++] = *eov; eov++; } if (i == 0) break; varname[i] = 0; } olen = strlen(varname); // if it's a variable, evaluate it a = getvar_full(varname); if (!a.err) { // it is a var Number f; num_init(f); if (a.exp) { // it is an expression parseme(a.exp); num_set(f, last_answer); } else { // it is a value num_set(f, a.val); num_free(a.val); } // get the number { char junk; // This value must fully reproduce the contents of f (thus, the -2 in arg 4) varvalue = num_to_str_complex(f, 10, 0, -2, 1, &junk); } num_free(f); } else { // not a known var: itza literal (e.g. cos) varvalue = (char *)strdup(varname); } nlen = strlen(varvalue); free(varname); // now, put it back in the string // it is a var, and needs parenthesis changedlen = strlen(str) + nlen - olen + 1; if (!a.err) changedlen += 2; // space for parens if it's a variable nstr = malloc(changedlen); if (!nstr) { // not enough memory perror("flatten: "); exit(EXIT_FAILURE); } { char *fromstring = str; char *tostring = nstr; // nstr is the new string, str is the input string tostring = nstr; while (fromstring != curs) { // copy up to the curs (the beginning of the var name) *tostring = *fromstring; ++fromstring; ++tostring; } if (!a.err) { *tostring = '('; ++tostring; } fromstring = varvalue; while (fromstring && *fromstring) { *tostring = *fromstring; ++fromstring; ++tostring; } if (!a.err) { *tostring = ')'; ++tostring; } curs = tostring; fromstring = eov; while (fromstring && *fromstring) { *tostring = *fromstring; ++fromstring; ++tostring; } *tostring = 0; free(str); str = nstr; } free(varvalue); } standard_output = standard_output_save; return str; } /*}}} */ static int recursion(char *str) { /*{{{ */ List vlist = NULL; int retval = 0; char *righthand; // do not examine commands if (*str == '\\') { return 0; } // do not examine the left side of an assignment righthand = strchr(str, '='); if (!righthand || !*righthand || *(righthand + 1) == '=') { righthand = str; } vlist = extract_vars(righthand); while (listLen(vlist) > 0) { char *varname = (char *)getHeadOfList(vlist); if (retval == 0) { retval = find_recursion(varname); } free(varname); } return retval; } /*}}} */ static int find_recursion(char *instring) { /*{{{ */ List vl = NULL; int retval; addToList(&vl, (char *)strdup(instring)); retval = find_recursion_core(vl); free(getHeadOfList(vl)); return retval; } /*}}} */ static int find_recursion_core(List oldvars) { /*{{{ */ List newvars = NULL; ListIterator oldvarsIterator; int retval = 0; struct answer a; char *newVarname = NULL, *oldVarname = NULL; a = getvar_full((char *)peekAheadInList(oldvars)); if (a.err) return 0; if (!a.exp) { num_free(a.val); return 0; } newvars = extract_vars(a.exp); oldvarsIterator = getListIterator(oldvars); // for each variable in that expression (i.e. each entry in newvars) // see if we've seen it before (i.e. it's in oldvars) while (listLen(newvars) > 0) { newVarname = (char *)getHeadOfList(newvars); while ((oldVarname = (char *)nextListElement(oldvarsIterator)) != NULL) { if (!strcmp(newVarname, oldVarname)) { report_error ("%s was found twice in symbol descent. Recursive variables are not allowed.", newVarname); // free the rest of the newvars list do { free(newVarname); } while ((newVarname = (char *)getHeadOfList(newvars)) != NULL); freeListIterator(oldvarsIterator); return 1; } } // now see if it has recursion addToListHead(&oldvars, newVarname); retval = find_recursion_core(oldvars); getHeadOfList(oldvars); resetListIterator(oldvarsIterator); free(newVarname); if (retval != 0) { break; } } // make sure newvars is empty (so all that memory gets freed) while ((newVarname = (char *)getHeadOfList(newvars)) != NULL) { free(newVarname); } freeListIterator(oldvarsIterator); return retval; } /*}}} */ void report_error(const char *err_fmt, ...) { /*{{{ */ extern char *errstring; extern int errloc; extern int column; extern int lines; extern int show_line_numbers; char *tempstring; unsigned int len; va_list ap; char *this_error; va_start(ap, err_fmt); this_error = calloc(strlen(err_fmt) + 1000, sizeof(char)); vsnprintf(this_error, strlen(err_fmt) + 1000, err_fmt, ap); len = strlen(this_error) + 100; va_end(ap); /* okay, now this_error has the current error text in it */ if (errstring) { len += strlen(errstring); } tempstring = calloc(len, sizeof(char)); if (errstring) { if (show_line_numbers) { snprintf(tempstring, len, "%s\nError on line %i: %s", errstring, lines, this_error); } else { snprintf(tempstring, len, "%s\n%s", errstring, this_error); } free(errstring); } else { if (show_line_numbers) { snprintf(tempstring, len, "Error on line %i: %s", lines, this_error); } else { snprintf(tempstring, len, "%s", this_error); } } errstring = tempstring; free(this_error); if (errloc == -1) { errloc = column; } } /*}}} */ void display_and_clear_errstring() { /*{{{ */ extern int scanerror; extern char *errstring; extern int errloc; if (errstring && errstring[0]) { if (errloc != -1) { int i; fprintf(stderr, " "); for (i = 0; i < errloc; i++) { fprintf(stderr, " "); } fprintf(stderr, "^\n"); errloc = -1; } fprintf(stderr, "%s", errstring); if (errstring[strlen(errstring) - 1] != '\n') fprintf(stderr, "\n"); free(errstring); errstring = NULL; scanerror = 0; } } /*}}} */ void set_prettyanswer(const Number num) { /*{{{ */ char *temp; Dprintf("set_prettyanswer\n"); if (pretty_answer) { free(pretty_answer); } Dprintf("set_prettyanswer - call print_this_result\n"); temp = print_this_result(num); Dprintf("set_prettyanswer: %s\n", temp); if (temp) { pretty_answer = (char *)strdup(temp); } else { pretty_answer = NULL; } Dprintf("set_prettyanswer - done\n"); } /*}}} */ static char *print_this_result_dbl(const double result) { /*{{{ */ char format[10]; static char *tmp; static char pa_dyn = 1; extern char *errstring; unsigned int decimal_places = 0; Dprintf("print_this_result_dbl(%f)\n", result); /* Build the "format" string, that will be used in an snprintf later */ switch (conf.output_format) { /*{{{ */ case DECIMAL_FORMAT: if (pa_dyn) tmp = realloc(pa, sizeof(char) * 310); else { tmp = pa = malloc(sizeof(char) * 310); pa_dyn = 1; } if (!tmp) { free(pa); pa = "Not Enough Memory"; pa_dyn = 0; return pa; } else pa = tmp; if (conf.precision > -1 && !conf.engineering) { snprintf(format, 10, "%%1.%if", conf.precision); decimal_places = conf.precision; } else if (conf.precision > -1 && conf.engineering) { snprintf(format, 10, "%%1.%iE", conf.precision); decimal_places = conf.precision; } else { snprintf(format, 10, "%%G"); if (fabs(result) < 10.0) { decimal_places = 6; } else if (fabs(result) < 100.0) { decimal_places = 4; } else if (fabs(result) < 1000.0) { decimal_places = 3; } else if (fabs(result) < 10000.0) { decimal_places = 2; } else if (fabs(result) < 100000.0) { decimal_places = 1; } else { decimal_places = 0; } } break; case OCTAL_FORMAT: if (pa_dyn) { tmp = realloc(pa, sizeof(char) * 14); } else { tmp = pa = malloc(sizeof(char) * 14); pa_dyn = 1; } if (!tmp) { free(pa); pa = "Not Enough Memory"; pa_dyn = 0; return pa; } else { pa = tmp; } snprintf(format, 10, conf.print_prefixes ? "%%#o" : "%%o"); break; case HEXADECIMAL_FORMAT: if (pa_dyn) { tmp = realloc(pa, sizeof(char) * 11); } else { tmp = pa = malloc(sizeof(char) * 11); pa_dyn = 1; } if (!tmp) { free(pa); pa = "Not Enough Memory"; pa_dyn = 0; return pa; } else { pa = tmp; } snprintf(format, 10, conf.print_prefixes ? "%%#x" : "%%x"); break; case BINARY_FORMAT: // Binary Format can't just use a format string, so // we have to handle it later if (pa_dyn) free(pa); pa = NULL; pa_dyn = 1; break; } /*}}} */ if (isinf(result)) { // if it is infinity, print "Infinity", regardless of format if (pa_dyn) tmp = realloc(pa, sizeof(char) * 11); else { tmp = pa = malloc(sizeof(char) * 11); pa_dyn = 1; } if (!tmp) { free(pa); pa = "Not Enough Memory"; pa_dyn = 0; return pa; } else pa = tmp; snprintf(pa, 11, "Infinity"); not_all_displayed = 0; } else if (isnan(result)) { // if it is not a number, print "Not a Number", regardless of format if (pa_dyn) tmp = realloc(pa, sizeof(char) * 13); else { tmp = pa = malloc(sizeof(char) * 13); pa_dyn = 1; } if (!tmp) { free(pa); pa = "Not Enough Memory"; pa_dyn = 0; return pa; } else pa = tmp; snprintf(pa, 13, "Not a Number"); not_all_displayed = 0; } else { char *curs; Dprintf("normal numbers (format: %s)\n", format); switch (conf.output_format) { /*{{{ */ case DECIMAL_FORMAT: { double junk; Dprintf("fabs = %f, conf.engineering = %i, conf.print_ints = %i\n", fabs(modf(result, &junk)), conf.engineering, conf.print_ints); /* This is the big call */ if (fabs(modf(result, &junk)) != 0.0 || conf.engineering || !conf.print_ints) { snprintf(pa, 310, format, result); } else { snprintf(pa, 310, "%1.0f", result); } Dprintf("pa (unlocalized): %s\n", pa); /* was it as good for you as it was for me? * now, you must localize it */ strswap('.',conf.dec_delimiter,pa); Dprintf("pa: %s\n", pa); switch (conf.rounding_indication) { case SIMPLE_ROUNDING_INDICATION: Dprintf("simple\n"); not_all_displayed = (modf(result * pow(10, decimal_places), &junk)) ? 1 : 0; break; case SIG_FIG_ROUNDING_INDICATION: Dprintf("sigfig\n"); if (sig_figs < UINT32_MAX) { unsigned int t = count_digits(pa); Dprintf("digits in pa: %u (%u)\n", t, sig_figs); if (pa[0] == '0' && pa[1] != '\0') { --t; } else if (pa[0] == '-' && pa[1] == '0') { --t; } not_all_displayed = (t < sig_figs); } else { not_all_displayed = 1; } break; default: case NO_ROUNDING_INDICATION: Dprintf("none\n"); not_all_displayed = 0; break; } } break; case HEXADECIMAL_FORMAT: curs = pa + (conf.print_prefixes ? 2 : 0); case OCTAL_FORMAT: curs = pa + (conf.print_prefixes ? 1 : 0); { long int temp = result; unsigned int t = 0; snprintf(pa, 310, format, temp); if (conf.rounding_indication == SIG_FIG_ROUNDING_INDICATION) { if (sig_figs < UINT32_MAX) { while (curs && *curs) { ++t; ++curs; } not_all_displayed = (t < sig_figs); } else { not_all_displayed = 0; } } else { not_all_displayed = 0; } } break; case BINARY_FORMAT: { int i, place = -1; // if it is binary, format it, and print it // first, find the upper limit for (i = 1; place == -1; ++i) { if (result < pow(2.0, i)) place = i - 1; } pa = calloc(sizeof(char), (place + (conf.print_prefixes * 2) + 1)); if (!pa) { pa = "Not Enough Memory"; pa_dyn = 0; return pa; } if (conf.print_prefixes) { pa[0] = '0'; pa[1] = 'b'; } // print it { double temp = result; for (i = conf.print_prefixes * 2; place >= 0; ++i) { double t = pow(2.0, place); if (temp >= t) { pa[i] = '1'; temp -= t; } else { pa[i] = '0'; } --place; } } pa[i + 1] = 0; if (sig_figs < UINT32_MAX) { if (conf.rounding_indication == SIG_FIG_ROUNDING_INDICATION) { not_all_displayed = count_digits(pa + (conf.print_prefixes ? 2 : 0)) < sig_figs; } else { not_all_displayed = 0; } } else { not_all_displayed = 0; } } // binary format } /*}}} */ } // if if (conf.print_commas) { char *str = add_commas(pa, conf.output_format); if (str) { free(pa); pa = str; } } if (standard_output) { if (errstring && strlen(errstring)) { display_and_clear_errstring(); } printf("%s%s\n", conf.print_equal ? (not_all_displayed ? "~= " : " = ") : (not_all_displayed ? "~" : ""), pa); } return pa; } /*}}} */ char *print_this_result(const Number result) { /*{{{ */ extern char *errstring; unsigned int base = 0; Dprintf("print_this_result (%f) in format %i\n", num_get_d(result), conf.output_format); // output in the proper base and format switch (conf.output_format) { case HEXADECIMAL_FORMAT: base = 16; break; default: case DECIMAL_FORMAT: // if you want precision_guard and automatic precision, // then we have to go with the tried and true "double" method // ... unless it's an int and you want ints printed whole // I know that DBL_EPSILON can be calculated like so: // 2^(mpfr_get_prec(result)-1) HOWEVER, printf magically handles // numbers like 5.1 that I don't even wanna begin to think about if (conf.precision_guard && conf.precision < 0) { Dprintf("precision guard and automatic precision\n"); if (!conf.print_ints || !is_int(result)) { Dprintf("no print_ints or it isn't an int\n"); //XXX: what is the following if() for? //if (mpfr_get_d(result, GMP_RNDN) != //mpfr_get_si(result, GMP_RNDN)) { double res = num_get_d(result); if (fabs(res) < DBL_EPSILON) { res = 0.0; } return print_this_result_dbl(res); //} } } base = 10; break; case OCTAL_FORMAT: base = 8; break; case BINARY_FORMAT: base = 2; break; } if (pa != NULL) { free(pa); } not_all_displayed = 0; pa = num_to_str_complex(result, base, conf.engineering, conf.precision, conf.print_prefixes, ¬_all_displayed); Dprintf("not_all_displayed = %i\n", not_all_displayed); /* now, decide whether it's been rounded or not */ if (num_is_inf(result) || num_is_nan(result)) { // if it is infinity, it's all there ;) not_all_displayed = 0; } else if (not_all_displayed == 0) { /* rounding guess */ switch (conf.rounding_indication) { case SIMPLE_ROUNDING_INDICATION: { char *pa2, junk; Dprintf("simple full\n"); pa2 = num_to_str_complex(result, base, conf.engineering, -2, conf.print_prefixes, &junk); not_all_displayed = (strlen(pa) < strlen(pa2)); free(pa2); } break; case SIG_FIG_ROUNDING_INDICATION: /* sig_figs is how many we need to display */ Dprintf("sigfig full\n"); if (sig_figs < UINT32_MAX) { unsigned int t = count_digits(pa); Dprintf("digits in pa: %u (%u)\n", t, sig_figs); not_all_displayed = (t < sig_figs); } else { not_all_displayed = 0; } break; default: case NO_ROUNDING_INDICATION: Dprintf("none full\n"); not_all_displayed = 0; break; } } if (conf.rounding_indication == NO_ROUNDING_INDICATION) { not_all_displayed = 0; } // add commas if (conf.print_commas) { char *str = add_commas(pa, conf.output_format); if (str) { free(pa); pa = str; } } if (standard_output) { if (errstring && strlen(errstring)) { display_and_clear_errstring(); } printf("%s%s\n", conf.print_equal ? (not_all_displayed ? "~= " : " = ") : (not_all_displayed ? "~" : ""), pa); } return pa; } /*}}} */ void simple_exp(Number output, const Number first, const enum operations op, const Number second) { /*{{{ */ if (compute) { Number temp; num_init(temp); Dprintf("simple_exp: %f %i %f\n", num_get_d(first), op, num_get_d(second)); switch (op) { default: num_set_d(output, 0.0); break; case wequal: num_set_ui(output, num_is_equal(first, second)); break; case wnequal: num_set_ui(output, !num_is_equal(first, second)); break; case wgt: num_set_ui(output, num_is_greater(first, second)); break; case wlt: num_set_ui(output, num_is_less(first, second)); break; case wgeq: num_set_ui(output, num_is_greaterequal(first, second)); break; case wleq: num_set_ui(output, num_is_lessequal(first, second)); break; case wplus: num_add(output, first, second); break; case wminus: num_sub(output, first, second); break; case wmult: num_mul(output, first, second); break; case wdiv: num_div(output, first, second); break; case wpow: num_pow(output, first, second); break; case wor: num_set_ui(output, (!num_is_zero(first)) || (!num_is_zero(second))); break; case wand: num_set_ui(output, (!num_is_zero(first)) && (!num_is_zero(second))); break; case wbor: num_bor(output, first, second); break; case wband: num_band(output, first, second); break; case wbxor: num_bxor(output, first, second); break; case wlshft: num_set_ui(temp, 2); num_pow(temp, temp, second); num_mul(output, first, temp); break; case wrshft: num_set_ui(temp, 2); num_pow(temp, temp, second); num_div(output, first, temp); break; case wmod: if (num_is_zero(second)) { num_set_nan(output); } else { /* divide, round to zero, multiply, subtract * * in essence, find the value x in the equation: * first = second * temp + x */ num_div(output, first, second); if (conf.c_style_mod) { num_rintz(output, output); // makes zeros work } else { if (num_sign(first) >= 0) { num_floor(output, output); } else { num_ceil(output, output); } } num_mul(output, output, second); num_sub(output, first, output); } break; } Dprintf("returns: %f\n", num_get_d(output)); num_free(temp); return; } else { num_set_ui(output, 0); return; } } /*}}} */ void uber_function(Number output, const enum functions func, Number input) { /*{{{ */ if (compute) { Number temp; num_init(temp); if (!conf.use_radians) { switch (func) { case wsin: case wcos: case wtan: case wcot: case wsec: case wcsc: num_const_pi(temp); num_mul(input, input, temp); num_div_ui(input, input, 180); break; case wasin: case wacos: case watan: case wacot: case wasec: case wacsc: num_const_pi(temp); num_pow_si(temp, temp, -1); num_mul_ui(temp, temp, 180); break; default: break; } } switch (func) { case wsin: num_sin(output, input); break; case wcos: num_cos(output, input); break; case wtan: num_tan(output, input); break; case wcot: num_cot(output, input); break; case wsec: num_sec(output, input); break; case wcsc: num_csc(output, input); break; case wasin: num_asin(output, input); if (!conf.use_radians) { num_mul(output, output, temp); } break; case wacos: num_acos(output, input); if (!conf.use_radians) { num_mul(output, output, temp); } break; case watan: num_atan(output, input); if (!conf.use_radians) { num_mul(output, output, temp); } break; case wacot: num_pow_si(output, input, -1); num_atan(output, output); if (!conf.use_radians) { num_mul(output, output, temp); } break; case wasec: num_pow_si(output, input, -1); num_acos(output, output); if (!conf.use_radians) { num_mul(output, output, temp); } break; case wacsc: num_pow_si(output, input, -1); num_asin(output, output); if (!conf.use_radians) { num_mul(output, output, temp); } break; case wsinh: num_sinh(output, input); break; case wcosh: num_cosh(output, input); break; case wtanh: num_tanh(output, input); break; case wcoth: num_coth(output, input); break; case wsech: num_sech(output, input); break; case wcsch: num_csch(output, input); break; case wasinh: num_asinh(output, input); break; case wacosh: num_acosh(output, input); break; case watanh: num_atanh(output, input); break; case wacoth: num_acoth(output, input); break; case wasech: num_asech(output, input); break; case wacsch: num_acsch(output, input); break; case wlog: num_log10(output, input); break; case wlogtwo: num_log2(output, input); break; case wln: num_log(output, input); break; case wround: num_rint(output, input); break; case wneg: num_neg(output, input); break; case wnot: num_set_ui(output, num_is_zero(input)); break; case wabs: num_abs(output, input); break; case wsqrt: num_sqrt(output, input); break; case wfloor: num_floor(output, input); break; case wceil: num_ceil(output, input); break; case wrand: while (num_random(output) != 0) ; num_mul(output, output, input); if (num_cmp_si(input, 0) < 0) { num_mul_si(output, output, -1); } break; case wirand: while (num_random(output) != 0) ; num_mul(output, output, input); if (num_cmp_si(input, 0) < 0) { num_mul_si(output, output, -1); } num_rint(output, output); break; case wcbrt: num_cbrt(output, input); break; case wexp: num_exp(output, input); break; case wfact: num_factorial(output, num_get_ui(input)); break; case wcomp: num_comp(output, input); break; #ifdef HAVE_MPFR_22 case weint: num_eint(output, input); break; #endif case wgamma: num_gamma(output, input); break; #ifdef HAVE_MPFR_22 case wlngamma: num_lngamma(output, input); break; #endif case wzeta: num_zeta(output, input); break; case wsinc: num_sinc(output, input); break; case wbnot: num_bnot(output, input); break; default: num_set(output, input); break; } num_free(temp); return; } else { num_set_ui(output, 0); return; } } /*}}} */ char *output_string(const unsigned int o) { /*{{{ */ switch (o) { case HEXADECIMAL_FORMAT: return "hexadecimal format (0xf)"; case OCTAL_FORMAT: return "octal format (08) "; case BINARY_FORMAT: return "binary format (0b1) "; case DECIMAL_FORMAT: return "decimal format (9) "; default: return "error, unknown format "; } } /*}}} */