Merge remote-tracking branch 'origin/master' into windows
[scilab.git] / scilab / modules / elementary_functions / sci_gateway / cpp / sci_rat.cpp
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012 - Scilab Enterprises - Cedric Delamarre
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 <algorithm>
17
18 #include "elem_func_gw.hxx"
19 #include "function.hxx"
20 #include "double.hxx"
21 #include "overload.hxx"
22
23 extern "C"
24 {
25 #include "Scierror.h"
26 #include "localization.h"
27 #include "basic_functions.h"
28
29     extern void C2F(rat)(double*, double*, int*, int*, int*);
30 }
31 /*
32 clear a; nb = 2500; a = rand(nb, nb); tic(); rat(a); toc
33 */
34 /*--------------------------------------------------------------------------*/
35 types::Function::ReturnValue sci_rat(types::typed_list &in, int _iRetCount, types::typed_list &out)
36 {
37     types::Double* pDblIn   = NULL;
38     types::Double* pDblN    = NULL; // numerator
39     types::Double* pDblD    = NULL; // denominator
40     types::Double* pDblOut  = NULL; // if _iRetCount == 1 the result is N/D
41
42     double dblTol  = 1.e-6;
43
44     if (in.size() < 1 || in.size() > 3)
45     {
46         Scierror(77, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), "rat", 1, 3);
47         return types::Function::Error;
48     }
49
50     if (_iRetCount > 2)
51     {
52         Scierror(78, _("%s: Wrong number of output argument(s): %d to %d expected.\n"), "rat", 1, 2);
53         return types::Function::Error;
54     }
55
56     /***** get data *****/
57     if (in[0]->isDouble() == false)
58     {
59         std::string stFuncName = "%" + in[0]->getShortTypeStr() + "_rat";
60         return Overload::call(stFuncName, in, _iRetCount, out);
61     }
62
63     pDblIn = in[0]->getAs<types::Double>();
64
65     if (pDblIn->getDims() > 2)
66     {
67         return Overload::call("%hm_rat", in, _iRetCount, out);
68     }
69
70     if (pDblIn->isComplex())
71     {
72         std::string stFuncName = "%" + in[0]->getShortTypeStr() + "_rat";
73         return Overload::call(stFuncName, in, _iRetCount, out);
74     }
75
76     if (in.size() == 2)
77     {
78         if (in[1]->isDouble() == false || in[1]->getAs<types::Double>()->isScalar() == false)
79         {
80             Scierror(999, _("%s: Wrong type for input argument #%d : A constant scalar expected.\n"), "rat", 2);
81             return types::Function::Error;
82         }
83
84         dblTol = in[1]->getAs<types::Double>()->get(0);
85     }
86
87     /***** perform operation and set result *****/
88     int dblN        = 0;
89     int dblD        = 0;
90     int iFail       = 0;
91     double dblRTol  = 0;
92     int size = pDblIn->getSize();
93     double* pR = pDblIn->get();
94
95     // Make tolerance relative to the element with maximum absolute value
96     for (int i = 0; i < size; i++)
97     {
98         dblRTol = std::max(dblRTol, std::fabs(pR[i]));
99     }
100
101     if (dblRTol > 0)
102     {
103         dblTol = dblTol * dblRTol;
104     }
105
106     if (_iRetCount == 1)
107     {
108         pDblOut = new types::Double(pDblIn->getRows(), pDblIn->getCols());
109         double* pOutR = pDblOut->get();
110         for (int i = 0; i < size; i++)
111         {
112             C2F(rat)(pR + i, &dblTol, &dblN, &dblD, &iFail);
113             if (iFail)
114             {
115                 Scierror(999, _("%s: The tolerance is too large for the value %d.\n"), "rat", i);
116                 return types::Function::Error;
117             }
118             pOutR[i] = (double)dblN / (double)dblD;
119         }
120
121         out.push_back(pDblOut);
122     }
123     else // _iRetCount == 2
124     {
125         pDblN = new types::Double(pDblIn->getRows(), pDblIn->getCols());
126         pDblD = new types::Double(pDblIn->getRows(), pDblIn->getCols());
127         double* pNR = pDblN->get();
128         double* pDR = pDblD->get();
129
130         for (int i = 0; i < size; i++)
131         {
132             C2F(rat)(pR + i, &dblTol, &dblN, &dblD, &iFail);
133             if (iFail)
134             {
135                 Scierror(999, _("%s: The tolerance is too large for the value %d.\n"), "rat", i);
136                 return types::Function::Error;
137             }
138             pNR[i] = (double)dblN;
139             pDR[i] = (double)dblD;
140         }
141
142         out.push_back(pDblN);
143         out.push_back(pDblD);
144     }
145
146     return types::Function::OK;
147 }
148 /*--------------------------------------------------------------------------*/