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