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