32 #ifndef _QORE_QORE_NUMBER_PRIVATE_H
34 #define _QORE_QORE_NUMBER_PRIVATE_H
41 #define QORE_MPFR_ROUND_THRESHOLD 9
43 #define QORE_MPFR_ROUND_THRESHOLD_2 15
46 #define QORE_NUM_ALL_DIGITS -999999
48 #define QORE_DEFAULT_PREC 128
49 #define QORE_MAX_PREC 8192
50 #ifndef HAVE_MPFR_RNDN
51 #define MPFR_RNDN GMP_RNDN
52 #define MPFR_RNDZ GMP_RNDZ
55 #define QORE_MPFR_RND MPFR_RNDN
57 #define QORE_MPFR_RNDZ MPFR_RNDZ
60 #ifndef HAVE_MPFR_EXP_T
61 typedef mp_exp_t mpfr_exp_t;
64 #ifdef HAVE_MPFR_SPRINTF
65 #define QORE_MPFR_SPRINTF_ARG 'R'
67 #define QORE_MPFR_SPRINTF_ARG 'L'
74 #if defined(HAVE_LOCAL_VARIADIC_ARRAYS) && !(defined(SPARC) && defined(SOLARIS) && defined(__GNUC__))
75 #define MPFR_TMP_VAR(x, p) MPFR_DECL_INIT(x, (p))
77 #define MPFR_TMP_VAR(x, p) qore_number_private tmp_x((mpfr_prec_t)p); mpfr_t& x = tmp_x.num
81 typedef int (*q_mpfr_binary_func_t)(mpfr_t,
const mpfr_t,
const mpfr_t, mpfr_rnd_t);
83 typedef int (*q_mpfr_unary_func_t)(mpfr_t,
const mpfr_t, mpfr_rnd_t);
85 typedef int (*q_mpfr_unary_nr_func_t)(mpfr_t,
const mpfr_t);
87 hashdecl qore_number_private_intern {
90 DLLLOCAL qore_number_private_intern() {
91 mpfr_init2(num, QORE_DEFAULT_PREC);
94 DLLLOCAL qore_number_private_intern(mpfr_prec_t prec) {
95 if (prec > QORE_MAX_PREC)
97 mpfr_init2(num, prec);
100 DLLLOCAL ~qore_number_private_intern() {
104 DLLLOCAL
void checkPrec(q_mpfr_binary_func_t func,
const mpfr_t r) {
106 if (func == mpfr_mul || func == mpfr_div) {
107 prec = mpfr_get_prec(num) + mpfr_get_prec(r);
109 prec =
QORE_MAX(mpfr_get_prec(num), mpfr_get_prec(r)) + 1;
111 if (prec > mpfr_get_prec(num))
112 mpfr_prec_round(num, prec, QORE_MPFR_RND);
115 DLLLOCAL
void setPrec(mpfr_prec_t prec) {
116 if (prec > QORE_MAX_PREC)
117 prec = QORE_MAX_PREC;
118 mpfr_prec_round(num, prec, QORE_MPFR_RND);
121 DLLLOCAL
static void do_divide_by_zero(
ExceptionSink* xsink) {
122 xsink->
raiseException(
"DIVISION-BY-ZERO",
"division by zero error in numeric operator");
126 #ifdef HAVE_MPFR_DIVBY0
127 if (mpfr_divby0_p()) {
129 do_divide_by_zero(xsink);
132 if (mpfr_erangeflag_p()) {
133 mpfr_clear_erangeflag();
134 xsink->
raiseException(
"INVALID-NUMERIC-OPERATION",
"invalid numeric operation attempted");
139 hashdecl qore_number_private :
public qore_number_private_intern {
140 DLLLOCAL
explicit qore_number_private(mpfr_prec_t prec) : qore_number_private_intern(prec) {
143 DLLLOCAL qore_number_private(
double f) {
152 QoreStringMaker str(
"%.17g", f);
153 mpfr_set_str(num, str.getBuffer(), 10, QORE_MPFR_RND);
156 DLLLOCAL qore_number_private(
int64 i) {
157 mpfr_set_sj(num, i, QORE_MPFR_RND);
160 DLLLOCAL qore_number_private(
const char* str) : qore_number_private_intern(
QORE_MAX(QORE_DEFAULT_PREC, strlen(str)*5)) {
162 const char* p =
strchrs(str,
"eE");
164 int exp = abs(atoi(p + 1));
165 mpfr_prec_t np = exp * 5;
170 mpfr_set_sj(num, 0, QORE_MPFR_RND);
172 mpfr_set_str(num, str, 10, QORE_MPFR_RND);
175 DLLLOCAL qore_number_private(
const char* str,
unsigned prec) : qore_number_private_intern(
QORE_MAX(QORE_DEFAULT_PREC, prec)) {
176 mpfr_set_str(num, str, 10, QORE_MPFR_RND);
179 DLLLOCAL qore_number_private(
const qore_number_private& old) : qore_number_private_intern(mpfr_get_prec(old.num)) {
180 mpfr_set(num, old.num, QORE_MPFR_RND);
183 DLLLOCAL
double getAsFloat()
const {
184 return mpfr_get_d(num, QORE_MPFR_RND);
187 DLLLOCAL
int64 getAsBigInt()
const {
188 return mpfr_get_sj(num, QORE_MPFR_RNDZ);
191 DLLLOCAL
bool getAsBool()
const {
195 DLLLOCAL
bool zero()
const {
196 return (
bool)mpfr_zero_p(num);
199 DLLLOCAL
bool nan()
const {
200 return (
bool)mpfr_nan_p(num);
203 DLLLOCAL
bool inf()
const {
204 return (
bool)mpfr_inf_p(num);
207 DLLLOCAL
bool number()
const {
208 return (
bool)mpfr_number_p(num);
211 #ifdef HAVE_MPFR_REGULAR
213 DLLLOCAL
bool regular()
const {
214 return (
bool)mpfr_regular_p(num);
218 DLLLOCAL
int sign()
const {
219 return mpfr_sgn(num);
222 DLLLOCAL
void sprintf(
QoreString& str,
const char* fmt)
const {
223 #ifdef HAVE_MPFR_SPRINTF
225 int len = mpfr_snprintf(0, 0, fmt, num);
233 mpfr_sprintf((
char*)(str.
getBuffer() + str.
size()), fmt, num);
237 long double ld = mpfr_get_ld(num, QORE_MPFR_RND);
238 int len = ::snprintf(0, 0, fmt, ld);
247 DLLLOCAL
void getScientificString(
QoreString& str,
bool round =
true)
const {
248 #ifdef HAVE_MPFR_SPRINTF
259 applyRoundingHeuristic(str, i, e);
264 DLLLOCAL
void getAsString(
QoreString& str,
bool round =
true,
int base = 10)
const;
266 DLLLOCAL
void toString(
QoreString& str,
int fmt = QORE_NF_DEFAULT)
const {
267 bool raw = !(fmt & QORE_NF_RAW);
268 if (fmt & QORE_NF_SCIENTIFIC)
269 getScientificString(str, raw);
271 getAsString(str, raw);
276 return formatNumberString(str, fmt, xsink);
281 return formatNumberString(str, prec, dsep_str, tsep_str, xsink);
284 DLLLOCAL
bool lessThan(
const qore_number_private& right)
const {
285 return mpfr_less_p(num, right.num);
288 DLLLOCAL
bool lessThan(
double right)
const {
289 MPFR_TMP_VAR(r, QORE_DEFAULT_PREC);
290 if (mpfr_nan_p(num) || std::isnan(right))
292 mpfr_set_d(r, right, QORE_MPFR_RND);
293 return mpfr_less_p(num, r);
296 DLLLOCAL
bool lessThan(
int64 right)
const {
297 MPFR_TMP_VAR(r, QORE_DEFAULT_PREC);
300 mpfr_set_sj(r, right, QORE_MPFR_RND);
301 return mpfr_less_p(num, r);
304 DLLLOCAL
bool lessThanOrEqual(
const qore_number_private& right)
const {
305 return mpfr_lessequal_p(num, right.num);
308 DLLLOCAL
bool lessThanOrEqual(
double right)
const {
309 MPFR_TMP_VAR(r, QORE_DEFAULT_PREC);
310 if (mpfr_nan_p(num) || std::isnan(right))
312 mpfr_set_d(r, right, QORE_MPFR_RND);
313 return mpfr_lessequal_p(num, r);
316 DLLLOCAL
bool lessThanOrEqual(
int64 right)
const {
317 MPFR_TMP_VAR(r, QORE_DEFAULT_PREC);
320 mpfr_set_sj(r, right, QORE_MPFR_RND);
321 return mpfr_lessequal_p(num, r);
324 DLLLOCAL
bool greaterThan(
const qore_number_private& right)
const {
325 return mpfr_greater_p(num, right.num);
328 DLLLOCAL
bool greaterThan(
double right)
const {
329 MPFR_TMP_VAR(r, QORE_DEFAULT_PREC);
330 if (mpfr_nan_p(num) || std::isnan(right))
332 mpfr_set_d(r, right, QORE_MPFR_RND);
333 return mpfr_greater_p(num, r);
336 DLLLOCAL
bool greaterThan(
int64 right)
const {
337 MPFR_TMP_VAR(r, QORE_DEFAULT_PREC);
340 mpfr_set_sj(r, right, QORE_MPFR_RND);
341 return mpfr_greater_p(num, r);
344 DLLLOCAL
bool greaterThanOrEqual(
const qore_number_private& right)
const {
345 return mpfr_greaterequal_p(num, right.num);
348 DLLLOCAL
bool greaterThanOrEqual(
double right)
const {
349 MPFR_TMP_VAR(r, QORE_DEFAULT_PREC);
350 if (mpfr_nan_p(num) || std::isnan(right))
352 mpfr_set_d(r, right, QORE_MPFR_RND);
353 return mpfr_greaterequal_p(num, r);
356 DLLLOCAL
bool greaterThanOrEqual(
int64 right)
const {
357 MPFR_TMP_VAR(r, QORE_DEFAULT_PREC);
360 mpfr_set_sj(r, right, QORE_MPFR_RND);
361 return mpfr_greaterequal_p(num, r);
364 DLLLOCAL
bool equals(
const qore_number_private& right)
const {
365 return mpfr_equal_p(num, right.num);
368 DLLLOCAL
bool equals(
double right)
const {
369 if (mpfr_nan_p(num) || std::isnan(right))
371 return 0 == mpfr_cmp_d(num, right);
374 DLLLOCAL
bool equals(
int64 right)
const {
375 MPFR_TMP_VAR(r, QORE_DEFAULT_PREC);
378 mpfr_set_sj(r, right, QORE_MPFR_RND);
379 return mpfr_equal_p(num, r);
382 DLLLOCAL qore_number_private* doBinary(q_mpfr_binary_func_t func,
const qore_number_private& r,
ExceptionSink* xsink = 0)
const {
384 if (func == mpfr_pow) {
385 prec = mpfr_get_prec(num) *
QORE_MIN(QORE_MAX_PREC, r.getAsBigInt());
386 }
else if (func == mpfr_mul || func == mpfr_div) {
387 prec = mpfr_get_prec(num) + mpfr_get_prec(r.num);
389 prec =
QORE_MAX(mpfr_get_prec(num), mpfr_get_prec(r.num)) + 1;
391 std::unique_ptr<qore_number_private> p(
new qore_number_private(prec));
392 func(p->num, num, r.num, QORE_MPFR_RND);
396 return (xsink && *xsink) ? 0 : p.release();
399 DLLLOCAL qore_number_private* doPlus(
const qore_number_private& r)
const {
400 return doBinary(mpfr_add, r);
403 DLLLOCAL qore_number_private* doMinus(
const qore_number_private& r)
const {
404 return doBinary(mpfr_sub, r);
407 DLLLOCAL qore_number_private* doMultiply(
const qore_number_private& r)
const {
408 return doBinary(mpfr_mul, r);
411 DLLLOCAL qore_number_private* doDivideBy(
const qore_number_private& r,
ExceptionSink* xsink)
const {
412 #ifndef HAVE_MPFR_DIVBY0
414 do_divide_by_zero(xsink);
418 return doBinary(mpfr_div, r, xsink);
421 DLLLOCAL qore_number_private* doUnary(q_mpfr_unary_func_t func,
ExceptionSink* xsink = 0)
const {
422 qore_number_private* p =
new qore_number_private(*
this);
423 func(p->num, num, QORE_MPFR_RND);
430 DLLLOCAL
void negateInPlace() {
431 mpfr_neg(num, num, QORE_MPFR_RND);
434 DLLLOCAL qore_number_private* negate()
const {
435 return doUnary(mpfr_neg);
438 DLLLOCAL qore_number_private* absolute()
const {
439 return doUnary(mpfr_abs);
442 DLLLOCAL qore_number_private* doUnaryNR(q_mpfr_unary_nr_func_t func,
ExceptionSink* xsink = 0)
const {
443 qore_number_private* p =
new qore_number_private(*
this);
452 DLLLOCAL qore_number_private* doRoundNR(q_mpfr_unary_nr_func_t func,
int prec = 0,
ExceptionSink* xsink = NULL)
const {
453 unique_ptr<qore_number_private> p0(
new qore_number_private(*
this));
456 func(p0 -> num, num);
464 qore_number_private* p2;
467 unique_ptr<qore_number_private> c(
new qore_number_private(pow(10, prec)));
468 unique_ptr<qore_number_private> p1(p0 -> doMultiply(*c));
469 func(p1 -> num, p1 -> num);
470 p2 = p1 -> doDivideBy(*c, xsink);
472 unique_ptr<qore_number_private> c(
new qore_number_private(pow(10, -prec)));
473 unique_ptr<qore_number_private> p1(p0 -> doDivideBy(*c, xsink));
474 func(p1 -> num, p1 -> num);
475 p2 = p1 -> doMultiply(*c);
484 DLLLOCAL mpfr_prec_t getPrec()
const {
485 return mpfr_get_prec(num);
488 DLLLOCAL
void inc() {
489 MPFR_TMP_VAR(tmp, mpfr_get_prec(num));
490 mpfr_set(tmp, num, QORE_MPFR_RND);
491 mpfr_add_si(num, tmp, 1, QORE_MPFR_RND);
494 DLLLOCAL
void dec() {
495 MPFR_TMP_VAR(tmp, mpfr_get_prec(num));
496 mpfr_set(tmp, num, QORE_MPFR_RND);
497 mpfr_sub_si(num, tmp, 1, QORE_MPFR_RND);
500 DLLLOCAL
void doBinaryInplace(q_mpfr_binary_func_t func,
const qore_number_private& r,
ExceptionSink* xsink = 0) {
501 checkPrec(func, r.num);
504 MPFR_TMP_VAR(tmp, mpfr_get_prec(num));
505 mpfr_set(tmp, num, QORE_MPFR_RND);
506 func(num, tmp, r.num, QORE_MPFR_RND);
511 DLLLOCAL
void plusEquals(
const qore_number_private& r) {
512 doBinaryInplace(mpfr_add, r);
515 DLLLOCAL
void minusEquals(
const qore_number_private& r) {
516 doBinaryInplace(mpfr_sub, r);
519 DLLLOCAL
void multiplyEquals(
const qore_number_private& r) {
520 doBinaryInplace(mpfr_mul, r);
523 DLLLOCAL
void divideEquals(
const qore_number_private& r) {
525 doBinaryInplace(mpfr_div, r);
529 n.
priv->negateInPlace();
543 DLLLOCAL
static void numError(
QoreString& str) {
544 str.
concat(
"<number error>");
548 DLLLOCAL
static void applyRoundingHeuristic(
QoreString& str,
size_t dp,
size_t last,
549 int round_threshold_1 = QORE_MPFR_ROUND_THRESHOLD,
int round_threshold_2 = QORE_MPFR_ROUND_THRESHOLD_2);
554 DLLLOCAL
static void applyRoundingHeuristicToString(
QoreString& str,
int round_threshold_1 = QORE_MPFR_ROUND_THRESHOLD,
555 int round_threshold_2 = QORE_MPFR_ROUND_THRESHOLD_2) {
558 applyRoundingHeuristic(str, i, str.
size(), round_threshold_1, round_threshold_2);
567 n.
priv->sprintf(str, fmt);
595 qore_number_private* p = n.
priv->doUnary(func, xsink);
600 qore_number_private* p = n.
priv->doBinary(func, *r.
priv, xsink);
605 qore_number_private* p = n.
priv->doUnaryNR(func, xsink);
610 qore_number_private* p = n.
priv->doRoundNR(func, prec, xsink);
623 qore_number_private* p =
new qore_number_private(0ll);
624 mpfr_const_pi(p->num, QORE_MPFR_RND);
628 DLLLOCAL
static qore_number_private* get(
const QoreNumberNode& n) {
633 std::unique_ptr<qore_number_private> n(
new qore_number_private(f));
634 return qore_number_private::toBase(n.get(), base, xsink);
638 return qore_number_private::toBase(n.
priv, base, xsink);
642 if (base < 2 || base > 36) {
643 xsink -> raiseException(
"INVALID-BASE",
"base %d is invalid; base must be 2 - 36 inclusive", base);
648 n -> getAsString(qs, 1, base);
static char * strchrs(const char *str, const char *chars)
find one of any characters in a string
Definition: QoreLib.h:247
#define QORE_MAX(a, b)
macro to return the maximum of 2 numbers
Definition: QoreLib.h:547
#define QORE_MIN(a, b)
macro to return the minimum of 2 numbers
Definition: QoreLib.h:550
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:48
DLLEXPORT AbstractQoreNode * raiseException(const char *err, const char *fmt,...)
appends a Qore-language exception to the list
Qore's arbitrary-precision number value type, dynamically-allocated only, reference counted.
Definition: QoreNumberNode.h:51
hashdecl qore_number_private * priv
the private implementation of the type
Definition: QoreNumberNode.h:69
Qore's string type supported by the QoreEncoding class.
Definition: QoreString.h:93
DLLEXPORT void terminate(size_t size)
terminates the string at byte position "size", the string is reallocated if necessary
DLLEXPORT void allocate(unsigned requested_size)
Ensure the internal buffer has at least expected size in bytes.
DLLEXPORT void concat(const QoreString *str, ExceptionSink *xsink)
concatenates a string and converts encodings if necessary
DLLEXPORT qore_offset_t find(char c, qore_offset_t pos=0) const
returns the byte position of a character (byte) within the string or -1 if not found
DLLEXPORT size_t size() const
returns number of bytes in the string (not including the null pointer)
DLLEXPORT void toupr()
converts the string to upper-case in place
DLLEXPORT qore_offset_t rfind(char c, qore_offset_t pos=-1) const
returns the last byte position of a character (byte) within the string or -1 if not found
DLLEXPORT const char * getBuffer() const
returns the string's buffer; this data should not be changed
Qore's string value type, reference counted, dynamically-allocated only.
Definition: QoreStringNode.h:50
intptr_t qore_offset_t
used for offsets that could be negative
Definition: common.h:76
long long int64
64bit integer type, cannot use int64_t here since it breaks the API on some 64-bit systems due to equ...
Definition: common.h:260