1 /********************************************************************/
2 /* */
3 /* numutl.c Numeric utility functions. */
4 /* Copyright (C) 1989 - 2020 Thomas Mertes */
5 /* */
6 /* This file is part of the Seed7 Runtime Library. */
7 /* */
8 /* The Seed7 Runtime Library is free software; you can */
9 /* redistribute it and/or modify it under the terms of the GNU */
10 /* Lesser General Public License as published by the Free Software */
11 /* Foundation; either version 2.1 of the License, or (at your */
12 /* option) any later version. */
13 /* */
14 /* The Seed7 Runtime Library is distributed in the hope that it */
15 /* will be useful, but WITHOUT ANY WARRANTY; without even the */
16 /* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR */
17 /* PURPOSE. See the GNU Lesser General Public License for more */
18 /* details. */
19 /* */
20 /* You should have received a copy of the GNU Lesser General */
21 /* Public License along with this program; if not, write to the */
22 /* Free Software Foundation, Inc., 51 Franklin Street, */
23 /* Fifth Floor, Boston, MA 02110-1301, USA. */
24 /* */
25 /* Module: Seed7 Runtime Library */
26 /* File: seed7/src/numutl.c */
27 /* Changes: 2014 - 2016, 2019 - 2020 Thomas Mertes */
28 /* Content: Numeric utility functions. */
29 /* */
30 /********************************************************************/
31
32 #define LOG_FUNCTIONS 0
33 #define VERBOSE_EXCEPTIONS 0
34
35 #include "version.h"
36
37 #include "stdlib.h"
38 #include "stdio.h"
39 #include "string.h"
40 #include "float.h"
41 #include "math.h"
42
43 #include "common.h"
44 #include "data_rtl.h"
45 #include "heaputl.h"
46 #include "striutl.h"
47 #include "flt_rtl.h"
48 #include "str_rtl.h"
49 #include "rtl_err.h"
50 #include "big_drv.h"
51
52 #undef EXTERN
53 #define EXTERN
54 #define DO_INIT
55 #include "numutl.h"
56
57 #define MAX_DECIMAL_BUFFER_LENGTH 128
58 #define AND_SO_ON_LIMIT 128
59
60 /* DECIMAL_WITH_LIMIT provides parameters for the format string \"%.*s%s\" */
61 #define DECIMAL_WITH_LIMIT(decimal, length) \
62 (int) (length <= AND_SO_ON_LIMIT ? length : AND_SO_ON_LIMIT), \
63 decimal, length > AND_SO_ON_LIMIT ? "\\ *AND_SO_ON* " : ""
64
65
66
67 /**
68 * Convert a bigInteger number to a double.
69 * @return the bigInteger as double
70 */
bigIntToDouble(const const_bigIntType number)71 double bigIntToDouble (const const_bigIntType number)
72
73 {
74 bigIntType absNumber;
75 bigIntType mantissa;
76 int64Type intMantissa;
77 int sign;
78 int exponent;
79 double doubleValue = 0.0;
80
81 /* bigIntToDouble */
82 logFunction(printf("bigIntToDouble(%s)\n",
83 striAsUnquotedCStri(bigStr(number))););
84 sign = (int) bigCmpSignedDigit(number, 0);
85 if (sign != 0) {
86 absNumber = bigAbs(number);
87 if (absNumber != NULL) {
88 exponent = (int) bigBitLength(absNumber) - 1;
89 if (DOUBLE_MANTISSA_SHIFT + 1 >= exponent) {
90 bigLShiftAssign(&absNumber, DOUBLE_MANTISSA_SHIFT - exponent + 1);
91 } else {
92 bigRShiftAssign(&absNumber, exponent - DOUBLE_MANTISSA_SHIFT - 1);
93 } /* if */
94 bigIncr(&absNumber);
95 if (absNumber != NULL) {
96 mantissa = bigRShift(absNumber, 1);
97 if (mantissa != NULL) {
98 intMantissa = bigToInt64(mantissa, NULL);
99 bigDestr(mantissa);
100 if (sign < 0) {
101 intMantissa = -intMantissa;
102 } /* if */
103 doubleValue = setMantissaAndExponent(intMantissa, exponent - DOUBLE_MANTISSA_SHIFT);
104 } /* if */
105 } /* if */
106 } /* if */
107 bigDestr(absNumber);
108 } /* if */
109 logFunction(printf("bigIntToDouble --> " FMT_E "\n", doubleValue););
110 return doubleValue;
111 } /* bigIntToDouble */
112
113
114
binaryExponent(const const_bigIntType absNumerator,const const_bigIntType denominator)115 static int binaryExponent (const const_bigIntType absNumerator,
116 const const_bigIntType denominator)
117
118 {
119 bigIntType quotient;
120 int exponent = 0;
121
122 /* binaryExponent */
123 if (bigCmp(absNumerator, denominator) >= 0) {
124 quotient = bigDiv(absNumerator, denominator);
125 if (quotient != NULL) {
126 exponent = (int) bigBitLength(quotient) - 1;
127 bigDestr(quotient);
128 } /* if */
129 } else {
130 quotient = bigDiv(denominator, absNumerator);
131 if (quotient != NULL) {
132 exponent = (int) -bigBitLength(quotient);
133 bigDestr(quotient);
134 } /* if */
135 } /* if */
136 return exponent;
137 } /* binaryExponent */
138
139
140
141 /**
142 * Convert a bigRational number to a double.
143 * @return the bigRational as double
144 */
bigRatToDouble(const const_bigIntType numerator,const const_bigIntType denominator)145 double bigRatToDouble (const const_bigIntType numerator,
146 const const_bigIntType denominator)
147
148 {
149 bigIntType absNumerator;
150 bigIntType shiftedDenominator;
151 bigIntType mantissa;
152 int64Type intMantissa;
153 int exponent;
154 double doubleValue = 0.0;
155
156 /* bigRatToDouble */
157 logFunction(printf("bigRatToDouble(%s, ",
158 striAsUnquotedCStri(bigStr(numerator)));
159 printf("%s)\n",
160 striAsUnquotedCStri(bigStr(denominator))););
161 if (bigEqSignedDigit(denominator, 0)) {
162 if (bigCmpSignedDigit(numerator, 0) > 0) {
163 doubleValue = POSITIVE_INFINITY;
164 } else if (bigEqSignedDigit(numerator, 0)) {
165 doubleValue = NOT_A_NUMBER;
166 } else {
167 doubleValue = NEGATIVE_INFINITY;
168 } /* if */
169 } else if (!bigEqSignedDigit(numerator, 0)) {
170 absNumerator = bigAbs(numerator);
171 shiftedDenominator = bigLShift(denominator, 1);
172 if (absNumerator != NULL && shiftedDenominator != NULL) {
173 exponent = binaryExponent(absNumerator, denominator);
174 if (DOUBLE_MANTISSA_SHIFT + 1 >= exponent) {
175 bigLShiftAssign(&absNumerator, DOUBLE_MANTISSA_SHIFT - exponent + 1);
176 } else {
177 bigRShiftAssign(&absNumerator, exponent - DOUBLE_MANTISSA_SHIFT - 1);
178 } /* if */
179 bigAddAssign(&absNumerator, denominator);
180 if (absNumerator != NULL) {
181 mantissa = bigDiv(absNumerator, shiftedDenominator);
182 if (mantissa != NULL) {
183 intMantissa = bigToInt64(mantissa, NULL);
184 bigDestr(mantissa);
185 if (bigCmpSignedDigit(numerator, 0) < 0) {
186 intMantissa = -intMantissa;
187 } /* if */
188 doubleValue = setMantissaAndExponent(intMantissa, exponent - DOUBLE_MANTISSA_SHIFT);
189 } /* if */
190 } /* if */
191 } /* if */
192 bigDestr(absNumerator);
193 bigDestr(shiftedDenominator);
194 } /* if */
195 logFunction(printf("bigRatToDouble --> " FMT_E "\n", doubleValue););
196 return doubleValue;
197 } /* bigRatToDouble */
198
199
200
201 /**
202 * Convert a double to a bigRational number with numerator and denomonator.
203 * @param denominator The address of a variable that receives the denominator.
204 * @return the nominator of the converted double.
205 */
doubleToBigRat(const double doubleValue,bigIntType * denominator)206 bigIntType doubleToBigRat (const double doubleValue, bigIntType *denominator)
207
208 {
209 int64Type intMantissa;
210 int exponent;
211 bigIntType numerator;
212
213 /* doubleToBigRat */
214 logFunction(printf("doubleToBigRat(" FMT_E ", *)\n",
215 doubleValue););
216 if (os_isnan(doubleValue)) {
217 numerator = bigFromInt32(0);
218 *denominator = bigFromInt32(0);
219 } else if (os_isinf(doubleValue)) {
220 if (doubleValue < 0.0) {
221 numerator = bigFromInt32(-1);
222 } else {
223 numerator = bigFromInt32(1);
224 } /* if */
225 *denominator = bigFromInt32(0);
226 } else {
227 intMantissa = getMantissaAndExponent(doubleValue, &exponent);
228 /* printf("intMantissa: " FMT_D64 "\n", intMantissa);
229 printf("exponent: %d\n", exponent); */
230 numerator = bigFromInt64(intMantissa);
231 if (exponent > 0) {
232 bigLShiftAssign(&numerator, exponent);
233 *denominator = bigFromInt32(1);
234 } else {
235 *denominator = bigLShiftOne(-exponent);
236 } /* if */
237 } /* if */
238 logFunction(printf("doubleToBigRat --> %s",
239 striAsUnquotedCStri(bigStr(numerator)));
240 printf(" (denominator = %s)\n",
241 striAsUnquotedCStri(bigStr(*denominator))););
242 return numerator;
243 } /* doubleToBigRat */
244
245
246
doubleToStri(const double doubleValue,boolType roundDouble)247 striType doubleToStri (const double doubleValue, boolType roundDouble)
248
249 {
250 char buffer[DOUBLE_TO_CHAR_BUFFER_SIZE];
251 memSizeType len;
252 striType result;
253
254 /* doubleToStri */
255 logFunction(printf("doubleToStri(" FMT_E ", %d)\n",
256 doubleValue, roundDouble););
257 if (roundDouble) {
258 len = doubleToCharBuffer(doubleValue, DOUBLE_STR_LARGE_NUMBER,
259 FMT_E_DBL, buffer);
260 } else {
261 len = doubleToCharBuffer(doubleValue, FLOAT_STR_LARGE_NUMBER,
262 FMT_E_FLT, buffer);
263 } /* if */
264 result = cstri_buf_to_stri(buffer, len);
265 if (unlikely(result == NULL)) {
266 raise_error(MEMORY_ERROR);
267 } /* if */
268 logFunction(printf("doubleToStri --> \"%s\"\n",
269 striAsUnquotedCStri(result)););
270 return result;
271 } /* doubleToStri */
272
273
274
roundDoubleToBigRat(const double doubleValue,boolType roundDouble,bigIntType * denominator)275 bigIntType roundDoubleToBigRat (const double doubleValue, boolType roundDouble,
276 bigIntType *denominator)
277
278 {
279 striType stri;
280 memSizeType decimalPointPos;
281 memSizeType scale;
282 memSizeType savedSize;
283 bigIntType numerator;
284
285 /* roundDoubleToBigRat */
286 logFunction(printf("roundDoubleToBigRat(" FMT_E ", %d, *)\n",
287 doubleValue, roundDouble););
288 if (os_isnan(doubleValue)) {
289 numerator = bigFromInt32(0);
290 *denominator = bigFromInt32(0);
291 } else if (os_isinf(doubleValue)) {
292 if (doubleValue < 0.0) {
293 numerator = bigFromInt32(-1);
294 } else {
295 numerator = bigFromInt32(1);
296 } /* if */
297 *denominator = bigFromInt32(0);
298 } else {
299 stri = doubleToStri(doubleValue, roundDouble);
300 if (stri == NULL) {
301 numerator = NULL;
302 } else {
303 decimalPointPos = (memSizeType) strChPos(stri, '.');
304 scale = stri->size - decimalPointPos;
305 memmove(&stri->mem[decimalPointPos - 1],
306 &stri->mem[decimalPointPos],
307 scale * sizeof(strElemType));
308 savedSize = stri->size;
309 stri->size--;
310 while (scale >= 1 && stri->mem[stri->size - 1] == '0') {
311 scale--;
312 stri->size--;
313 } /* while */
314 numerator = bigParse(stri);
315 if (numerator != NULL) {
316 if (scale == 0) {
317 *denominator = bigFromInt32(1);
318 } else {
319 *denominator = bigIPowSignedDigit(10, (intType) scale);
320 } /* if */
321 } /* if */
322 FREE_STRI(stri, savedSize);
323 } /* if */
324 } /* if */
325 logFunction(printf("roundDoubleToBigRat --> %s",
326 striAsUnquotedCStri(bigStr(numerator)));
327 printf(" (denominator = %s)\n",
328 striAsUnquotedCStri(bigStr(*denominator))););
329 return numerator;
330 } /* roundDoubleToBigRat */
331
332
333
getDecimalInt(const const_ustriType decimal,memSizeType length)334 intType getDecimalInt (const const_ustriType decimal, memSizeType length)
335
336 {
337 boolType okay;
338 boolType negative;
339 memSizeType position = 0;
340 uintType digitval;
341 uintType uintValue;
342 intType intResult;
343
344 /* getDecimalInt */
345 logFunction(printf("getDecimalInt(\"%.*s%s\", " FMT_U_MEM ")\n",
346 DECIMAL_WITH_LIMIT(decimal, length), length););
347 if (likely(length != 0)) {
348 if (decimal[0] == '-') {
349 negative = TRUE;
350 position++;
351 } else {
352 if (decimal[0] == '+') {
353 position++;
354 } /* if */
355 negative = FALSE;
356 } /* if */
357 } /* if */
358 if (unlikely(position >= length)) {
359 logError(printf("getDecimalInt: Digit missing.\n"););
360 raise_error(RANGE_ERROR);
361 intResult = 0;
362 } else {
363 uintValue = 0;
364 okay = TRUE;
365 #if TWOS_COMPLEMENT_INTTYPE
366 while (position < length &&
367 (digitval = ((uintType) decimal[position]) - ((uintType) '0')) <= 9) {
368 #else
369 while (position < length &&
370 decimal[position] >= '0' &&
371 decimal[position] <= '9' && okay) {
372 digitval = ((uintType) decimal[position]) - ((uintType) '0');
373 #endif
374 if (unlikely(uintValue > MAX_DIV_10)) {
375 okay = FALSE;
376 } else {
377 uintValue = ((uintType) 10) * uintValue + digitval;
378 } /* if */
379 position++;
380 } /* while */
381 if (unlikely(position < length)) {
382 logError(printf("getDecimalInt: Illegal digit.\n"););
383 raise_error(RANGE_ERROR);
384 intResult = 0;
385 } else if (unlikely(!okay)) {
386 logError(printf("getDecimalInt: Absolute value of literal is too big.\n"););
387 raise_error(RANGE_ERROR);
388 intResult = 0;
389 } else {
390 if (negative) {
391 if (unlikely(uintValue > (uintType) INTTYPE_MAX + 1)) {
392 logError(printf("getDecimalInt: Literal too small.\n"););
393 raise_error(RANGE_ERROR);
394 intResult = 0;
395 } else {
396 /* The unsigned value is negated to avoid an overflow */
397 /* if the most negative intType value is negated. */
398 intResult = (intType) -uintValue;
399 } /* if */
400 } else if (unlikely(uintValue > (uintType) INTTYPE_MAX)) {
401 logError(printf("getDecimalInt: Literal too big.\n"););
402 raise_error(RANGE_ERROR);
403 intResult = 0;
404 } else {
405 intResult = (intType) uintValue;
406 } /* if */
407 } /* if */
408 } /* if */
409 logFunction(printf("getDecimalInt --> " FMT_D "\n",
410 intResult););
411 return intResult;
412 } /* getDecimalInt */
413
414
415
416 bigIntType getDecimalBigInt (const const_ustriType decimal, memSizeType length)
417
418 {
419 striType stri;
420 bigIntType bigIntValue;
421
422 /* getDecimalBigInt */
423 logFunction(printf("getDecimalBigInt(\"%.*s%s\", " FMT_U_MEM ")\n",
424 DECIMAL_WITH_LIMIT(decimal, length), length););
425 stri = cstri_buf_to_stri((const_cstriType) decimal, length);
426 /* printf("getDecimalBigInt: stri: ");
427 prot_stri(stri);
428 printf("\n"); */
429 if (unlikely(stri == NULL)) {
430 raise_error(MEMORY_ERROR);
431 bigIntValue = NULL;
432 } else {
433 bigIntValue = bigParse(stri);
434 strDestr(stri);
435 } /* if */
436 logFunction(printf("getDecimalBigInt --> %s\n",
437 bigIntValue == NULL ? "NULL" :
438 striAsUnquotedCStri(bigStr(bigIntValue))););
439 return bigIntValue;
440 } /* getDecimalBigInt */
441
442
443
444 bigIntType getDecimalBigRational (const const_ustriType decimal, memSizeType length,
445 bigIntType *denominator)
446
447 {
448 striType stri;
449 boolType okay = TRUE;
450 boolType hasDecimalPoint = FALSE;
451 memSizeType decimalPointPos = 0;
452 memSizeType srcIndex;
453 memSizeType destIndex = 0;
454 memSizeType scale;
455 bigIntType numerator;
456
457 /* getDecimalBigRational */
458 logFunction(printf("getDecimalBigRational(\"%.*s%s\", " FMT_U_MEM ")\n",
459 DECIMAL_WITH_LIMIT(decimal, length), length););
460 if (unlikely(!ALLOC_STRI_CHECK_SIZE(stri, length))) {
461 *denominator = NULL;
462 raise_error(MEMORY_ERROR);
463 numerator = NULL;
464 } else {
465 for (srcIndex = 0; srcIndex < length && okay; srcIndex++) {
466 if ((decimal[srcIndex] >= '0' && decimal[srcIndex] <= '9') ||
467 (decimal[srcIndex] == '-' && srcIndex == 0)) {
468 stri->mem[destIndex] = decimal[srcIndex];
469 destIndex++;
470 } else if (decimal[srcIndex] == '.' || decimal[srcIndex] == ',') {
471 /* Accept decimal point and decimal comma. */
472 if (hasDecimalPoint) {
473 okay = FALSE;
474 } else {
475 decimalPointPos = destIndex;
476 hasDecimalPoint = TRUE;
477 } /* if */
478 } else {
479 okay = FALSE;
480 } /* if */
481 } /* for */
482 stri->size = (memSizeType) destIndex;
483 /* prot_stri(stri);
484 printf("\n"); */
485 if (unlikely(!okay)) {
486 logError(printf("getDecimalBigRational: Decimal literal illegal.\n"););
487 FREE_STRI(stri, length);
488 *denominator = NULL;
489 raise_error(RANGE_ERROR);
490 numerator = NULL;
491 } else {
492 /* printf("decimalPointPos: " FMT_U_MEM "\n", decimalPointPos); */
493 if (hasDecimalPoint) {
494 scale = stri->size - decimalPointPos;
495 } else {
496 scale = 0;
497 } /* if */
498 /* printf("scale: " FMT_U_MEM "\n", scale); */
499 numerator = bigParse(stri);
500 FREE_STRI(stri, length);
501 if (numerator != NULL) {
502 if (unlikely(scale > INTTYPE_MAX)) {
503 *denominator = NULL;
504 bigDestr(numerator);
505 logError(printf("getDecimalBigRational: scale > INTTYPE_MAX\n"
506 "scale = " FMT_U_MEM ", INTTYPE_MAX = " FMT_D "\n",
507 scale, INTTYPE_MAX););
508 raise_error(RANGE_ERROR);
509 numerator = NULL;
510 } else {
511 *denominator = bigIPowSignedDigit(10, (intType) scale);
512 } /* if */
513 } /* if */
514 } /* if */
515 } /* if */
516 logFunction(printf("getDecimalBigRational --> %s",
517 striAsUnquotedCStri(bigStr(numerator)));
518 printf(" (denominator = %s)\n",
519 striAsUnquotedCStri(bigStr(*denominator))););
520 return numerator;
521 } /* getDecimalBigRational */
522
523
524
525 floatType getDecimalFloat (const const_ustriType decimal, memSizeType length)
526
527 {
528 char localCharBuffer[MAX_DECIMAL_BUFFER_LENGTH + NULL_TERMINATION_LEN];
529 char *charBuffer;
530 char *commaPos;
531 floatType floatValue;
532
533 /* getDecimalFloat */
534 logFunction(printf("getDecimalFloat(\"%.*s%s\", " FMT_U_MEM ")\n",
535 DECIMAL_WITH_LIMIT(decimal, length), length););
536 if (length > MAX_DECIMAL_BUFFER_LENGTH) {
537 charBuffer = (char *) malloc(length + NULL_TERMINATION_LEN);
538 } else {
539 charBuffer = localCharBuffer;
540 } /* if */
541 if (unlikely(charBuffer == NULL)) {
542 raise_error(MEMORY_ERROR);
543 floatValue = 0.0;
544 } else {
545 memcpy(charBuffer, decimal, length);
546 charBuffer[length] = '\0';
547 commaPos = strchr(charBuffer, ',');
548 if (commaPos != NULL) {
549 /* Accept decimal point and decimal comma. */
550 *commaPos = '.';
551 } /* if */
552 floatValue = (floatType) strtod(charBuffer, NULL);
553 if (charBuffer != localCharBuffer) {
554 free(charBuffer);
555 } /* if */
556 } /* if */
557 logFunction(printf("getDecimalFloat --> " FMT_E "\n",
558 floatValue););
559 return floatValue;
560 } /* getDecimalFloat */
561
562
563
564 ustriType bigIntToDecimal (const const_bigIntType bigIntValue,
565 memSizeType *length, errInfoType *err_info)
566
567 {
568 striType stri;
569 memSizeType idx;
570 ustriType decimal;
571
572 /* bigIntToDecimal */
573 logFunction(printf("bigIntToDecimal(%s, *, *)\n",
574 striAsUnquotedCStri(bigStr(bigIntValue))););
575 stri = bigStr(bigIntValue);
576 if (stri == NULL) {
577 *err_info = MEMORY_ERROR;
578 decimal = NULL;
579 } else if (unlikely(!ALLOC_USTRI(decimal, stri->size))) {
580 FREE_STRI(stri, stri->size);
581 *err_info = MEMORY_ERROR;
582 } else {
583 for (idx = 0; idx < stri->size; idx++) {
584 decimal[idx] = (ucharType) stri->mem[idx];
585 } /* for */
586 decimal[idx] = '\0';
587 /* printf("decimal: %s\n", decimal); */
588 *length = stri->size;
589 FREE_STRI(stri, stri->size);
590 } /* if */
591 logFunction(printf("bigIntToDecimal --> %s (length=" FMT_U_MEM ", err_info=%d)\n",
592 decimal == NULL ? "NULL" : (char *) decimal,
593 *length, *err_info););
594 return decimal;
595 } /* bigIntToDecimal */
596
597
598
599 ustriType bigRatToDecimal (const const_bigIntType numerator,
600 const const_bigIntType denominator, memSizeType scale,
601 memSizeType *length, errInfoType *err_info)
602
603 {
604 bigIntType number;
605 bigIntType mantissaValue;
606 striType stri;
607 memSizeType striSizeUsed;
608 memSizeType srcIndex;
609 memSizeType destIndex;
610 memSizeType decimalSize;
611 ustriType decimal;
612
613 /* bigRatToDecimal */
614 logFunction(printf("bigRatToDecimal(%s, ",
615 striAsUnquotedCStri(bigStr(numerator)));
616 printf("%s, " FMT_U_MEM ", *, *)\n",
617 striAsUnquotedCStri(bigStr(denominator)),
618 scale););
619 if (bigEqSignedDigit(denominator, 0)) {
620 /* Decimal values do not support Infinity and NaN. */
621 /* printf("Decimal values do not support Infinity and NaN.\n"); */
622 *err_info = RANGE_ERROR;
623 decimal = NULL;
624 } else if (scale > INTTYPE_MAX) {
625 *err_info = RANGE_ERROR;
626 decimal = NULL;
627 } else {
628 number = bigIPowSignedDigit(10, (intType) scale);
629 if (unlikely(number == NULL)) {
630 mantissaValue = NULL;
631 } else {
632 bigMultAssign(&number, numerator);
633 mantissaValue = bigDiv(number, denominator);
634 bigDestr(number);
635 } /* if */
636 if (unlikely(mantissaValue == NULL)) {
637 decimal = NULL;
638 } else {
639 if (bigEqSignedDigit(mantissaValue, 0)) {
640 if (unlikely(!ALLOC_USTRI(decimal, 3))) {
641 *err_info = MEMORY_ERROR;
642 } else {
643 strcpy((char *) decimal, "0.0");
644 *length = 3;
645 } /* if */
646 } else {
647 stri = bigStr(mantissaValue);
648 if (stri == NULL) {
649 *err_info = MEMORY_ERROR;
650 decimal = NULL;
651 } else {
652 /* prot_stri(stri);
653 printf("\n"); */
654 striSizeUsed = stri->size;
655 while (scale >= 2 && stri->mem[striSizeUsed - 1] == '0') {
656 scale--;
657 striSizeUsed--;
658 } /* while */
659 decimalSize = striSizeUsed;
660 if (decimalSize - (stri->mem[0] == '-') > scale) {
661 /* Add one character for the decimal point. */
662 decimalSize += 1;
663 } else {
664 /* Add space for sign, zero and decimal point. */
665 decimalSize = (stri->mem[0] == '-') + scale + 2;
666 } /* if */
667 if (unlikely(!ALLOC_USTRI(decimal, decimalSize))) {
668 *err_info = MEMORY_ERROR;
669 } else {
670 srcIndex = 0;
671 destIndex = 0;
672 if (stri->mem[0] == '-') {
673 decimal[0] = '-';
674 srcIndex++;
675 destIndex++;
676 } /* if */
677 if (striSizeUsed - srcIndex > scale) {
678 for (; srcIndex < striSizeUsed - scale; srcIndex++) {
679 decimal[destIndex] = (unsigned char) stri->mem[srcIndex];
680 destIndex++;
681 } /* for */
682 decimal[destIndex] = '.';
683 destIndex++;
684 } else {
685 decimal[destIndex] = '0';
686 destIndex++;
687 decimal[destIndex] = '.';
688 destIndex++;
689 memset(&decimal[destIndex], '0', scale - striSizeUsed + srcIndex);
690 destIndex += scale - striSizeUsed + srcIndex;
691 } /* if */
692 for (; srcIndex < striSizeUsed; srcIndex++) {
693 decimal[destIndex] = (unsigned char) stri->mem[srcIndex];
694 destIndex++;
695 } /* for */
696 decimal[destIndex] = '\0';
697 *length = destIndex;
698 } /* if */
699 FREE_STRI(stri, stri->size);
700 } /* if */
701 } /* if */
702 bigDestr(mantissaValue);
703 } /* if */
704 } /* if */
705 logFunction(printf("bigRatToDecimal --> %s (length=" FMT_U_MEM ", err_info=%d)\n",
706 decimal == NULL ? "NULL" : (char *) decimal,
707 *length, *err_info););
708 return decimal;
709 } /* bigRatToDecimal */
710