1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 ** This file is part of the QtScript module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
10 ** This file contains pre-release code and may not be distributed.
11 ** You may use this file in accordance with the terms and conditions
12 ** contained in the either Technology Preview License Agreement or the
13 ** Beta Release License Agreement.
15 ** GNU Lesser General Public License Usage
16 ** Alternatively, this file may be used under the terms of the GNU Lesser
17 ** General Public License version 2.1 as published by the Free Software
18 ** Foundation and appearing in the file LICENSE.LGPL included in the
19 ** packaging of this file. Please review the following information to
20 ** ensure the GNU Lesser General Public License version 2.1 requirements
21 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 ** In addition, as a special exception, Nokia gives you certain
24 ** additional rights. These rights are described in the Nokia Qt LGPL
25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
28 ** GNU General Public License Usage
29 ** Alternatively, this file may be used under the terms of the GNU
30 ** General Public License version 3.0 as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL included in the
32 ** packaging of this file. Please review the following information to
33 ** ensure the GNU General Public License version 3.0 requirements will be
34 ** met: http://www.gnu.org/copyleft/gpl.html.
36 ** If you are unsure which license is appropriate for your use, please
37 ** contact the sales department at http://www.qtsoftware.com/contact.
40 ****************************************************************************/
42 #include "qscriptecmamath_p.h"
46 #include "qscriptengine_p.h"
47 #include "qscriptvalueimpl_p.h"
48 #include "qscriptcontext_p.h"
49 #include "qscriptmember_p.h"
50 #include "qscriptobject_p.h"
52 #include <QtCore/QtDebug>
53 #include <QtCore/qnumeric.h>
54 #include <QtCore/QSysInfo>
59 namespace QScript
{ namespace Ecma
{
61 static const qsreal qt_PI
= 2.0 * ::asin(1.0);
63 Math::Math(QScriptEnginePrivate
*engine
, QScriptClassInfo
*classInfo
):
65 m_classInfo(classInfo
)
73 void Math::construct(QScriptValueImpl
*object
, QScriptEnginePrivate
*eng
)
75 QScriptClassInfo
*classInfo
= eng
->registerClass(QLatin1String("Math"));
77 Math
*instance
= new Math(eng
, classInfo
);
78 eng
->newObject(object
, classInfo
);
79 object
->setObjectData(instance
);
81 QScriptValue::PropertyFlags flags
= QScriptValue::Undeletable
82 | QScriptValue::ReadOnly
83 | QScriptValue::SkipInEnumeration
;
85 object
->setProperty(QLatin1String("E"),
86 QScriptValueImpl(::exp(1.0)), flags
);
87 object
->setProperty(QLatin1String("LN2"),
88 QScriptValueImpl(::log(2.0)), flags
);
89 object
->setProperty(QLatin1String("LN10"),
90 QScriptValueImpl(::log(10.0)), flags
);
91 object
->setProperty(QLatin1String("LOG2E"),
92 QScriptValueImpl(1.0/::log(2.0)), flags
);
93 object
->setProperty(QLatin1String("LOG10E"),
94 QScriptValueImpl(1.0/::log(10.0)), flags
);
95 object
->setProperty(QLatin1String("PI"),
96 QScriptValueImpl(qt_PI
), flags
);
97 object
->setProperty(QLatin1String("SQRT1_2"),
98 QScriptValueImpl(::sqrt(0.5)), flags
);
99 object
->setProperty(QLatin1String("SQRT2"),
100 QScriptValueImpl(::sqrt(2.0)), flags
);
102 flags
= QScriptValue::SkipInEnumeration
;
103 addFunction(*object
, QLatin1String("abs"), method_abs
, 1, flags
);
104 addFunction(*object
, QLatin1String("acos"), method_acos
, 1, flags
);
105 addFunction(*object
, QLatin1String("asin"), method_asin
, 0, flags
);
106 addFunction(*object
, QLatin1String("atan"), method_atan
, 1, flags
);
107 addFunction(*object
, QLatin1String("atan2"), method_atan2
, 2, flags
);
108 addFunction(*object
, QLatin1String("ceil"), method_ceil
, 1, flags
);
109 addFunction(*object
, QLatin1String("cos"), method_cos
, 1, flags
);
110 addFunction(*object
, QLatin1String("exp"), method_exp
, 1, flags
);
111 addFunction(*object
, QLatin1String("floor"), method_floor
, 1, flags
);
112 addFunction(*object
, QLatin1String("log"), method_log
, 1, flags
);
113 addFunction(*object
, QLatin1String("max"), method_max
, 2, flags
);
114 addFunction(*object
, QLatin1String("min"), method_min
, 2, flags
);
115 addFunction(*object
, QLatin1String("pow"), method_pow
, 2, flags
);
116 addFunction(*object
, QLatin1String("random"), method_random
, 0, flags
);
117 addFunction(*object
, QLatin1String("round"), method_round
, 1, flags
);
118 addFunction(*object
, QLatin1String("sin"), method_sin
, 1, flags
);
119 addFunction(*object
, QLatin1String("sqrt"), method_sqrt
, 1, flags
);
120 addFunction(*object
, QLatin1String("tan"), method_tan
, 1, flags
);
123 /* copies the sign from y to x and returns the result */
124 static qsreal
copySign(qsreal x
, qsreal y
)
126 uchar
*xch
= (uchar
*)&x
;
127 uchar
*ych
= (uchar
*)&y
;
128 if (QSysInfo::ByteOrder
== QSysInfo::BigEndian
)
129 xch
[0] = (xch
[0] & 0x7f) | (ych
[0] & 0x80);
131 xch
[7] = (xch
[7] & 0x7f) | (ych
[7] & 0x80);
135 QScriptValueImpl
Math::method_abs(QScriptContextPrivate
*context
,
136 QScriptEnginePrivate
*,
139 qsreal v
= context
->argument(0).toNumber();
140 if (v
== 0) // 0 | -0
141 return (QScriptValueImpl(0));
143 return (QScriptValueImpl(v
< 0 ? -v
: v
));
146 QScriptValueImpl
Math::method_acos(QScriptContextPrivate
*context
,
147 QScriptEnginePrivate
*,
150 qsreal v
= context
->argument(0).toNumber();
152 return QScriptValueImpl(qSNaN());
153 return (QScriptValueImpl(::acos(v
)));
156 QScriptValueImpl
Math::method_asin(QScriptContextPrivate
*context
,
157 QScriptEnginePrivate
*,
160 qsreal v
= context
->argument(0).toNumber();
162 return QScriptValueImpl(qSNaN());
163 return (QScriptValueImpl(::asin(v
)));
166 QScriptValueImpl
Math::method_atan(QScriptContextPrivate
*context
,
167 QScriptEnginePrivate
*,
170 qsreal v
= context
->argument(0).toNumber();
172 return QScriptValueImpl(v
);
173 return (QScriptValueImpl(::atan(v
)));
176 QScriptValueImpl
Math::method_atan2(QScriptContextPrivate
*context
,
177 QScriptEnginePrivate
*,
180 qsreal v1
= context
->argument(0).toNumber();
181 qsreal v2
= context
->argument(1).toNumber();
184 const bool v1MinusZero
= _copysign(1.0, v1
) < 0.0;
185 const bool v2MinusZero
= (v2
== 0 && _copysign(1.0, v2
) < 0.0);
186 if ((v1MinusZero
&& v2MinusZero
) || (v1MinusZero
&& v2
== -1.0))
187 return QScriptValueImpl(-qt_PI
);
189 return QScriptValueImpl(qt_PI
);
190 if (v1MinusZero
&& v2
== 1.0)
191 return QScriptValueImpl(-0.0);
193 if (v2
== 0.0 && (v1MinusZero
|| (!v1MinusZero
&& !v2MinusZero
)))
194 return QScriptValueImpl(0.0);
198 #if defined(Q_OS_WINCE) && defined(_X86_)
199 if (v1
== -1.0 && !_finite(v2
) && _copysign(1.0, v2
) > 0.0)
200 return QScriptValueImpl(-0.0);
202 if ((v1
< 0) && qIsFinite(v1
) && qIsInf(v2
) && (copySign(1.0, v2
) == 1.0))
203 return QScriptValueImpl(copySign(0, -1.0));
204 if ((v1
== 0.0) && (v2
== 0.0)) {
205 if ((copySign(1.0, v1
) == 1.0) && (copySign(1.0, v2
) == -1.0))
206 return QScriptValueImpl(qt_PI
);
207 else if ((copySign(1.0, v1
) == -1.0) && (copySign(1.0, v2
) == -1.0))
208 return QScriptValueImpl(-qt_PI
);
210 return (QScriptValueImpl(::atan2(v1
, v2
)));
213 QScriptValueImpl
Math::method_ceil(QScriptContextPrivate
*context
,
214 QScriptEnginePrivate
*,
217 qsreal v
= context
->argument(0).toNumber();
218 if (v
< 0.0 && v
> -1.0)
219 return QScriptValueImpl(copySign(0, -1.0));
220 return (QScriptValueImpl(::ceil(v
)));
223 QScriptValueImpl
Math::method_cos(QScriptContextPrivate
*context
,
224 QScriptEnginePrivate
*,
227 qsreal v
= context
->argument(0).toNumber();
228 return (QScriptValueImpl(::cos(v
)));
231 QScriptValueImpl
Math::method_exp(QScriptContextPrivate
*context
,
232 QScriptEnginePrivate
*,
235 qsreal v
= context
->argument(0).toNumber();
237 if (copySign(1.0, v
) == -1.0)
238 return QScriptValueImpl(0);
240 return QScriptValueImpl(qInf());
242 return (QScriptValueImpl(::exp(v
)));
245 QScriptValueImpl
Math::method_floor(QScriptContextPrivate
*context
,
246 QScriptEnginePrivate
*,
249 qsreal v
= context
->argument(0).toNumber();
250 return (QScriptValueImpl(::floor(v
)));
253 QScriptValueImpl
Math::method_log(QScriptContextPrivate
*context
,
254 QScriptEnginePrivate
*,
257 qsreal v
= context
->argument(0).toNumber();
259 return QScriptValueImpl(qSNaN());
260 return (QScriptValueImpl(::log(v
)));
263 QScriptValueImpl
Math::method_max(QScriptContextPrivate
*context
,
264 QScriptEnginePrivate
*,
268 for (int i
= 0; i
< context
->argumentCount(); ++i
) {
269 qsreal x
= context
->argument(i
).toNumber();
270 if (x
> mx
|| qIsNaN(x
))
273 return (QScriptValueImpl(mx
));
276 QScriptValueImpl
Math::method_min(QScriptContextPrivate
*context
,
277 QScriptEnginePrivate
*,
281 for (int i
= 0; i
< context
->argumentCount(); ++i
) {
282 qsreal x
= context
->argument(i
).toNumber();
283 if ((x
== 0 && mx
== x
&& copySign(1.0, x
) == -1.0)
284 || (x
< mx
) || qIsNaN(x
)) {
288 return (QScriptValueImpl(mx
));
291 QScriptValueImpl
Math::method_pow(QScriptContextPrivate
*context
,
292 QScriptEnginePrivate
*,
295 qsreal x
= context
->argument(0).toNumber();
296 qsreal y
= context
->argument(1).toNumber();
298 return QScriptValueImpl(qSNaN());
300 return QScriptValueImpl(1);
301 if (((x
== 1) || (x
== -1)) && qIsInf(y
))
302 return QScriptValueImpl(qSNaN());
303 if (((x
== 0) && copySign(1.0, x
) == 1.0) && (y
< 0))
304 return QScriptValueImpl(qInf());
305 if ((x
== 0) && copySign(1.0, x
) == -1.0) {
307 if (::fmod(-y
, 2.0) == 1.0)
308 return QScriptValueImpl(-qInf());
310 return QScriptValueImpl(qInf());
312 if (::fmod(y
, 2.0) == 1.0)
313 return QScriptValueImpl(copySign(0, -1.0));
315 return QScriptValueImpl(0);
319 if (qIsInf(x
) && copySign(1.0, x
) == -1.0) {
321 if (::fmod(y
, 2.0) == 1.0)
322 return QScriptValueImpl(-qInf());
324 return QScriptValueImpl(qInf());
326 if (::fmod(-y
, 2.0) == 1.0)
327 return QScriptValueImpl(copySign(0, -1.0));
329 return QScriptValueImpl(0);
333 return (QScriptValueImpl(::pow(x
, y
)));
336 QScriptValueImpl
Math::method_random(QScriptContextPrivate
*,
337 QScriptEnginePrivate
*,
340 return (QScriptValueImpl(qrand() / (qsreal
) RAND_MAX
));
343 QScriptValueImpl
Math::method_round(QScriptContextPrivate
*context
,
344 QScriptEnginePrivate
*,
347 qsreal v
= context
->argument(0).toNumber();
348 v
= copySign(::floor(v
+ 0.5), v
);
349 return (QScriptValueImpl(v
));
352 QScriptValueImpl
Math::method_sin(QScriptContextPrivate
*context
,
353 QScriptEnginePrivate
*,
356 qsreal v
= context
->argument(0).toNumber();
357 return (QScriptValueImpl(::sin(v
)));
360 QScriptValueImpl
Math::method_sqrt(QScriptContextPrivate
*context
,
361 QScriptEnginePrivate
*,
364 qsreal v
= context
->argument(0).toNumber();
365 return (QScriptValueImpl(::sqrt(v
)));
368 QScriptValueImpl
Math::method_tan(QScriptContextPrivate
*context
,
369 QScriptEnginePrivate
*,
372 qsreal v
= context
->argument(0).toNumber();
374 return QScriptValueImpl(v
);
375 return (QScriptValueImpl(::tan(v
)));
378 void Math::addFunction(QScriptValueImpl
&object
, const QString
&name
,
379 QScriptInternalFunctionSignature fun
, int length
,
380 const QScriptValue::PropertyFlags flags
)
382 QScriptEnginePrivate
*eng_p
= object
.engine();
383 QScriptValueImpl val
= eng_p
->createFunction(fun
, length
, object
.classInfo(), name
);
384 object
.setProperty(name
, val
, flags
);
387 } } // namespace QScript::Ecma
391 #endif // QT_NO_SCRIPT