mirror of
https://github.com/louisrubet/rpn
synced 2024-12-28 09:58:52 +01:00
#148: first attempt to write with an arbitrary base
This commit is contained in:
parent
8648d69554
commit
59875e360b
3 changed files with 213 additions and 6 deletions
|
@ -76,4 +76,35 @@ typedef enum {
|
|||
#define HISTORY_FILE ".rpn_history"
|
||||
#define HISTORY_FILE_MAX_LINES (100)
|
||||
|
||||
// some defs for mpfr
|
||||
#if _MPFR_EXP_FORMAT == 1
|
||||
#define MPFR_EXP_MAX (SHRT_MAX)
|
||||
#define MPFR_EXP_MIN (SHRT_MIN)
|
||||
#elif _MPFR_EXP_FORMAT == 2
|
||||
#define MPFR_EXP_MAX (INT_MAX)
|
||||
#define MPFR_EXP_MIN (INT_MIN)
|
||||
#elif _MPFR_EXP_FORMAT == 3
|
||||
#define MPFR_EXP_MAX (LONG_MAX)
|
||||
#define MPFR_EXP_MIN (LONG_MIN)
|
||||
#elif _MPFR_EXP_FORMAT == 4
|
||||
#define MPFR_EXP_MAX (MPFR_INTMAX_MAX)
|
||||
#define MPFR_EXP_MIN (MPFR_INTMAX_MIN)
|
||||
#else
|
||||
#error "Invalid MPFR Exp format"
|
||||
#endif
|
||||
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MAX(h,i) ((h) > (i) ? (h) : (i))
|
||||
|
||||
#define MPFR_EXP_INF (MPFR_EXP_MIN+3)
|
||||
#define MPFR_EXP_NAN (MPFR_EXP_MIN+2)
|
||||
#define MPFR_EXP(x) ((x)->_mpfr_exp)
|
||||
#define MPFR_IS_SINGULAR(x) (MPFR_EXP(x) <= MPFR_EXP_INF)
|
||||
#define MPFR_UNLIKELY(x) (__builtin_expect(!!(x),0))
|
||||
#define MPFR_IS_NAN(x) (MPFR_EXP(x) == MPFR_EXP_NAN)
|
||||
#define MPFR_IS_INF(x) (MPFR_EXP(x) == MPFR_EXP_INF)
|
||||
#define MPFR_IS_NEG(x) (MPFR_SIGN(x) < 0)
|
||||
#define MPFR_IS_POS(x) (MPFR_SIGN(x) > 0)
|
||||
#define MPFR_PREC(x) ((x)->_mpfr_prec)
|
||||
|
||||
#endif
|
||||
|
|
178
src/object.cpp
178
src/object.cpp
|
@ -1,6 +1,8 @@
|
|||
#include <string>
|
||||
#include <math.h>
|
||||
using namespace std;
|
||||
|
||||
#include "mpfr.h"
|
||||
#include "constant.h"
|
||||
#include "object.hpp"
|
||||
|
||||
|
@ -18,21 +20,195 @@ string number::s_mpfr_printf_format = string(MPFR_DEFAULT_FORMAT);
|
|||
//
|
||||
const char* object::s_cmd_type_string[cmd_max] = CMD_TYPE_STRINGS;
|
||||
|
||||
static bool is_min(mpfr_t p, mpfr_prec_t prec)
|
||||
{
|
||||
// see mpfr_vasprintf code
|
||||
bool ret;
|
||||
int round_away;
|
||||
switch (floating_t::s_mpfr_rnd)
|
||||
{
|
||||
case MPFR_RNDA:
|
||||
round_away = 1;
|
||||
break;
|
||||
case MPFR_RNDD:
|
||||
round_away = MPFR_IS_NEG (p);
|
||||
break;
|
||||
case MPFR_RNDU:
|
||||
round_away = MPFR_IS_POS (p);
|
||||
break;
|
||||
case MPFR_RNDN:
|
||||
{
|
||||
/* compare |p| to y = 0.5*10^(-prec) */
|
||||
mpfr_t y;
|
||||
mpfr_exp_t e = MAX (MPFR_PREC (p), 56);
|
||||
mpfr_init2 (y, e + 8);
|
||||
do
|
||||
{
|
||||
/* find a lower approximation of
|
||||
0.5*10^(-prec) different from |p| */
|
||||
e += 8;
|
||||
mpfr_set_prec (y, e);
|
||||
mpfr_set_si (y, -prec, MPFR_RNDN);
|
||||
mpfr_exp10 (y, y, MPFR_RNDD);
|
||||
mpfr_div_2ui (y, y, 1, MPFR_RNDN);
|
||||
} while (mpfr_cmpabs (y, p) == 0);
|
||||
|
||||
round_away = mpfr_cmpabs (y, p) < 0;
|
||||
mpfr_clear (y);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
round_away = 0;
|
||||
}
|
||||
|
||||
if (round_away)
|
||||
/* round away from zero: the last output digit is '1' */
|
||||
ret = true;
|
||||
else
|
||||
/* only zeros in fractional part */
|
||||
ret = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int base_digits_from_bit_precision(int base, int bit_precision)
|
||||
{
|
||||
return (int)ceil(bit_precision * log(2.0) / log((double)base));
|
||||
}
|
||||
|
||||
static void print_fix(FILE* stream, mpfr_t real, int base)
|
||||
{
|
||||
// see mpfr_vasprintf code
|
||||
mpfr_exp_t exp = mpfr_floor_logn(real, base);
|
||||
int digits = number::s_decimal_digits;
|
||||
int i;
|
||||
|
||||
if (MPFR_UNLIKELY(MPFR_IS_SINGULAR(real)))
|
||||
{
|
||||
if (MPFR_IS_NAN(real))
|
||||
fputs("nan", stream);
|
||||
else if (MPFR_IS_INF(real))
|
||||
{
|
||||
if (MPFR_IS_NEG(real))
|
||||
fputc('-', stream);
|
||||
fputs("inf", stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
// zero
|
||||
if (MPFR_IS_NEG(real))
|
||||
fputc('-', stream);//signed zero is allowed
|
||||
fputc('0', stream);
|
||||
if (number::s_decimal_digits > 0)
|
||||
{
|
||||
fputc('.', stream);
|
||||
for(i = 0; i < digits; i++)
|
||||
fputc('0', stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (exp < -number::s_decimal_digits)
|
||||
{
|
||||
if (MPFR_IS_NEG(real))
|
||||
fputc('-', stream);
|
||||
fputc('0', stream);
|
||||
if (number::s_decimal_digits > 0)
|
||||
{
|
||||
fputc('.', stream);
|
||||
for (i = 0; i< digits - 1; i++)
|
||||
fputc('0', stream);
|
||||
|
||||
if (is_min(real, digits))
|
||||
fputc('1', stream);
|
||||
else
|
||||
fputc('0', stream);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char* str = mpfr_get_str(NULL, &exp, base, digits + exp + 1, real, floating_t::s_mpfr_rnd);
|
||||
int len = strlen(str);
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
if (str[0] == '-')
|
||||
{
|
||||
fputc(str[0], stream);
|
||||
len--;
|
||||
str++;
|
||||
}
|
||||
else if (str[0] == '+')
|
||||
{
|
||||
len--;
|
||||
str++;
|
||||
}
|
||||
if (exp < 0)
|
||||
{
|
||||
fputc('0', stream);
|
||||
if (number::s_decimal_digits > 0)
|
||||
{
|
||||
fputc('.', stream);
|
||||
for (i = 0; i < -(int)exp; i++)
|
||||
fputc('0', stream);
|
||||
fputs(str, stream);
|
||||
for (i = 0; i < (int)(number::s_decimal_digits - len + exp); i++)
|
||||
fputc('0', stream);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exp == 0)
|
||||
fputc('0', stream);
|
||||
else
|
||||
for (i = 0; i < (int)exp; i++)
|
||||
fputc(str[i], stream);
|
||||
if (number::s_decimal_digits > 0)
|
||||
{
|
||||
fputc('.', stream);
|
||||
|
||||
int remaining = (int)MIN(strlen(str) - exp - 1, digits) + 1;
|
||||
for (i = (int)exp; i < remaining + (int)exp; i++)
|
||||
fputc(str[i], stream);
|
||||
for (i = 0; i < (int)(exp + digits - len); i++)
|
||||
fputc('0', stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void object::show(FILE* stream)
|
||||
{
|
||||
int digits;
|
||||
char* str;
|
||||
|
||||
switch(_type)
|
||||
{
|
||||
case cmd_number:
|
||||
switch(number::s_mode)
|
||||
{
|
||||
case number::fix:
|
||||
//printf("OLD: ");
|
||||
//mpfr_fprintf(stream, number::s_mpfr_printf_format.c_str(), ((number*)this)->_value.mpfr);
|
||||
print_fix(stream, ((number*)this)->_value.mpfr, 2);
|
||||
break;
|
||||
}
|
||||
switch(((number*)this)->_representation)
|
||||
{
|
||||
case number::dec:
|
||||
mpfr_fprintf(stream, number::s_mpfr_printf_format.c_str(), ((number*)this)->_value.mpfr);
|
||||
break;
|
||||
case number::hex:
|
||||
mpfr_fprintf(stream, string(MPFR_FORMAT_HEX).c_str(), ((number*)this)->_value.mpfr);
|
||||
fprintf(stream, "0x");
|
||||
print_fix(stream, ((number*)this)->_value.mpfr, 16);
|
||||
//mpfr_fprintf(stream, string(MPFR_FORMAT_HEX).c_str(), ((number*)this)->_value.mpfr);
|
||||
break;
|
||||
case number::bin:
|
||||
fprintf(stream, "0b");
|
||||
print_fix(stream, ((number*)this)->_value.mpfr, 2);
|
||||
break;
|
||||
default:
|
||||
fprintf(stream, "<unknown number representation>");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case cmd_complex:
|
||||
|
|
|
@ -69,14 +69,14 @@ string make_digit_format(int decimal_digits, const char* printf_format)
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
bool check_precision_inbound(double precision)
|
||||
bool check_decimal_digits(double precision)
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
// MPFR_PREC_MAX mpfr_prec_t depends on _MPFR_PREC_FORMAT macro (see mpfr.h)
|
||||
// this could not exceed 63 bits max (0x7FFFFFFFFFFFFFFF)
|
||||
double prec_max = (double)MPFR_PREC_MAX;
|
||||
double prec_min = (double)MPFR_PREC_MIN;
|
||||
double prec_min = 0.0;
|
||||
|
||||
if (precision < prec_min || precision > prec_max)
|
||||
ret = false;
|
||||
|
@ -88,7 +88,7 @@ void std()
|
|||
{
|
||||
// to std mode
|
||||
number::s_mode = number::std;
|
||||
|
||||
|
||||
// calc max nb of digits user can see with the current bit precision
|
||||
number::s_decimal_digits = decimal_digits_from_bit_precision(floating_t::s_mpfr_prec);
|
||||
number::s_mpfr_printf_format = make_digit_format(number::s_decimal_digits, MPFR_FORMAT_STD);
|
||||
|
@ -101,7 +101,7 @@ void fix()
|
|||
|
||||
double precision = double(((number*)_stack->pop_back())->_value);
|
||||
|
||||
if (check_precision_inbound(precision))
|
||||
if (check_decimal_digits(precision))
|
||||
{
|
||||
// set mode, precision, decimal digits and print format
|
||||
number::s_mode = number::fix;
|
||||
|
@ -119,7 +119,7 @@ void sci()
|
|||
|
||||
double precision = double(((number*)_stack->pop_back())->_value);
|
||||
|
||||
if (check_precision_inbound(precision))
|
||||
if (check_decimal_digits(precision))
|
||||
{
|
||||
// set mode, precision, decimal digits and print format
|
||||
number::s_mode = number::sci;
|
||||
|
|
Loading…
Reference in a new issue