elementary_functions: fix rand() with a single key letter after 02f1f9cd
[scilab.git] / scilab / modules / elementary_functions / sci_gateway / cpp / sci_rand.cpp
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2011 - DIGITEO - Antoine ELIAS
4  * Copyright (C) 2014 - Scilab Enterprises - Anais Aubert
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 "elem_func_gw.hxx"
18 #include "function.hxx"
19 #include "overload.hxx"
20 #include "double.hxx"
21 #include "string.hxx"
22
23 extern "C"
24 {
25 #include "Scierror.h"
26 #include "localization.h"
27 #include "basic_functions.h"
28 }
29
30 const wchar_t g_pwstConfigInfo[] = L"info";
31 const wchar_t g_pwstConfigSeed[] = L"seed";
32
33 const wchar_t g_pwstTypeUniform[] = L"uniform";
34 const wchar_t g_pwstTypeNormal[] = L"normal";
35
36 int setRandType(const wchar_t* _wcType);
37 double getNextRandValue(int _iRandType, int* _piRandSave, int _iForceInit);
38
39 /*
40 clear a;nb = 2500;a = rand(nb, nb);tic();rand(a);toc
41 clear a;nb = 2500;a = rand(nb, nb);a = a + a * %i;tic();rand(a);toc
42 */
43
44 types::Function::ReturnValue sci_rand(types::typed_list &in, int _iRetCount, types::typed_list &out)
45 {
46     types::Double* pOut = NULL;
47     static int siRandType = 0;
48     static int siRandSave = 0;
49     static int iForceInit       = 0;
50
51     int iSizeIn = (int)in.size();
52     if (iSizeIn == 0 || iSizeIn == -1)
53     {
54         //rand or rand()
55         double dblRand = getNextRandValue(siRandType, &siRandSave, 0);
56         out.push_back(new types::Double(dblRand));
57         return types::Function::OK;
58     }
59
60     if (in[0]->isString())
61     {
62         //rand("xxx")
63         types::String* pS = in[0]->getAs<types::String>();
64         if (pS->getSize() != 1)
65         {
66             Scierror(999, _("%s: Wrong size for input argument #%d: string expected.\n"), "rand", 1);
67             return types::Function::Error;
68         }
69
70         wchar_t* pwstKey = pS->get(0);
71
72         if (!wcscmp(pwstKey,g_pwstConfigInfo))
73         {
74             //info
75             if (iSizeIn > 1)
76             {
77                 Scierror(77, _("%s: Wrong number of input argument(s): %d expected.\n"), "rand", 1);
78                 return types::Function::Error;
79             }
80
81             if (siRandType == 0)
82             {
83                 out.push_back(new types::String(g_pwstTypeUniform));
84             }
85             else
86             {
87                 out.push_back(new types::String(g_pwstTypeNormal));
88             }
89         }
90         else if (!wcscmp(pwstKey,g_pwstConfigSeed))
91         {
92             //seed
93             if (iSizeIn == 1)
94             {
95                 //get
96                 out.push_back(new types::Double(siRandSave));
97             }
98             else if (iSizeIn == 2)
99             {
100                 if (in[1]->isDouble() == false || in[1]->getAs<types::Double>()->isScalar() == false)
101                 {
102                     Scierror(999, _("%s: Wrong size for input argument #%d: A scalar expected.\n"), "rand", 2);
103                     return types::Function::Error;
104                 }
105
106                 siRandSave = (int)std::max(in[1]->getAs<types::Double>()->get(0), double(0));
107                 iForceInit = 1;
108             }
109             else
110             {
111                 Scierror(77, _("%s: Wrong number of input argument(s): %d expected.\n"), "rand", 2);
112                 return types::Function::Error;
113             }
114         }
115         else
116         {
117             int iRandSave = siRandType;
118             if (iSizeIn > 1)
119             {
120                 Scierror(77, _("%s: Wrong number of input argument(s): %d expected.\n"), "rand", 1);
121                 return types::Function::Error;
122             }
123             siRandType = setRandType(pwstKey);
124             if (siRandType < 0) 
125             {
126                 siRandType = iRandSave;                
127                 Scierror(999, _("%s: Wrong value for input argument #%d: '%s', '%s', '%s' or '%s' expected.\n"), "rand", 1,"info","seed","uniform","normal");
128                 return types::Function::Error;
129             }
130         }
131     }
132     else
133     {
134         int iRandSave = siRandType;
135         if (in[iSizeIn - 1]->isString())
136         {
137             //uniform ou normal
138             types::String* pS = in[iSizeIn - 1]->getAs<types::String>();
139             if (pS->getSize() != 1)
140             {
141                 Scierror(999, _("%s: Wrong size for input argument #%d: string expected.\n"), "rand", iSizeIn);
142                 return types::Function::Error;
143             }
144
145             //set randomize law
146             siRandType = setRandType(pS->get(0));
147             if (siRandType < 0) 
148             {
149                 siRandType = iRandSave;                
150                 Scierror(999, _("%s: Wrong value for input argument #%d: '%s' or '%s' expected.\n"), "rand", iSizeIn,"uniform","normal");
151                 return types::Function::Error;
152             }
153             
154             iSizeIn--;
155         }
156
157         types::typed_list args;
158         std::copy(in.begin(), in.begin() + iSizeIn, back_inserter(args));
159
160         int iDims = 0;
161         int* piDims = NULL;
162         bool alloc = false;
163
164         bool ret = getDimsFromArguments(args, "rand", &iDims, &piDims, &alloc);
165         if (ret == false)
166         {
167             switch (iDims)
168             {
169                 case -1:
170                     Scierror(21, _("Invalid index.\n"));
171                     break;
172                 case 1:
173                 {
174                     //call overload
175                     return Overload::generateNameAndCall(L"rand", in, _iRetCount, out);
176                 }
177             }
178
179             return types::Function::Error;
180         }
181
182         //special case for complex unique complex argument
183         bool complex = false;
184         if (in.size() == 1 && in[0]->isGenericType())
185         {
186             complex = in[0]->getAs<types::GenericType>()->isComplex();
187         }
188
189         pOut = new types::Double(iDims, piDims, complex);
190         if (alloc)
191         {
192             delete[] piDims;
193         }
194
195         double* pd = pOut->get();
196         for (int i = 0; i < pOut->getSize(); i++)
197         {
198             pd[i] = getNextRandValue(siRandType, &siRandSave, iForceInit);
199             iForceInit = 0;
200         }
201
202         if (pOut->isComplex())
203         {
204             double* pImg = pOut->getImg();
205             for (int i = 0; i < pOut->getSize(); i++)
206             {
207                 pImg[i] = getNextRandValue(siRandType, &siRandSave, iForceInit);
208             }
209         }
210         out.push_back(pOut);
211         //retore previous law
212         siRandType = iRandSave;
213     }
214
215     return types::Function::OK;
216 }
217 /*--------------------------------------------------------------------------*/
218 double getNextRandValue(int _iRandType, int* _piRandSave, int _iForceInit)
219 {
220     static int siInit = TRUE;
221     static double sdblImg = 0;
222     static double sdblR = 0;
223     double dblReal = 0;
224     double dblVal = 0;
225     double dblTemp = 2;
226
227     if (_iForceInit)
228     {
229         siInit = TRUE;
230     }
231
232     if (_iRandType == 0)
233     {
234         dblVal = durands(_piRandSave);
235     }
236     else
237     {
238         if (siInit == TRUE)
239         {
240             while (dblTemp > 1)
241             {
242                 dblReal = 2 * durands(_piRandSave) - 1;
243                 sdblImg = 2 * durands(_piRandSave) - 1;
244                 dblTemp = dblReal * dblReal + sdblImg * sdblImg;
245             }
246             sdblR = dsqrts(-2 * dlogs(dblTemp) / dblTemp);
247             dblVal = dblReal * sdblR;
248         }
249         else
250         {
251             dblVal = sdblImg * sdblR;
252         }
253         siInit = !siInit;
254     }
255     return dblVal;
256 }
257
258 int setRandType(const wchar_t* _wcType)
259 {
260     if (!wcscmp(_wcType,g_pwstTypeUniform))
261     {
262         return 0;
263     }
264     if (!wcscmp(_wcType,g_pwstTypeNormal))
265     {
266         return 1;
267     }
268
269     // shortcut version
270     if (_wcType[0] == g_pwstTypeUniform[0] && _wcType[1] == L'\0')
271     {
272         return 0;
273     }
274     if (_wcType[0] == g_pwstTypeNormal[0] && _wcType[1] == L'\0')
275     {
276         return 1;
277     }
278
279     // invalid key
280     return -1;
281 }
282 /*--------------------------------------------------------------------------*/
283