Qore Programming Language  1.12.0
qore_number_private.h
1 /* -*- mode: c++; indent-tabs-mode: nil -*- */
2 /*
3  qore_number_private.h
4 
5  Qore Programming Language
6 
7  Copyright (C) 2003 - 2022 Qore Technologies, s.r.o.
8 
9  Permission is hereby granted, free of charge, to any person obtaining a
10  copy of this software and associated documentation files (the "Software"),
11  to deal in the Software without restriction, including without limitation
12  the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  and/or sell copies of the Software, and to permit persons to whom the
14  Software is furnished to do so, subject to the following conditions:
15 
16  The above copyright notice and this permission notice shall be included in
17  all copies or substantial portions of the Software.
18 
19  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  DEALINGS IN THE SOFTWARE.
26 
27  Note that the Qore library is released under a choice of three open-source
28  licenses: MIT (as above), LGPL 2+, or GPL 2+; see README-LICENSE for more
29  information.
30 */
31 
32 #ifndef _QORE_QORE_NUMBER_PRIVATE_H
33 
34 #define _QORE_QORE_NUMBER_PRIVATE_H
35 
36 #include <cmath>
37 #include <memory>
38 using namespace std;
39 
40 // the number of consecutive trailing 0 or 9 digits that will be rounded in string output
41 #define QORE_MPFR_ROUND_THRESHOLD 9
42 // the number of consecutive trailing 0 or 9 digits that will be rounded in string output if there are 2 trailing non-0/9 digits
43 #define QORE_MPFR_ROUND_THRESHOLD_2 15
44 
45 // the magic precesion number that indicates that all decimals should be included in the output string when formatting
46 #define QORE_NUM_ALL_DIGITS -999999
47 
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
53 #endif
54 // round to nearest (roundTiesToEven in IEEE 754-2008)
55 #define QORE_MPFR_RND MPFR_RNDN
56 // round toward zero
57 #define QORE_MPFR_RNDZ MPFR_RNDZ
58 // MPFR_RNDA
59 
60 #ifndef HAVE_MPFR_EXP_T
61 typedef mp_exp_t mpfr_exp_t;
62 #endif
63 
64 #ifdef HAVE_MPFR_SPRINTF
65 #define QORE_MPFR_SPRINTF_ARG 'R'
66 #else
67 #define QORE_MPFR_SPRINTF_ARG 'L'
68 #endif
69 
70 // some compilers (sun/oracle pro c notably) do not support arrays with a variable size
71 // if not, we can't use the stack for the temporary variable and have to use a dynamically-allocated one
72 // also MPFR_DECL_INIT is compiled incorrectly on g 5.2 on Solaris SPARC with all optimization levels
73 // for some unknown reason (https://github.com/qorelanguage/qore/issues/958)
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))
76 #else
77 #define MPFR_TMP_VAR(x, p) qore_number_private tmp_x((mpfr_prec_t)p); mpfr_t& x = tmp_x.num
78 #endif
79 
80 // for binary operations on MPFR data
81 typedef int (*q_mpfr_binary_func_t)(mpfr_t, const mpfr_t, const mpfr_t, mpfr_rnd_t);
82 // for unary operations on MPFR data
83 typedef int (*q_mpfr_unary_func_t)(mpfr_t, const mpfr_t, mpfr_rnd_t);
84 // for unary operations on MPFR data without a rounding argument
85 typedef int (*q_mpfr_unary_nr_func_t)(mpfr_t, const mpfr_t);
86 
87 hashdecl qore_number_private_intern {
88  mpfr_t num;
89 
90  DLLLOCAL qore_number_private_intern() {
91  mpfr_init2(num, QORE_DEFAULT_PREC);
92  }
93 
94  DLLLOCAL qore_number_private_intern(mpfr_prec_t prec) {
95  if (prec > QORE_MAX_PREC)
96  prec = QORE_MAX_PREC;
97  mpfr_init2(num, prec);
98  }
99 
100  DLLLOCAL ~qore_number_private_intern() {
101  mpfr_clear(num);
102  }
103 
104  DLLLOCAL void checkPrec(q_mpfr_binary_func_t func, const mpfr_t r) {
105  mpfr_prec_t prec;
106  if (func == mpfr_mul || func == mpfr_div) {
107  prec = mpfr_get_prec(num) + mpfr_get_prec(r);
108  } else {
109  prec = QORE_MAX(mpfr_get_prec(num), mpfr_get_prec(r)) + 1;
110  }
111  if (prec > mpfr_get_prec(num))
112  mpfr_prec_round(num, prec, QORE_MPFR_RND);
113  }
114 
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);
119  }
120 
121  DLLLOCAL static void do_divide_by_zero(ExceptionSink* xsink) {
122  xsink->raiseException("DIVISION-BY-ZERO", "division by zero error in numeric operator");
123  }
124 
125  DLLLOCAL static void checkFlags(ExceptionSink* xsink) {
126 #ifdef HAVE_MPFR_DIVBY0
127  if (mpfr_divby0_p()) {
128  mpfr_clear_divby0();
129  do_divide_by_zero(xsink);
130  }
131 #endif
132  if (mpfr_erangeflag_p()) {
133  mpfr_clear_erangeflag();
134  xsink->raiseException("INVALID-NUMERIC-OPERATION", "invalid numeric operation attempted");
135  }
136  }
137 };
138 
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) {
141  }
142 
143  DLLLOCAL qore_number_private(double f) {
144  /* from the MPFR docs: http://www.mpfr.org/mpfr-current/mpfr.html
145  Note: If you want to store a floating-point constant to a mpfr_t, you should use mpfr_set_str
146  (or one of the MPFR constant functions, such as mpfr_const_pi for Pi) instead of mpfr_set_flt,
147  mpfr_set_d, mpfr_set_ld or mpfr_set_decimal64. Otherwise the floating-point constant will be
148  first converted into a reduced-precision (e.g., 53-bit) binary (or decimal, for
149  mpfr_set_decimal64) number before MPFR can work with it.
150  */
151 
152  QoreStringMaker str("%.17g", f);
153  mpfr_set_str(num, str.getBuffer(), 10, QORE_MPFR_RND);
154  }
155 
156  DLLLOCAL qore_number_private(int64 i) {
157  mpfr_set_sj(num, i, QORE_MPFR_RND);
158  }
159 
160  DLLLOCAL qore_number_private(const char* str) : qore_number_private_intern(QORE_MAX(QORE_DEFAULT_PREC, strlen(str)*5)) {
161  // see if number has an exponent and increase the number's precision if necessary
162  const char* p = strchrs(str, "eE");
163  if (p) {
164  int exp = abs(atoi(p + 1));
165  mpfr_prec_t np = exp * 5;
166  if (np > getPrec())
167  setPrec(np);
168  }
169  if (!str[0])
170  mpfr_set_sj(num, 0, QORE_MPFR_RND);
171  else
172  mpfr_set_str(num, str, 10, QORE_MPFR_RND);
173  }
174 
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);
177  }
178 
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);
181  }
182 
183  DLLLOCAL double getAsFloat() const {
184  return mpfr_get_d(num, QORE_MPFR_RND);
185  }
186 
187  DLLLOCAL int64 getAsBigInt() const {
188  return mpfr_get_sj(num, QORE_MPFR_RNDZ);
189  }
190 
191  DLLLOCAL bool getAsBool() const {
192  return !zero();
193  }
194 
195  DLLLOCAL bool zero() const {
196  return (bool)mpfr_zero_p(num);
197  }
198 
199  DLLLOCAL bool nan() const {
200  return (bool)mpfr_nan_p(num);
201  }
202 
203  DLLLOCAL bool inf() const {
204  return (bool)mpfr_inf_p(num);
205  }
206 
207  DLLLOCAL bool number() const {
208  return (bool)mpfr_number_p(num);
209  }
210 
211 #ifdef HAVE_MPFR_REGULAR
212  // regular and not zero
213  DLLLOCAL bool regular() const {
214  return (bool)mpfr_regular_p(num);
215  }
216 #endif
217 
218  DLLLOCAL int sign() const {
219  return mpfr_sgn(num);
220  }
221 
222  DLLLOCAL void sprintf(QoreString& str, const char* fmt) const {
223 #ifdef HAVE_MPFR_SPRINTF
224  //printd(5, "qore_number_private::sprintf() fmt: '%s'\n", fmt);
225  int len = mpfr_snprintf(0, 0, fmt, num);
226  if (!len)
227  return;
228  if (len < 0) {
229  numError(str);
230  return;
231  }
232  str.allocate(str.size() + len + 1);
233  mpfr_sprintf((char*)(str.getBuffer() + str.size()), fmt, num);
234  str.terminate(str.size() + len);
235 #else
236  // if there is no mpfr_sprintf, then we convert to a long double and output the number
237  long double ld = mpfr_get_ld(num, QORE_MPFR_RND);
238  int len = ::snprintf(0, 0, fmt, ld);
239  if (len <= 0)
240  return;
241  str.allocate(str.size() + len + 1);
242  ::sprintf((char*)(str.getBuffer() + str.size()), fmt, ld);
243  str.terminate(str.size() + len);
244 #endif
245  }
246 
247  DLLLOCAL void getScientificString(QoreString& str, bool round = true) const {
248 #ifdef HAVE_MPFR_SPRINTF
249  sprintf(str, "%Re");
250 #else
251  sprintf(str, "%Le");
252 #endif
253 
254  if (round) {
255  qore_offset_t i = str.find('.');
256  if (i != -1) {
257  qore_offset_t e = str.rfind('e');
258  if (e != -1)
259  applyRoundingHeuristic(str, i, e);
260  }
261  }
262  }
263 
264  DLLLOCAL void getAsString(QoreString& str, bool round = true, int base = 10) const;
265 
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);
270  else
271  getAsString(str, raw);
272  }
273 
274  DLLLOCAL int format(QoreString& str, const QoreString& fmt, ExceptionSink* xsink) {
275  getAsString(str);
276  return formatNumberString(str, fmt, xsink);
277  }
278 
279  DLLLOCAL int format(QoreString& str, int prec, const QoreString& dsep_str, const QoreString& tsep_str, ExceptionSink* xsink) {
280  getAsString(str);
281  return formatNumberString(str, prec, dsep_str, tsep_str, xsink);
282  }
283 
284  DLLLOCAL bool lessThan(const qore_number_private& right) const {
285  return mpfr_less_p(num, right.num);
286  }
287 
288  DLLLOCAL bool lessThan(double right) const {
289  MPFR_TMP_VAR(r, QORE_DEFAULT_PREC);
290  if (mpfr_nan_p(num) || std::isnan(right)) // If any of the "numbers" is NaN.
291  return false;
292  mpfr_set_d(r, right, QORE_MPFR_RND);
293  return mpfr_less_p(num, r);
294  }
295 
296  DLLLOCAL bool lessThan(int64 right) const {
297  MPFR_TMP_VAR(r, QORE_DEFAULT_PREC);
298  if (mpfr_nan_p(num)) // If the number is NaN.
299  return false;
300  mpfr_set_sj(r, right, QORE_MPFR_RND);
301  return mpfr_less_p(num, r);
302  }
303 
304  DLLLOCAL bool lessThanOrEqual(const qore_number_private& right) const {
305  return mpfr_lessequal_p(num, right.num);
306  }
307 
308  DLLLOCAL bool lessThanOrEqual(double right) const {
309  MPFR_TMP_VAR(r, QORE_DEFAULT_PREC);
310  if (mpfr_nan_p(num) || std::isnan(right)) // If any of the "numbers" is NaN.
311  return false;
312  mpfr_set_d(r, right, QORE_MPFR_RND);
313  return mpfr_lessequal_p(num, r);
314  }
315 
316  DLLLOCAL bool lessThanOrEqual(int64 right) const {
317  MPFR_TMP_VAR(r, QORE_DEFAULT_PREC);
318  if (mpfr_nan_p(num)) // If the number is NaN.
319  return false;
320  mpfr_set_sj(r, right, QORE_MPFR_RND);
321  return mpfr_lessequal_p(num, r);
322  }
323 
324  DLLLOCAL bool greaterThan(const qore_number_private& right) const {
325  return mpfr_greater_p(num, right.num);
326  }
327 
328  DLLLOCAL bool greaterThan(double right) const {
329  MPFR_TMP_VAR(r, QORE_DEFAULT_PREC);
330  if (mpfr_nan_p(num) || std::isnan(right)) // If any of the "numbers" is NaN.
331  return false;
332  mpfr_set_d(r, right, QORE_MPFR_RND);
333  return mpfr_greater_p(num, r);
334  }
335 
336  DLLLOCAL bool greaterThan(int64 right) const {
337  MPFR_TMP_VAR(r, QORE_DEFAULT_PREC);
338  if (mpfr_nan_p(num)) // If the number is NaN.
339  return false;
340  mpfr_set_sj(r, right, QORE_MPFR_RND);
341  return mpfr_greater_p(num, r);
342  }
343 
344  DLLLOCAL bool greaterThanOrEqual(const qore_number_private& right) const {
345  return mpfr_greaterequal_p(num, right.num);
346  }
347 
348  DLLLOCAL bool greaterThanOrEqual(double right) const {
349  MPFR_TMP_VAR(r, QORE_DEFAULT_PREC);
350  if (mpfr_nan_p(num) || std::isnan(right)) // If any of the "numbers" is NaN.
351  return false;
352  mpfr_set_d(r, right, QORE_MPFR_RND);
353  return mpfr_greaterequal_p(num, r);
354  }
355 
356  DLLLOCAL bool greaterThanOrEqual(int64 right) const {
357  MPFR_TMP_VAR(r, QORE_DEFAULT_PREC);
358  if (mpfr_nan_p(num)) // If the number is NaN.
359  return false;
360  mpfr_set_sj(r, right, QORE_MPFR_RND);
361  return mpfr_greaterequal_p(num, r);
362  }
363 
364  DLLLOCAL bool equals(const qore_number_private& right) const {
365  return mpfr_equal_p(num, right.num);
366  }
367 
368  DLLLOCAL bool equals(double right) const {
369  if (mpfr_nan_p(num) || std::isnan(right)) // If any of the "numbers" is NaN.
370  return false;
371  return 0 == mpfr_cmp_d(num, right);
372  }
373 
374  DLLLOCAL bool equals(int64 right) const {
375  MPFR_TMP_VAR(r, QORE_DEFAULT_PREC);
376  if (mpfr_nan_p(num)) // If the number is NaN.
377  return false;
378  mpfr_set_sj(r, right, QORE_MPFR_RND);
379  return mpfr_equal_p(num, r);
380  }
381 
382  DLLLOCAL qore_number_private* doBinary(q_mpfr_binary_func_t func, const qore_number_private& r, ExceptionSink* xsink = 0) const {
383  mpfr_prec_t prec;
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);
388  } else {
389  prec = QORE_MAX(mpfr_get_prec(num), mpfr_get_prec(r.num)) + 1;
390  }
391  std::unique_ptr<qore_number_private> p(new qore_number_private(prec));
392  func(p->num, num, r.num, QORE_MPFR_RND);
393  if (xsink)
394  checkFlags(xsink);
395 
396  return (xsink && *xsink) ? 0 : p.release();
397  }
398 
399  DLLLOCAL qore_number_private* doPlus(const qore_number_private& r) const {
400  return doBinary(mpfr_add, r);
401  }
402 
403  DLLLOCAL qore_number_private* doMinus(const qore_number_private& r) const {
404  return doBinary(mpfr_sub, r);
405  }
406 
407  DLLLOCAL qore_number_private* doMultiply(const qore_number_private& r) const {
408  return doBinary(mpfr_mul, r);
409  }
410 
411  DLLLOCAL qore_number_private* doDivideBy(const qore_number_private& r, ExceptionSink* xsink) const {
412 #ifndef HAVE_MPFR_DIVBY0
413  if (r.zero()) {
414  do_divide_by_zero(xsink);
415  return 0;
416  }
417 #endif
418  return doBinary(mpfr_div, r, xsink);
419  }
420 
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);
424  if (xsink)
425  checkFlags(xsink);
426 
427  return p;
428  }
429 
430  DLLLOCAL void negateInPlace() {
431  mpfr_neg(num, num, QORE_MPFR_RND);
432  }
433 
434  DLLLOCAL qore_number_private* negate() const {
435  return doUnary(mpfr_neg);
436  }
437 
438  DLLLOCAL qore_number_private* absolute() const {
439  return doUnary(mpfr_abs);
440  }
441 
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);
444  func(p->num, num);
445  if (xsink)
446  checkFlags(xsink);
447 
448  return p;
449  }
450 
451  // for round functions: round(), ceil(), floor()
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));
454 
455  if (prec == 0) {
456  func(p0 -> num, num);
457 
458  if (xsink)
459  checkFlags(xsink);
460 
461  return p0.release();
462  }
463 
464  qore_number_private* p2;
465 
466  if (prec > 0) {
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);
471  } else {
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);
476  }
477 
478  if (xsink)
479  checkFlags(xsink);
480 
481  return p2;
482  }
483 
484  DLLLOCAL mpfr_prec_t getPrec() const {
485  return mpfr_get_prec(num);
486  }
487 
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);
492  }
493 
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);
498  }
499 
500  DLLLOCAL void doBinaryInplace(q_mpfr_binary_func_t func, const qore_number_private& r, ExceptionSink* xsink = 0) {
501  checkPrec(func, r.num);
502  // some compilers (sun/oracle pro c++ notably) do not support arrays with a variable size
503  // if not, we can't use the stack for the temporary variable and have to use a dynamically-allocated one
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);
507  if (xsink)
508  checkFlags(xsink);
509  }
510 
511  DLLLOCAL void plusEquals(const qore_number_private& r) {
512  doBinaryInplace(mpfr_add, r);
513  }
514 
515  DLLLOCAL void minusEquals(const qore_number_private& r) {
516  doBinaryInplace(mpfr_sub, r);
517  }
518 
519  DLLLOCAL void multiplyEquals(const qore_number_private& r) {
520  doBinaryInplace(mpfr_mul, r);
521  }
522 
523  DLLLOCAL void divideEquals(const qore_number_private& r) {
524  assert(!r.zero());
525  doBinaryInplace(mpfr_div, r);
526  }
527 
528  DLLLOCAL static void negateInPlace(QoreNumberNode& n) {
529  n.priv->negateInPlace();
530  }
531 
532  DLLLOCAL static int doRound(QoreString& num, qore_offset_t& dp, int prec);
533 
534  DLLLOCAL static int formatNumberString(QoreString& num, const QoreString& fmt, ExceptionSink* xsink);
535 
536  DLLLOCAL static int formatNumberString(QoreString& num, int prec, const QoreString& dsep_str, const QoreString& tsep_str, ExceptionSink* xsink);
537 
538 protected:
539  // assumes dsep, tsep and num all have the same encoding
540  DLLLOCAL static int formatNumberStringIntern(QoreString& num, int prec, const QoreString& dsep, const QoreString& tsep, ExceptionSink* xsink);
541 
542 public:
543  DLLLOCAL static void numError(QoreString& str) {
544  str.concat("<number error>");
545  }
546 
547  // try to remove noise from the binary -> decimal conversion process in insignificant digits
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);
550 
551  // try to remove noise from the binary -> decimal conversion process in insignificant digits
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) {
556  qore_offset_t i = str.find('.');
557  if (i != -1) {
558  applyRoundingHeuristic(str, i, str.size(), round_threshold_1, round_threshold_2);
559  }
560  }
561 
562  // returns number of digits inserted
563  DLLLOCAL static int roundUp(QoreString& str, qore_offset_t pos);
564 
565  // static accessor methods
566  DLLLOCAL static void sprintf(const QoreNumberNode& n, QoreString& str, const char* fmt) {
567  n.priv->sprintf(str, fmt);
568  }
569 
570  DLLLOCAL static void inc(QoreNumberNode& n) {
571  n.priv->inc();
572  }
573 
574  DLLLOCAL static void dec(QoreNumberNode& n) {
575  n.priv->dec();
576  }
577 
578  DLLLOCAL static void plusEquals(QoreNumberNode& n, const QoreNumberNode& r) {
579  n.priv->plusEquals(*r.priv);
580  }
581 
582  DLLLOCAL static void minusEquals(QoreNumberNode& n, const QoreNumberNode& r) {
583  n.priv->minusEquals(*r.priv);
584  }
585 
586  DLLLOCAL static void multiplyEquals(QoreNumberNode& n, const QoreNumberNode& r) {
587  n.priv->multiplyEquals(*r.priv);
588  }
589 
590  DLLLOCAL static void divideEquals(QoreNumberNode& n, const QoreNumberNode& r) {
591  n.priv->divideEquals(*r.priv);
592  }
593 
594  DLLLOCAL static QoreNumberNode* doUnary(const QoreNumberNode& n, q_mpfr_unary_func_t func, ExceptionSink* xsink = 0) {
595  qore_number_private* p = n.priv->doUnary(func, xsink);
596  return p ? new QoreNumberNode(p) : 0;
597  }
598 
599  DLLLOCAL static QoreNumberNode* doBinary(const QoreNumberNode& n, q_mpfr_binary_func_t func, const QoreNumberNode& r, ExceptionSink* xsink = 0) {
600  qore_number_private* p = n.priv->doBinary(func, *r.priv, xsink);
601  return p ? new QoreNumberNode(p) : 0;
602  }
603 
604  DLLLOCAL static QoreNumberNode* doUnaryNR(const QoreNumberNode& n, q_mpfr_unary_nr_func_t func, ExceptionSink* xsink = 0) {
605  qore_number_private* p = n.priv->doUnaryNR(func, xsink);
606  return p ? new QoreNumberNode(p) : 0;
607  }
608 
609  DLLLOCAL static QoreNumberNode* doRoundNR(const QoreNumberNode& n, q_mpfr_unary_nr_func_t func, int prec = 0, ExceptionSink* xsink = 0) {
610  qore_number_private* p = n.priv->doRoundNR(func, prec, xsink);
611  return p ? new QoreNumberNode(p) : 0;
612  }
613 
614  DLLLOCAL static QoreNumberNode* getNaNumber() {
615  return new QoreNumberNode(new qore_number_private("@NaN@"));
616  }
617 
618  DLLLOCAL static QoreNumberNode* getInfinity() {
619  return new QoreNumberNode(new qore_number_private("@Inf@"));
620  }
621 
622  DLLLOCAL static QoreNumberNode* getPi() {
623  qore_number_private* p = new qore_number_private(0ll);
624  mpfr_const_pi(p->num, QORE_MPFR_RND);
625  return new QoreNumberNode(p);
626  }
627 
628  DLLLOCAL static qore_number_private* get(const QoreNumberNode& n) {
629  return n.priv;
630  }
631 
632  DLLLOCAL static QoreStringNode* toBase(double f, int base, ExceptionSink* xsink) {
633  std::unique_ptr<qore_number_private> n(new qore_number_private(f));
634  return qore_number_private::toBase(n.get(), base, xsink);
635  }
636 
637  DLLLOCAL static QoreStringNode* toBase(const QoreNumberNode& n, int base, ExceptionSink* xsink) {
638  return qore_number_private::toBase(n.priv, base, xsink);
639  }
640 
641  DLLLOCAL static QoreStringNode* toBase(qore_number_private* n, int base, ExceptionSink* xsink) {
642  if (base < 2 || base > 36) {
643  xsink -> raiseException("INVALID-BASE", "base %d is invalid; base must be 2 - 36 inclusive", base);
644  return 0;
645  }
646 
647  QoreString qs;
648  n -> getAsString(qs, 1, base);
649  qs.toupr();
650  return new QoreStringNode(qs);
651  }
652 };
653 
654 #endif
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