* Bug 15886 fixed: display of polynomials repaired
[scilab.git] / scilab / modules / ast / src / cpp / types / tostring_common.cpp
1 /*
2 *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 *  Copyright (C) 2009 - DIGITEO - Antoine ELIAS
4 *  Copyright (C) 2018 - St├ęphane MOTTELET
5 *
6  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14 *
15 */
16
17 #include <cmath>
18 #include <algorithm>
19 #include <iostream>
20 #include <iomanip>
21 #include "tostring_common.hxx"
22 #include "configvariable.hxx"
23
24 extern "C"
25 {
26 #include "sci_malloc.h"
27 #include "elem_common.h"
28 #include "os_string.h"
29 #include "dtoa.h"
30 #include "charEncoding.h"
31 }
32
33 #define BLANK_SIZE 1
34 #define POINT_SIZE 1
35 #define EXPOSANT_SIZE 2         //exposant symbol + exposant sign
36
37 //template <typename T>
38 //void GetIntFormat(T _TVal, int *_piWidth)
39 //{
40 // *_piWidth = (int)(log10((double)_abs64(_TVal)) + 1);
41 //}
42
43 //template <typename T>
44 //void AddIntValue(ostringstream *_postr, T _TVal, int _iWidth, bool bPrintPlusSign, bool bPrintOne)
45 //{
46 // if(bPrintPlusSign == true)
47 // {
48 //  *_postr << (_TVal < 0 ? MINUS_STRING_INT : PLUS_STRING);
49 // }
50 // else
51 // {
52 //  *_postr << (_TVal < 0 ? MINUS_STRING_INT : NO_SIGN);
53 // }
54 //
55 // configureStream(_postr, _iWidth, 0, ' ');
56 //
57 // if(bPrintOne == true || _TVal != 1)
58 // {
59 //  *_postr << right << _abs64(_TVal);
60 // }
61 //}
62
63 void addSign(std::wostringstream * _postr, double _dblVal, bool _bPrintPlusSign, bool _bPaddSign)
64 {
65     if (_bPrintPlusSign == true)
66     {
67         *_postr << (_dblVal < 0 ? MINUS_STRING : PLUS_STRING);
68     }
69     else
70     {
71         if (_bPaddSign)
72         {
73             *_postr << (_dblVal < 0 ? MINUS_STRING : NO_SIGN);
74         }
75         else
76         {
77             *_postr << (_dblVal < 0 ? MINUS_STRING : L"");
78         }
79     }
80 }
81
82 //void getDoubleFormat(double _dblVal, int *_piWidth, int *_piPrec, /*in/out*/bool* _pExp)
83 void getDoubleFormat(double _dblVal, DoubleFormat * _pDF)
84 {
85     double dblDec = 0;
86     double dblEnt = 0;
87     double dblAbs = std::fabs(_dblVal);
88     int iNbDigit = 0;
89     int iNbDec = 0;
90     int iBlankSize = _pDF->bPrintBlank ? BLANK_SIZE : 0;
91     _pDF->iSignLen = _pDF->bPrintBlank ? SIGN_LENGTH + BLANK_SIZE : _pDF->iSignLen;
92
93     _pDF->bExp |= ConfigVariable::getFormatMode() == 0;
94     int iTotalLen = 0;
95     int iPrecNeeded = ConfigVariable::getFormatSize();
96
97     if (ISNAN(_dblVal) || !finite(_dblVal))
98     {
99         _pDF->iWidth = 4;      //" nan" or " inf"
100         _pDF->iPrec = 0;
101         return;
102     }
103     //get integer part and fractionnal part
104     dblDec = std::modf(dblAbs, &dblEnt);
105
106     //compute len of entire part
107     if (dblEnt == 0)
108     {
109         //[-1, 1]
110         iNbDigit = (int)std::fabs(std::floor(std::log10(dblAbs)));
111
112         if (iNbDigit >= (iPrecNeeded - 2) || _pDF->bExp)
113         {
114             //exponant
115             _pDF->bExp = true;
116             iTotalLen = iBlankSize + 1 /*integer before dot */  + POINT_SIZE + EXPOSANT_SIZE + std::max(((int)log10((double)iNbDigit)) + 1, 2);
117             _pDF->iWidth = iPrecNeeded;
118             _pDF->iPrec = iPrecNeeded - iTotalLen;
119             return;
120         }
121         else
122         {
123             iTotalLen = iBlankSize + 1 /*integer before dot */  + POINT_SIZE;
124         }
125     }
126     else
127     {
128         double dblTemp = log10(dblEnt);
129
130         if (dblTemp > (iPrecNeeded - 2) || _pDF->bExp)
131         {
132             //exponant mode
133             if (dblTemp == 0)
134             {
135                 dblTemp = 1;    //no incidence on value, just to allow log10(dblTemp)
136             }
137
138             _pDF->bExp = true;
139             iTotalLen = iBlankSize + 1 /*integer before dot */  + POINT_SIZE + EXPOSANT_SIZE + std::max(((int)log10(dblTemp)) + 1, 2);
140             _pDF->iWidth = iPrecNeeded;
141             _pDF->iPrec = iPrecNeeded - iTotalLen;
142             return;
143         }
144         else
145         {
146             //number of digit in integer part
147             iTotalLen = iBlankSize + ((int)dblTemp + 1) + POINT_SIZE;
148         }
149     }
150
151     //prepare fractionnal part to precision asked
152     double dblScale = pow(10., iPrecNeeded - iTotalLen);
153     while (iTotalLen <= iPrecNeeded)
154     {
155         dblDec = dblDec * dblScale;
156         dblDec = floor(dblDec + 0.5);
157         dblDec = dblDec / dblScale;
158
159         // when dblAbs = 1.9999999..., modf function
160         // return a decimal part equal to 1.0
161         if (dblDec == 0. || dblDec == 1.)
162         {
163             break;
164         }
165
166         dblDec = dblDec * 10;
167         int iFloor = (int)floor(dblDec);
168
169         dblDec -= iFloor;
170         iTotalLen++;
171         iNbDec++;
172         dblScale /= 10;
173     }
174
175     _pDF->iWidth = iTotalLen;
176     _pDF->iPrec = iNbDec;
177 }
178
179 //void getComplexFormat(double _dblR, double _dblI, int *_piTotalWidth, int *_piWidthR, int *_piWidthI, int *_piPrecR, int *_piPrecI, bool* _pExpR, bool* _pExpI)
180 void getComplexFormat(double _dblR, double _dblI, int *_piTotalWidth, DoubleFormat * _pDFR, DoubleFormat * _pDFI)
181 {
182     getDoubleFormat(_dblR, _pDFR);
183     getDoubleFormat(_dblI, _pDFI);
184
185     *_piTotalWidth = 0;
186     if (isRealZero(_dblI))
187     {
188         if (isRealZero(_dblR))
189         {
190             *_piTotalWidth += 1;    //"0"
191             _pDFI->iWidth = 0;
192             _pDFI->iSignLen = 0;
193         }
194         else
195         {
196             *_piTotalWidth += _pDFR->iWidth;
197             _pDFI->iWidth = 0;
198             _pDFI->iSignLen = 0;
199         }
200     }
201     else
202     {
203         if (isRealZero(_dblR))
204         {
205             *_piTotalWidth += _pDFI->iWidth;
206             _pDFR->iWidth = 0;
207         }
208         else
209         {
210             *_piTotalWidth += _pDFR->iWidth + _pDFI->iWidth;
211         }
212
213         // i character
214         *_piTotalWidth += 1;
215     }
216 }
217
218 void addDoubleValue(std::wostringstream * _postr, double _dblVal, DoubleFormat * _pDF)
219 {
220     wchar_t pwstFormat[32] = {0};
221     wchar_t pwstOutput[32] = {0};     // > @ format max
222     wchar_t pwstSign[32] = {0};
223     char    pstBuf[32] = {0};
224
225     if (_pDF == NULL)
226     {
227         return;
228     }
229
230     const wchar_t* pBlank = L"";
231     if (_pDF->bPrintBlank)
232     {
233         pBlank = L" ";
234     }
235
236     const wchar_t* pSign = MINUS_STRING;
237     if (_dblVal >= 0 || ISNAN(_dblVal))
238     {
239         if (_pDF->bPrintPlusSign)
240         {
241             pSign = PLUS_STRING;
242         }
243         else if (_pDF->bPaddSign)
244         {
245             pSign = NO_SIGN;
246         }
247         else
248         {
249             // PLUS_SIGN "+" is not written by default
250             pSign = L"";
251         }
252     }
253
254     // Step 1: BLANK and SIGN in pwstSign
255     if (_pDF->bPrintComplexPlusSpace)
256     {
257         os_swprintf(pwstSign, 32, L"%ls%ls%ls", pBlank, pSign, pBlank);
258     }
259     else
260     {
261         os_swprintf(pwstSign, 32, L"%ls%ls", pBlank, pSign);
262     }
263
264
265     if (ISNAN(_dblVal))
266     {
267         //NaN
268         os_swprintf(pwstOutput, 32, L"%ls%-*ls", pwstSign, _pDF->iWidth - 1, L"Nan");
269     }
270     else if (!finite(_dblVal))
271     {
272         //Inf
273         os_swprintf(pwstOutput, 32, L"%ls%-*ls", pwstSign, _pDF->iWidth - 1, L"Inf");
274     }
275     else if (_pDF->bExp)
276     {
277         // Prints the exponent part 1.543D+03 for example
278         int iDecpt = 0;
279         int iSign = 0;
280         char *pRve = nullptr;
281         char *pDtoaStr = dtoa(fabs(_dblVal), 2, _pDF->iPrec + 1, &iDecpt, &iSign, &pRve);
282
283         std::string str(pDtoaStr);
284         freedtoa(pDtoaStr);
285
286         // in format("e") omiting the decimal point has a sense
287         // only if fabs(_dblVal) is an integer in {1...9}
288         if (_pDF->bPrintPoint || str.length() > 1)
289         {
290             /* add trailing zeros */
291             str.append(fmax(0, _pDF->iPrec + 1 - str.length()), '0');
292             str.insert(1, ".");
293         }
294
295         wchar_t* pwstData = to_wide_string(str.data());
296         os_swprintf(pwstOutput, 32, L"%ls%lsD%+.02d", pwstSign, pwstData, iDecpt - 1);
297         FREE(pwstData);
298     }
299     else if ((_pDF->bPrintOne == true) || (isEqual(fabs(_dblVal), 1)) == false)
300     {
301         //do not print if _bPrintOne == false && _dblVal == 1
302         int iDecpt = 0;
303         int iSign = 0;
304         int iWidth = _pDF->iWidth;
305         char *pRve = nullptr;
306         char *pDtoaStr = dtoa(fabs(_dblVal), 2, std::floor(log10(fabs(_dblVal))) + _pDF->iPrec + 1, &iDecpt, &iSign, &pRve);
307
308         std::string str(pDtoaStr);
309         freedtoa(pDtoaStr);
310
311         /* add leading 0.000..., if applicable */
312         if (iDecpt <= 0)
313         {
314             str.insert(str.begin(), 1 - iDecpt, '0');
315             str.insert(1, ".");
316         }
317         else if (_pDF->bPrintPoint || iDecpt < str.length())
318         {
319             str.append(std::max(0, (int)(iDecpt - str.length())), '0');
320             str.insert(iDecpt, ".");
321         }
322         else 
323         {
324             str.append(std::max(0, (int)(iDecpt - str.length())), '0');
325             iWidth--;
326         }
327
328         wchar_t* pwstData = to_wide_string(str.data());
329         os_swprintf(pwstOutput, 32, L"%ls%-*ls", pwstSign, iWidth-1, pwstData);
330         FREE(pwstData);
331     }
332     else if (wcslen(pwstSign) != 0)
333     {
334         os_swprintf(pwstOutput, 32, L"%ls", pwstSign);
335     }
336
337     *_postr << pwstOutput;
338 }
339
340 /*
341 void addDoubleValue(std::wostringstream *_postr, double _dblVal, int _iWidth, int _iPrec, bool bPrintPlusSign, bool bPrintOne, bool bPaddSign)
342 {
343     addSign(_postr, _dblVal, bPrintPlusSign, bPaddSign);
344     configureStream(_postr, _iWidth, _iPrec, ' ');
345
346     if(bPrintOne == true || isEqual(_dblVal, 1) == false)
347     {
348         NEWprintDoubleVar(_postr, _dblVal, _iWidth, _iPrec);
349     }
350 }
351 */
352 void addDoubleComplexValue(std::wostringstream * _postr, double _dblR, double _dblI, int _iTotalWidth, DoubleFormat * _pDFR, DoubleFormat * _pDFI)
353 {
354     std::wostringstream ostemp;
355
356     /*
357      * if R && !C -> R
358      * if R && C -> R + Ci
359      * if !R && !C -> 0
360      * if(!R && C -> Ci
361      */
362
363     // *_postr << "|%" << _iTotalWitdh << "%|";
364     if (_dblR == 0)
365     {
366         //no real part
367         if (_dblI == 0)
368         {
369             //no imaginary part
370
371             //0
372             DoubleFormat df;
373
374             addDoubleValue(&ostemp, 0, &df);
375         }
376         else
377         {
378             //imaginary part
379
380             //I
381             DoubleFormat df;
382
383             df.iWidth = 0;
384             df.iPrec = _pDFI->iPrec;
385             df.bExp = _pDFI->bExp;
386             df.bPrintPlusSign = false;
387             df.bPrintOne = false;
388             addDoubleValue(&ostemp, _dblI, &df);
389             ostemp << std::left << SYMBOL_I;
390             if (_dblI == 1)
391             {
392                 addSpaces(&ostemp, 1);
393             }
394
395         }
396     }
397     else
398     {
399         //real part
400         if (_dblI == 0)
401         {
402             //no imaginary part
403
404             //R
405             DoubleFormat df;
406
407             df.iWidth = 0;
408             df.iPrec = _pDFR->iPrec;
409             df.bExp = _pDFR->bExp;
410             addDoubleValue(&ostemp, _dblR, &df);
411         }
412         else
413         {
414             //imaginary part
415
416             //R
417             DoubleFormat df;
418
419             df.iPrec = _pDFR->iPrec;
420             df.bExp = _pDFR->bExp;
421
422             addDoubleValue(&ostemp, _dblR, &df);
423
424             //I
425             df.iPrec = _pDFI->iPrec;
426             df.bExp = _pDFI->bExp;
427             df.bPrintPlusSign = true;
428             df.bPrintComplexPlusSpace = true;
429             df.bPrintOne = false;
430
431             addDoubleValue(&ostemp, _dblI, &df);
432             ostemp << std::left << SYMBOL_I;
433             if (_dblI == 1)
434             {
435                 addSpaces(&ostemp, 2);
436             }
437         }
438     }
439
440     configureStream(_postr, _iTotalWidth, 0, ' ');
441     *_postr << std::left << ostemp.str() << std::resetiosflags(std::ios::adjustfield);
442 }
443
444 void addSpaces(std::wostringstream * _postr, int _iSpace)
445 {
446     for (int i = 0; i < _iSpace; i++)
447     {
448         *_postr << L" ";
449     }
450 }
451
452 void configureStream(std::wostringstream * _postr, int _iWidth, int _iPrec, char _cFill)
453 {
454     _postr->setf(std::ios::showpoint);
455     _postr->width(_iWidth);
456     _postr->precision(_iPrec);
457     _postr->fill(_cFill);
458 }
459
460 void addColumnString(std::wostringstream& ostr, int _iFrom, int _iTo)
461 {
462     if (_iFrom == _iTo)
463     {
464         ostr << std::endl << L"         column " << _iFrom << std::endl << std::endl;
465     }
466     else
467     {
468         ostr << std::endl << L"         column " << _iFrom << L" to " << _iTo << std::endl << std::endl;
469     }
470 }
471
472 void printEmptyString(std::wostringstream& ostr)
473 {
474     ostr << L"    []";
475 }
476
477 void printDoubleValue(std::wostringstream& ostr, double val)
478 {
479     DoubleFormat df;
480     getDoubleFormat(val, &df);
481     ostr << SPACE_BETWEEN_TWO_VALUES;
482     addDoubleValue(&ostr, val, &df);
483 }
484
485 void printComplexValue(std::wostringstream& ostr, double val_r, double val_i)
486 {
487     DoubleFormat dfR, dfI;
488     getDoubleFormat(ZeroIsZero(val_r), &dfR);
489     getDoubleFormat(ZeroIsZero(val_i), &dfI);
490     ostr << SPACE_BETWEEN_TWO_VALUES;
491     addDoubleComplexValue(&ostr, ZeroIsZero(val_r), ZeroIsZero(val_i), dfR.iWidth + dfI.iWidth, &dfR, &dfI);
492 }