From cdb129819da834d4d6f0f0b0154298e96d6a161a Mon Sep 17 00:00:00 2001 From: Louis Rubet Date: Sun, 25 Jun 2017 01:29:53 +0200 Subject: [PATCH] #168: std is now unary and auto calcs its decimal digits nb, modified hel pmessage, added bounds check for precision in sci and fix --- MANUAL.md | 10 ++-- src/constant.h | 7 ++- src/object.cpp | 2 +- src/object.hpp | 7 ++- src/program.cpp | 2 +- src/program.hpp | 5 +- src/rpn-general.hpp | 110 +++++++++++++++++++++++++++----------------- test/01-mode.txt | 23 +++++---- 8 files changed, 102 insertions(+), 64 deletions(-) diff --git a/MANUAL.md b/MANUAL.md index 419e31a..39e8601 100644 --- a/MANUAL.md +++ b/MANUAL.md @@ -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 diff --git a/src/constant.h b/src/constant.h index 8c26040..2b93b0b 100644 --- a/src/constant.h +++ b/src/constant.h @@ -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 // diff --git a/src/object.cpp b/src/object.cpp index 199c8f2..d87e6c5 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -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); // diff --git a/src/object.hpp b/src/object.hpp index 099ecf1..b9c5643 100644 --- a/src/object.hpp +++ b/src/object.hpp @@ -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; }; diff --git a/src/program.cpp b/src/program.cpp index 6eda1a2..e842a3c 100644 --- a/src/program.cpp +++ b/src/program.cpp @@ -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" diff --git a/src/program.hpp b/src/program.hpp index c5481f7..7689c61 100644 --- a/src/program.hpp +++ b/src/program.hpp @@ -5,6 +5,7 @@ #include #include #include +#include extern "C" { #include @@ -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 diff --git a/src/rpn-general.hpp b/src/rpn-general.hpp index 3fff5a4..5e6b5f4 100644 --- a/src/rpn-general.hpp +++ b/src/rpn-general.hpp @@ -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); diff --git a/test/01-mode.txt b/test/01-mode.txt index 4f36022..2042446 100644 --- a/test/01-mode.txt +++ b/test/01-mode.txt @@ -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