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