|
- /* ns.c - Number Stack */
-
- #define NS_PRINTLINE_FORMAT NS_PRINT_FORMAT "\n"
-
- /* Easy access functions */
- #define NS_PEEK(s) s->num[s->top]
- #define NS_PEEKN(s,n) s->num[s->top + n]
- #define NS_PEEKDOT(s) s.num[s.top]
- /* Handling of the stack max size and expanding */
- #define NS_EXPAND(s,n) n >= s->max ? !ns_expand(s,n) : 1
- #define NS_EXPANDDOT(s,n) n >= s.max ? !ns_expand(&s,n) : 1
- #define NS_LTMAX(s,n) s->top + n >= s->max ? !ns_expand(s,s->max+n) : 1
- #define NS_LTMAXDOT(s,n) s.top + n >= s.max ? !ns_expand(&s,s.max+n) : 1
- /* Debugging and Stack Output */
- #define NS_DIV0(fail) do { fprintf(stderr, PROGN ": divide by zero\n"); return fail; } while (0)
- #define NS_REG_UNDERFLOW(fail, c) do { fprintf(stderr, PROGN ": stack register '%c' (%04d) is empty\n", (char) c, c); return fail; } while (0)
- #ifndef DC_COMPLY
- #define NS_OVERFLOW(fail) do { fprintf(stderr, PROGN ": overflow\n"); return fail; } while (0)
- #define NS_UNDERFLOW(fail) do { fprintf(stderr, PROGN ": underflow\n"); return fail; } while (0)
- #define NS_REG_OOB(fail, c) fprintf(stderr, PROGN ": register '%c' (%04d) is out of bounds\n", (char) c, c)
- #else
- #define NS_OVERFLOW(fail) do { fprintf(stderr, PROGN ": at top of stack\n"); return fail; } while (0)
- #define NS_UNDERFLOW(fail) do { fprintf(stderr, PROGN ": stack empty\n"); return fail; } while (0)
- #define NS_REG_OOB(fail, c) __builtin_unreachable()
- #endif /* !DC_COMPLY */
- #define PERROR_RETURN(str,ret) do { perror(str); return ret; } while (1)
- #define NS_RETURN(ret) do { perror(PROGN); return ret; } while (1)
-
- /* #define NS_EXPAND(s,n) \ */
- /* if (s->top + n >= s->max) \ */
- /* { ns_expand(s,s->max+n); } */
-
- #define NS_OP(fn, op) \
- DC_EXPORT int \
- fn(ns_t * s) \
- { \
- if (s->top > 0) \
- { \
- --s->top; \
- op(NS_PEEK(s), \
- NS_PEEK(s), NS_PEEKN(s,1)); \
- return 0; \
- } \
- else \
- { NS_UNDERFLOW(1); } \
- }
-
- #define NS_OP_ONE(fn, op) \
- DC_EXPORT int \
- fn(ns_t * s) \
- { \
- if (s->top > -1) \
- { \
- op(NS_PEEK(s), \
- NS_PEEK(s)); \
- return 0; \
- } \
- else \
- { NS_UNDERFLOW(1); } \
- }
-
- #define NS_OP_DIV(fn, op) \
- DC_EXPORT int fn(ns_t * s) \
- { \
- if (s->top > 0) \
- { \
- if (!(mpf_cmp_ui(NS_PEEK(s), 0) || \
- mpf_cmp_ui(NS_PEEKN(s,-1), 0))) \
- { NS_DIV0(2); } \
- else \
- { \
- --s->top; \
- op(NS_PEEK(s), \
- NS_PEEK(s), NS_PEEKN(s,1)); \
- return 0; \
- } \
- } \
- else \
- { NS_UNDERFLOW(1); } \
- }
-
- typedef struct
- {
- ssize_t max;
- ssize_t top;
- mpf_t * num;
- } ns_t; /* number stack */
-
- DC_EXPORT_VAR mp_bitcnt_t g_prec = NS_DEFAULT_PREC;
- DC_EXPORT_VAR int g_iradix = 10;
- DC_EXPORT_VAR int g_oradix = 10;
-
- /* Data handling */
-
- DC_EXPORT void
- ns_free(ns_t * s)
- {
- ssize_t i;
- /* fprintf(stderr, "%p: Freeing %ld blocks\n", (void *) s, s->max); */
- for (i = 0; i < s->max; ++i)
- {
- mpf_clear(s->num[i]);
- }
- free(s->num);
- /* free(s); */
- }
-
- /* Growth */
-
- DC_EXPORT int
- ns_expand(ns_t * s, ssize_t newmax)
- {
- /* fprintf(stderr, "%p: Expanding to %ld blocks\n", (void *) s, newmax); */
- s->num = realloc(s->num, newmax * sizeof(mpf_t));
- if (!s->num)
- { NS_RETURN(1); }
- else
- {
- ssize_t i;
- for (i = s->max; i < newmax; ++i)
- { mpf_init(s->num[i]); }
- s->max = newmax;
- return 0;
- }
- }
-
- /* Stack */
-
- #define NS_PUSH(fn, op, type) \
- DC_EXPORT int \
- fn(ns_t * s, type val) \
- { \
- if (NS_LTMAX(s,1)) \
- { \
- ++s->top; \
- op(NS_PEEK(s), val); \
- return 0; \
- } \
- NS_OVERFLOW(1); \
- }
-
- NS_PUSH(ns_push, mpf_set, mpf_t)
- NS_PUSH(ns_push_ui, mpf_set_ui, unsigned int)
-
- DC_EXPORT mpf_t *
- ns_pop(ns_t * s)
- {
- if (s->top > -1)
- { return &s->num[s->top--]; }
- else
- { return NULL; }
- }
-
- DC_EXPORT inline int
- ns_dup(ns_t * s)
- {
- if (NS_LTMAX(s,1))
- { return ns_push(s, NS_PEEK(s)); }
- return 1;
- }
-
- DC_EXPORT inline void
- ns_clear(ns_t * s)
- { s->top = -1; }
-
- DC_EXPORT inline int
- ns_reverse(ns_t * s)
- {
- if (s->top > 0)
- {
- mpf_swap(NS_PEEK(s), NS_PEEKN(s,-1));
- return 0;
- }
- else
- { return 1; }
- }
-
- /* nrotate = x - 1
- top - n swapped with peek -x */
- DC_EXPORT int
- ns_nrotate(ns_t * s)
- {
- mpf_t * val = ns_pop(s);
- if (!val)
- { NS_UNDERFLOW(1); }
- else
- {
- signed long v = mpf_get_si(*val);
- long i = -v;
- const long l = -v;
- while (++i < v)
- {
-
- mpf_swap(NS_PEEKN(s,i), NS_PEEKN(s,l));
- }
- }
- return 0;
- }
-
- /* Registers */
-
- ns_t g_reg[NS_REG_MAX];
-
- void
- ns_reg_init(void)
- {
- size_t i;
- for (i = 0; i < NS_REG_MAX; ++i)
- {
- g_reg[i].top = -1;
- g_reg[i].max = 0;
- }
- }
-
- void
- ns_reg_free(void)
- {
- size_t i;
- for (i = 0; i < NS_REG_MAX; ++i)
- { ns_free(&g_reg[i]); }
- }
-
- DC_EXPORT int
- ns_reg_set(ns_t * s, int c)
- {
- mpf_t * val = ns_pop(s);
- if (!val)
- { NS_REG_UNDERFLOW(1, c); }
- if (g_reg[c].top > -1)
- { mpf_set(NS_PEEKDOT(g_reg[c]), *val); }
- else
- { ns_push(&g_reg[c], *val); }
- return 0;
- }
-
- DC_EXPORT int
- ns_reg_get(ns_t * s, int c)
- {
- mpf_t * val = ns_pop(&g_reg[c]);
- if (!val)
- { NS_REG_UNDERFLOW(1, c); }
- if (NS_LTMAX(s,1))
- { ns_push(s, *val); }
- return 0;
- }
-
- DC_EXPORT int
- ns_reg_push(ns_t * s, int c)
- {
- mpf_t * val = ns_pop(s);
- if (!val)
- { NS_REG_UNDERFLOW(1, c); }
- if (NS_LTMAXDOT(g_reg[c],1))
- { ns_push(&g_reg[c], *val); }
- return 0;
- }
-
- DC_EXPORT int
- ns_reg_pop(ns_t * s, int c)
- {
- mpf_t * val = ns_pop(&g_reg[c]);
- if (!val)
- { NS_REG_UNDERFLOW(1, c); }
- if (NS_LTMAX(s,1))
- { ns_push(s, *val); }
- return 0;
- }
-
- DC_EXPORT int
- ns_reg_push_index(ns_t * s, int c)
- {
- mpf_t * val, * ip;
- ip = ns_pop(s);
- val = ns_pop(s);
- if (!ip || !val)
- { NS_REG_UNDERFLOW(1, c); }
- else
- {
- ssize_t i = mpf_get_si(*ip);
- if (NS_EXPANDDOT(g_reg[c],i+1))
- {
- mpf_set(g_reg[c].num[i], *val);
- return 0;
- }
- else return 1;
- }
- }
-
- DC_EXPORT int
- ns_reg_pop_index(ns_t * s, int c)
- {
- mpf_t * ip = ns_pop(s);
- if (!ip)
- { NS_REG_UNDERFLOW(1, c); }
- else
- {
- ssize_t i;
- i = mpf_get_ui(*ip);
- if (NS_LTMAX(s,1) && NS_EXPANDDOT(g_reg[c],i+1))
- {
- ns_push(s, g_reg[c].num[i]);
- return 0;
- }
- else return 1;
- }
- }
-
- /* Printing */
-
- DC_EXPORT void
- ns_printline_all(ns_t * s)
- {
- ssize_t i;
- #ifdef FOR_HUMANS
- for (i = 0; i <= s->top; ++i)
- #else
- for (i = s->top; i >= 0; --i)
- #endif /* FOR_HUMANS */
- { gmp_printf(NS_FORMAT, s->num[i]); }
- }
-
- DC_EXPORT inline void
- ns_printline_peek(ns_t * s)
- {
- if (s->top > -1)
- { gmp_printf(NS_FORMAT, NS_PEEK(s)); }
- }
-
- DC_EXPORT inline int
- ns_print_peek(ns_t * s)
- {
- if (s->top > -1)
- {
- gmp_printf(NS_FORMAT, NS_PEEK(s));
- return 0;
- }
- else
- { return 1; }
- }
-
- #undef PRINT
-
- /* Numbers */
-
- DC_EXPORT inline int
- ns_isnum(char c)
- {
- switch (c)
- {
- case '.':
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- case 'A': case 'B': case 'C': case 'D': case 'E':
- case 'F':
- return 1;
- default:
- return 0;
- }
- }
-
- DC_EXPORT size_t
- ns_getnum(ns_t * s, char * eval, size_t len, int base)
- {
- size_t i = 0;
- char t;
- while (ns_isnum(eval[i]) && i < len) { ++i; }
- if (!i)
- { return 0; }
- if (NS_LTMAX(s,1))
- {
- ++s->top;
- t = eval[i];
- eval[i] = '\0';
- mpf_set_str(NS_PEEK(s), eval, base);
- eval[i] = t;
- return i-1;
- }
- else
- { NS_OVERFLOW(0); }
- }
-
- /* Digits */
-
- #if 0
-
- DC_EXPORT int
- ns_digit_last(ns_t * s)
- {
- return 1;
- }
-
- DC_EXPORT int
- ns_digit(ns_t * s)
- {
- return 1;
- }
-
- #endif /* 0 */
-
- /* Arithmetic */
-
- /* handles negative numbers and is multi-precision on both operands unlike mpf_exp_ui */
- DC_EXPORT int
- ns_exp(ns_t * s)
- {
- if (s->top > 0)
- {
- if (!(mpf_cmp_ui(NS_PEEK(s), 0) ||
- mpf_cmp_ui(s->num[s->top-1], 0)))
- { fprintf(stderr, "dc: divide by 0\n"); return 2; }
- else
- {
- mpf_t i;
- mpf_t mpf;
- if (mpf_cmp_ui(NS_PEEK(s), 0) == 0)
- { mpf_set_ui(NS_PEEK(s), 1); return 0; }
- --s->top;
- mpf_inits(i, mpf, NULL);
- mpf_set(mpf, NS_PEEK(s));
- mpf_set(i, s->num[s->top + 1]);
- mpf_ceil(i, i);
- mpf_sub_ui(i, i, 1);
- if (mpf_cmp_ui(i, 0) > 0)
- {
- for (; mpf_cmp_ui(i, 0); mpf_sub_ui(i, i, 1))
- { mpf_mul(NS_PEEK(s), NS_PEEK(s), mpf); }
- }
- else
- {
- for (; mpf_cmp_ui(i, 0); mpf_add_ui(i, i, 1))
- { mpf_div(NS_PEEK(s), NS_PEEK(s), mpf); }
- }
- mpf_clears(i, mpf, NULL);
- return 0;
- }
- }
- NS_UNDERFLOW(1);
- }
-
- NS_OP(ns_add, mpf_add)
- NS_OP(ns_sub, mpf_sub)
- NS_OP(ns_mul, mpf_mul)
- NS_OP_ONE(ns_abs, mpf_abs)
- NS_OP_ONE(ns_sqrt, mpf_sqrt)
- NS_OP_ONE(ns_floor, mpf_floor)
- NS_OP_ONE(ns_ceil, mpf_ceil)
- NS_OP_DIV(ns_div, mpf_div)
-
- /* Params */
-
- DC_EXPORT int
- ns_pop_prec(ns_t * s)
- {
- ssize_t i, f;
- mpf_t * mpf = ns_pop(s);
- if (!mpf)
- { NS_UNDERFLOW(1); }
- else
- {
- size_t prec = mpf_get_ui(*mpf);
- /* fprintf(stderr, "new prec: %ld\n", prec); */
- g_prec = prec;
- for (i = 0; i < s->max; ++i)
- { mpf_set_prec(s->num[i], prec); }
- for (f = NS_REG_OFF; f < NS_REG_MAX; ++f)
- {
- for (i = 0; i < g_reg[f].max; ++i)
- { mpf_set_prec(g_reg[f].num[i], prec); }
- }
- return 0;
- }
- }
-
-
- DC_EXPORT int
- ns_push_prec(ns_t * s)
- { return ns_push_ui(s, g_prec); }
-
- DC_EXPORT int
- ns_pop_iradix(ns_t * s)
- {
- mpf_t * mpf = ns_pop(s);
- if (!mpf)
- { NS_UNDERFLOW(1); }
- else
- {
- int x = (int) mpf_get_ui(*mpf);
- if (2 < x && x < INT_MAX - 1)
- { fprintf(stderr, PROGN ": input base must be a number between 2 and %d (inclusive)\n", INT_MAX - 1); }
- return 0;
- }
- }
-
- DC_EXPORT int
- ns_push_iradix(ns_t * s)
- { return ns_push_ui(s, g_iradix); }
-
- DC_EXPORT int
- ns_pop_oradix(ns_t * s)
- {
- mpf_t * mpf = ns_pop(s);
- if (!mpf)
- { NS_UNDERFLOW(1); }
- else
- {
- g_oradix = (int) mpf_get_ui(*mpf);
- return 0;
- }
- }
-
- DC_EXPORT int
- ns_push_oradix(ns_t * s)
- { return ns_push_ui(s, g_oradix); }
-
- /* Test Functions */
-
- #if 0
-
- /* It probably shouldn't return -1 but I'm not worried about this function */
- DC_EXPORT int
- ns_ndup(ns_t * s)
- {
- int ret = 0;
- mpf_t dupn;
- if (!ns_pop(s))
- { NS_UNDERFLOW(-1); }
- for (mpf_set(dupn, NS_PEEKN(s,1));
- !ret &&
- mpf_cmp_ui(dupn,1);
- mpf_sub_ui(dupn,dupn,1))
- { ret = ns_dup(s); }
- return ret;
- }
-
- #endif /* 0 */
-
- /* Definition Cleanup */
-
- /* #undef NS_OP */
- /* #undef NS_OP_ONE */
- /* #undef NS_OP_DIV */
- /* #undef NS_OVERFLOW */
- /* #undef NS_UNDERFLOW */
- /* #undef NS_REG_UNDERFLOW */
- /* #undef NS_DIV0 */
|