#168: std is now unary and auto calcs its decimal digits nb, modified hel pmessage, added bounds check for precision in sci and fix

This commit is contained in:
Louis Rubet 2017-06-25 01:29:53 +02:00
parent 5033746821
commit cdb129819d
8 changed files with 102 additions and 64 deletions

View file

@ -37,9 +37,9 @@ rpn> 1.0986122886681096914
### **arbitrary precision**
Precision can be really high, up to 0x7FFFFFFFFFFFFFFF bits with GNU MPFR
```
rpn> 256 prec 200 std
rpn> pi 3 * 4 / cos
-0.707106781186547524400844362104849039284835937688474036588339868995366239(...)
rpn> 256 prec
rpn> pi
3.1415926535897932384626433832795028841971693993751058209749445923078164062862
rpn>
```
@ -136,7 +136,7 @@ exit chs sqrt % ceil conj fix >= xor
|keyword|description|
|-|-|
|std| standard floating numbers representation. ex: [25] std
|std| standard floating numbers representation. ex: std
|fix| fixed point representation. ex: 6 fix
|sci| scientific floating point representation. ex: 20 sci
|prec| get float precision in bits when first stack is not a number, set float precision in bits when first stack entry is a number. ex: ```256 prec```
@ -268,7 +268,7 @@ exit chs sqrt % ceil conj fix >= xor
### default
Default float mode is 'std' with 20 digits
Default float mode is 'std' with 39 digits
Default floating point precision is 128 bits

View file

@ -7,8 +7,11 @@
// default mode and number of printed digits
//
#define DEFAULT_MODE number::std
#define DEFAULT_PRECISION 20
#define MPFR_DEFAULT_FORMAT "%.20Rg"
#define MPFR_DEFAULT_FORMAT "%.xxRg"
/* directly calculated from 128 bits precision
ceil(128 * log10(2) = 39) */
#define DEFAULT_DECIMAL_DIGITS 39
// MPFR related defaults
//

View file

@ -12,7 +12,7 @@ const char* floating_t::s_mpfr_rnd_str[5] = MPFR_RND_STRINGS;
// number statics
number::mode_enum number::s_mode = DEFAULT_MODE;
int number::s_current_precision = DEFAULT_PRECISION;
int number::s_decimal_digits = DEFAULT_DECIMAL_DIGITS;
string number::s_mpfr_printf_format = string(MPFR_DEFAULT_FORMAT);
//

View file

@ -62,6 +62,11 @@ struct floating_t
mpfr_set_ui(mpfr, val, s_mpfr_rnd);
}
operator double()
{
return mpfr_get_d(mpfr, s_mpfr_rnd);
}
operator int()
{
return (int)mpfr_get_si(mpfr, s_mpfr_rnd);
@ -154,7 +159,7 @@ struct number : public object
static mode_enum s_mode;
// precision
static int s_current_precision;
static int s_decimal_digits;
static string s_mpfr_printf_format;
};

View file

