Qore Programming Language 1.19.1
Loading...
Searching...
No Matches
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 - 2023 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>
38using 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
61typedef 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
81typedef int (*q_mpfr_binary_func_t)(mpfr_t, const mpfr_t, const mpfr_t, mpfr_rnd_t);
82// for unary operations on MPFR data
83typedef 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
85typedef int (*q_mpfr_unary_nr_func_t)(mpfr_t, const mpfr_t);
86
87hashdecl 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
139hashdecl 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
538protected:
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
542public:
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:250
#define QORE_MAX(a, b)
macro to return the maximum of 2 numbers
Definition: QoreLib.h:613
#define QORE_MIN(a, b)
macro to return the minimum of 2 numbers
Definition: QoreLib.h:616
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:50
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 const char * getBuffer() const
returns the string's buffer; this data should not be changed
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
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
#define QORE_NF_DEFAULT
Definition: QoreNumberNode.h:43
#define QORE_NF_RAW
number format bitfield: raw (unrounded)
Definition: QoreNumberNode.h:47
#define QORE_NF_SCIENTIFIC
number format bitfield: scientific
Definition: QoreNumberNode.h:45