105 lines
3.9 KiB
C
105 lines
3.9 KiB
C
#define ARITH(fn, op) \
|
|
static inline int \
|
|
fn(ns_t * s) \
|
|
{ \
|
|
if (s->top > 0) \
|
|
{ \
|
|
--s->top; \
|
|
op(NS_PEEK(s), \
|
|
NS_PEEK(s), s->num[s->top+1]); \
|
|
return 0; \
|
|
} \
|
|
else \
|
|
{ \
|
|
fprintf(stderr, "dc: underflow\n"); \
|
|
return 1; \
|
|
} \
|
|
}
|
|
|
|
#define ARITH_ONE(fn, op) \
|
|
static inline int \
|
|
fn(ns_t * s) \
|
|
{ \
|
|
if (s->top > -1) \
|
|
{ \
|
|
op(NS_PEEK(s), \
|
|
NS_PEEK(s)); \
|
|
return 0; \
|
|
} \
|
|
else \
|
|
{ \
|
|
fprintf(stderr, "dc: underflow\n"); \
|
|
return 1; \
|
|
} \
|
|
}
|
|
|
|
#define ARITH_DIV(fn, op) \
|
|
static inline int fn(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 \
|
|
{ \
|
|
--s->top; op(NS_PEEK(s), NS_PEEK(s), s->num[s->top+1]); \
|
|
return 0; \
|
|
} \
|
|
} \
|
|
else \
|
|
{ fprintf(stderr, "dc: underflow\n"); return 1; } \
|
|
}
|
|
|
|
/* handles negative numbers and is multi-presision unlike mpf_exp_ui */
|
|
static inline 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;
|
|
}
|
|
{
|
|
|
|
}
|
|
}
|
|
else
|
|
{ fprintf(stderr, "dc: underflow\n"); return 1; }
|
|
__builtin_unreachable();
|
|
}
|
|
|
|
ARITH(ns_add, mpf_add)
|
|
ARITH(ns_sub, mpf_sub)
|
|
ARITH(ns_mul, mpf_mul)
|
|
ARITH_DIV(ns_div, mpf_div)
|
|
ARITH_DIV(ns_mod, mpf_div)
|
|
ARITH_ONE(ns_abs, mpf_abs)
|
|
ARITH_ONE(ns_sqrt, mpf_sqrt)
|
|
ARITH_ONE(ns_floor, mpf_floor)
|
|
ARITH_ONE(ns_ceil, mpf_ceil)
|