#ifdef HAVE_CONFIG_H
#include "config.h"
#else
#define HAVE_MPFR_22
#endif
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <math.h> /* for HUGE_VAL */
#include <float.h> /* for DBL_EPSILON */
#include <ctype.h> /* for isalpha() */
#if ! defined(HAVE_CONFIG_H) || HAVE_STRING_H
# include <string.h> /* 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 <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# 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 ";
}
} /*}}} */
syntax highlighted by Code2HTML, v. 0.9.1