@ -67,7 +67,7 @@ program::keyword_t program::s_keywords[] =
//MODE
{ cmd_undef, "", NULL, "\nMODE"},
{ cmd_keyword, "std", &program::std, "standard floating numbers representation. ex: [25] std" },
{ cmd_keyword, "std", &program::std, "standard floating numbers representation. ex: std" },
{ cmd_keyword, "fix", &program::fix, "fixed point representation. ex: 6 fix" },
{ cmd_keyword, "sci", &program::sci, "scientific floating point representation. ex: 20 sci" },
{ cmd_keyword, "prec", &program::precision, "get float precision in bits when first stack is not a number\n\t"

View file

@ -5,6 +5,7 @@
#include <stdlib.h>
#include <stdint.h>
#include <sys/mman.h>
#include <math.h>
extern "C" {
#include <readline/readline.h>
@ -525,11 +526,11 @@ public:
{
//default float precision, float mode
number::s_mode = DEFAULT_MODE;
number::s_current_precision = DEFAULT_PRECISION;
number::s_decimal_digits = DEFAULT_DECIMAL_DIGITS;
// format for mpfr_printf
stringstream ss;
ss << number::s_current_precision;
ss << number::s_decimal_digits;
number::s_mpfr_printf_format = string(MPFR_FORMAT_BEG) + ss.str() + string(MPFR_FORMAT_STD);
// default calc precision for MPFR

View file

@ -47,39 +47,51 @@ void help()
case number::sci: printf("'sci'"); break;
default: printf("unknown"); break;
}
printf(" with %d digits\n", number::s_current_precision);
printf(" with %d decimal digits shown\n", number::s_decimal_digits);
// calc precision and rounding mode
// 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_min = (double)MPFR_PREC_MIN;
double prec_max = (double)MPFR_PREC_MAX;
printf("Current floating point precision is %d bits (min=%ld bits, max=0x%lx bits)\n", (int)floating_t::s_mpfr_prec, (int64_t)prec_min, (int64_t)prec_max);
// bits precision, decimal digits and rounding mode
printf("Current floating point precision is %d bits\n", (int)floating_t::s_mpfr_prec);
printf("Current rounding mode is '%s'\n", floating_t::s_mpfr_rnd_str[floating_t::s_mpfr_rnd]);
printf("\n\n");
}
int decimal_digits_from_bit_precision(int bit_precision)
{
return (int)ceil(bit_precision * log10(2.0));
}
string make_digit_format(int decimal_digits, const char* printf_format)
{
stringstream ss;
ss << MPFR_FORMAT_BEG;
ss << number::s_decimal_digits;
ss << printf_format;
return ss.str();
}
bool check_precision_inbound(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;
if (precision < prec_min || precision > prec_max)
ret = false;
return ret;
}
void std()
{
int precision = -1;
if (stack_size()>=1)
{
ARG_MUST_BE_OF_TYPE(0, cmd_number);
precision = int(((number*)_stack->pop_back())->_value);
}
if (precision != -1)
number::s_current_precision = precision;
// to std mode
number::s_mode = number::std;
// format for mpfr_printf
stringstream ss;
ss << number::s_current_precision;
number::s_mpfr_printf_format = string(MPFR_FORMAT_BEG) + ss.str() + string(MPFR_FORMAT_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);
}
void fix()
@ -87,15 +99,17 @@ void fix()
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
int precision = int(((number*)_stack->pop_back())->_value);
number::s_current_precision = int(precision);
number::s_mode = number::fix;
// format for mpfr_printf
stringstream ss;
ss << number::s_current_precision;
number::s_mpfr_printf_format = string(MPFR_FORMAT_BEG) + ss.str() + string(MPFR_FORMAT_FIX);
double precision = double(((number*)_stack->pop_back())->_value);
if (check_precision_inbound(precision))
{
// set mode, precision, decimal digits and print format
number::s_mode = number::fix;
number::s_decimal_digits = (int)precision;
number::s_mpfr_printf_format = make_digit_format(number::s_decimal_digits, MPFR_FORMAT_FIX);
}
else
ERR_CONTEXT(ret_out_of_range);
}
void sci()
@ -103,15 +117,17 @@ void sci()
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
int precision = int(((number*)_stack->pop_back())->_value);
number::s_current_precision = int(precision);
number::s_mode = number::sci;
// format for mpfr_printf
stringstream ss;
ss << number::s_current_precision;
number::s_mpfr_printf_format = string(MPFR_FORMAT_BEG) + ss.str() + string(MPFR_FORMAT_SCI);
double precision = double(((number*)_stack->pop_back())->_value);
if (check_precision_inbound(precision))
{
// set mode, precision, decimal digits and print format
number::s_mode = number::sci;
number::s_decimal_digits = (int)precision;
number::s_mpfr_printf_format = make_digit_format(number::s_decimal_digits, MPFR_FORMAT_SCI);
}
else
ERR_CONTEXT(ret_out_of_range);
}
void rpn_version()
@ -173,6 +189,14 @@ void precision()
{
floating_t::s_mpfr_prec = (mpfr_prec_t)prec;
floating_t::s_mpfr_prec_bytes = mpfr_custom_get_size(prec);
// modify digits seen by user if std mode
if (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);
}
}
else
ERR_CONTEXT(ret_out_of_range);

View file

@ -3,19 +3,14 @@ default erase
# std (1)
erase
1
10 std
-> stack should be 1
std
-> stack size should be 0
-> error should be 0
erase
# std (2)
1 3 /
-> stack should be 0.3333333333
erase
# std (3)
1 3 / 3 std
-> stack should be 0.333
-> stack should be 0.333333333333333333333333333333333333334
erase
# fix (1)
@ -29,6 +24,11 @@ erase
-> stack should be 1.0000
erase
# fix (3)
1 fix
-> error should be 4
erase
# sci (1)
1 12 sci
-> stack should be 1.000000000000e+00
@ -39,4 +39,9 @@ erase
-> stack should be 1.00e+00
erase
# sci (3)
1 sci
-> error should be 4
erase
default