1 | // -*- c-basic-offset: 2 -*- |
2 | /* |
3 | * This file is part of the KDE libraries |
4 | * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Lesser General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Lesser General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Lesser General Public |
17 | * License along with this library; if not, write to the Free Software |
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | * |
20 | */ |
21 | |
22 | #include "math_object.h" |
23 | #include <config-kjs.h> |
24 | #include "math_object.lut.h" |
25 | #include "wtf/MathExtras.h" |
26 | |
27 | #include "operations.h" |
28 | #include <math.h> |
29 | #include <time.h> |
30 | |
31 | #ifndef M_PI |
32 | #define M_PI 3.14159265358979323846 |
33 | #endif /* M_PI */ |
34 | |
35 | #if COMPILER(MSVC) |
36 | static double cbrt(double x) |
37 | { |
38 | return pow(abs(x), 1.0 / 3.0); |
39 | } |
40 | |
41 | static double log2(double x) |
42 | { |
43 | return log(x) / log(2); |
44 | } |
45 | #endif |
46 | |
47 | using namespace KJS; |
48 | |
49 | // ------------------------------ MathObjectImp -------------------------------- |
50 | |
51 | const ClassInfo MathObjectImp::info = { "Math" , 0, &mathTable, 0 }; |
52 | |
53 | /* Source for math_object.lut.h |
54 | @begin mathTable 21 |
55 | E MathObjectImp::Euler DontEnum|DontDelete|ReadOnly |
56 | LN2 MathObjectImp::Ln2 DontEnum|DontDelete|ReadOnly |
57 | LN10 MathObjectImp::Ln10 DontEnum|DontDelete|ReadOnly |
58 | LOG2E MathObjectImp::Log2E DontEnum|DontDelete|ReadOnly |
59 | LOG10E MathObjectImp::Log10E DontEnum|DontDelete|ReadOnly |
60 | PI MathObjectImp::Pi DontEnum|DontDelete|ReadOnly |
61 | SQRT1_2 MathObjectImp::Sqrt1_2 DontEnum|DontDelete|ReadOnly |
62 | SQRT2 MathObjectImp::Sqrt2 DontEnum|DontDelete|ReadOnly |
63 | abs MathObjectImp::Abs DontEnum|Function 1 |
64 | acos MathObjectImp::ACos DontEnum|Function 1 |
65 | asin MathObjectImp::ASin DontEnum|Function 1 |
66 | atan MathObjectImp::ATan DontEnum|Function 1 |
67 | atan2 MathObjectImp::ATan2 DontEnum|Function 2 |
68 | ceil MathObjectImp::Ceil DontEnum|Function 1 |
69 | cos MathObjectImp::Cos DontEnum|Function 1 |
70 | exp MathObjectImp::Exp DontEnum|Function 1 |
71 | floor MathObjectImp::Floor DontEnum|Function 1 |
72 | log MathObjectImp::Log DontEnum|Function 1 |
73 | max MathObjectImp::Max DontEnum|Function 2 |
74 | min MathObjectImp::Min DontEnum|Function 2 |
75 | pow MathObjectImp::Pow DontEnum|Function 2 |
76 | random MathObjectImp::Random DontEnum|Function 0 |
77 | round MathObjectImp::Round DontEnum|Function 1 |
78 | sin MathObjectImp::Sin DontEnum|Function 1 |
79 | sqrt MathObjectImp::Sqrt DontEnum|Function 1 |
80 | tan MathObjectImp::Tan DontEnum|Function 1 |
81 | acosh MathObjectImp::ACosH DontEnum|Function 1 |
82 | acosh MathObjectImp::ASinH DontEnum|Function 1 |
83 | atanh MathObjectImp::ATanH DontEnum|Function 1 |
84 | cbrt MathObjectImp::Cbrt DontEnum|Function 1 |
85 | cosh MathObjectImp::CosH DontEnum|Function 1 |
86 | exmp1 MathObjectImp::Exmp1 DontEnum|Function 1 |
87 | log1p MathObjectImp::Log1p DontEnum|Function 1 |
88 | log10 MathObjectImp::Log10 DontEnum|Function 1 |
89 | log2 MathObjectImp::Log2 DontEnum|Function 1 |
90 | sign MathObjectImp::Sign DontEnum|Function 1 |
91 | sinh MathObjectImp::SinH DontEnum|Function 1 |
92 | tanh MathObjectImp::TanH DontEnum|Function 1 |
93 | trunc MathObjectImp::Trunc DontEnum|Function 1 |
94 | hypot MathObjectImp::Hypot DontEnum|Function 0 |
95 | imul MathObjectImp::Imul DontEnum|Function 2 |
96 | fround MathObjectImp::FRound DontEnum|Function 1 |
97 | @end |
98 | */ |
99 | |
100 | |
101 | MathObjectImp::MathObjectImp(ExecState * /*exec*/, |
102 | ObjectPrototype *objProto) |
103 | : JSObject(objProto) |
104 | { |
105 | } |
106 | |
107 | // ECMA 15.8 |
108 | |
109 | bool MathObjectImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot &slot) |
110 | { |
111 | return getStaticPropertySlot<MathFuncImp, MathObjectImp, JSObject>(exec, &mathTable, this, propertyName, slot); |
112 | } |
113 | |
114 | JSValue *MathObjectImp::getValueProperty(ExecState *, int token) const |
115 | { |
116 | switch (token) { |
117 | case Euler: |
118 | return jsNumber(exp(1.0)); |
119 | case Ln2: |
120 | return jsNumber(log(2.0)); |
121 | case Ln10: |
122 | return jsNumber(log(10.0)); |
123 | case Log2E: |
124 | return jsNumber(1.0/log(2.0)); |
125 | case Log10E: |
126 | return jsNumber(1.0/log(10.0)); |
127 | case Pi: |
128 | return jsNumber(piDouble); |
129 | case Sqrt1_2: |
130 | return jsNumber(sqrt(0.5)); |
131 | case Sqrt2: |
132 | return jsNumber(sqrt(2.0)); |
133 | } |
134 | |
135 | assert(0); |
136 | return 0; |
137 | } |
138 | |
139 | // ------------------------------ MathObjectImp -------------------------------- |
140 | |
141 | static bool randomSeeded = false; |
142 | |
143 | MathFuncImp::MathFuncImp(ExecState* exec, int i, int l, const Identifier& name) |
144 | : InternalFunctionImp(static_cast<FunctionPrototype*>(exec->lexicalInterpreter()->builtinFunctionPrototype()), name) |
145 | , id(i) |
146 | { |
147 | putDirect(exec->propertyNames().length, l, DontDelete|ReadOnly|DontEnum); |
148 | } |
149 | |
150 | JSValue *MathFuncImp::callAsFunction(ExecState *exec, JSObject* /*thisObj*/, const List &args) |
151 | { |
152 | double arg = args[0]->toNumber(exec); |
153 | double arg2 = args[1]->toNumber(exec); |
154 | double result; |
155 | |
156 | switch (id) { |
157 | case MathObjectImp::Abs: |
158 | result = ( arg < 0 || arg == -0) ? (-arg) : arg; |
159 | break; |
160 | case MathObjectImp::ACos: |
161 | result = ::acos(arg); |
162 | break; |
163 | case MathObjectImp::ASin: |
164 | result = ::asin(arg); |
165 | break; |
166 | case MathObjectImp::ATan: |
167 | result = ::atan(arg); |
168 | break; |
169 | case MathObjectImp::ATan2: |
170 | result = ::atan2(arg, arg2); |
171 | break; |
172 | case MathObjectImp::Ceil: |
173 | result = ::ceil(arg); |
174 | break; |
175 | case MathObjectImp::Cos: |
176 | result = ::cos(arg); |
177 | break; |
178 | case MathObjectImp::Exp: |
179 | result = ::exp(arg); |
180 | break; |
181 | case MathObjectImp::Floor: |
182 | result = ::floor(arg); |
183 | break; |
184 | case MathObjectImp::Log: |
185 | result = ::log(arg); |
186 | break; |
187 | case MathObjectImp::Max: { |
188 | unsigned int argsCount = args.size(); |
189 | result = -Inf; |
190 | for ( unsigned int k = 0 ; k < argsCount ; ++k ) { |
191 | double val = args[k]->toNumber(exec); |
192 | if ( isNaN( val ) ) |
193 | { |
194 | result = NaN; |
195 | break; |
196 | } |
197 | if ( val > result || (val == 0 && result == 0 && !signbit(val)) ) |
198 | result = val; |
199 | } |
200 | break; |
201 | } |
202 | case MathObjectImp::Min: { |
203 | unsigned int argsCount = args.size(); |
204 | result = +Inf; |
205 | for ( unsigned int k = 0 ; k < argsCount ; ++k ) { |
206 | double val = args[k]->toNumber(exec); |
207 | if ( isNaN( val ) ) |
208 | { |
209 | result = NaN; |
210 | break; |
211 | } |
212 | if ( val < result || (val == 0 && result == 0 && signbit(val)) ) |
213 | result = val; |
214 | } |
215 | break; |
216 | } |
217 | case MathObjectImp::Pow: |
218 | // ECMA 15.8.2.1.13 (::pow takes care of most of the critera) |
219 | if (isNaN(arg2)) |
220 | result = NaN; |
221 | else if (isNaN(arg) && arg2 != 0) |
222 | result = NaN; |
223 | else if (::fabs(arg) == 1 && isInf(arg2)) |
224 | result = NaN; |
225 | else if (arg2 == 0 && arg != 0) |
226 | result = 1; |
227 | else |
228 | result = ::pow(arg, arg2); |
229 | break; |
230 | case MathObjectImp::Random: |
231 | if (!randomSeeded) { |
232 | srand(static_cast<unsigned>(time(0))); |
233 | randomSeeded = true; |
234 | } |
235 | result = (double)rand() / RAND_MAX; |
236 | break; |
237 | case MathObjectImp::Round: |
238 | if (signbit(arg) && arg >= -0.5) |
239 | result = -0.0; |
240 | else |
241 | result = ::floor(arg + 0.5); |
242 | break; |
243 | case MathObjectImp::Sin: |
244 | result = ::sin(arg); |
245 | break; |
246 | case MathObjectImp::Sqrt: |
247 | result = ::sqrt(arg); |
248 | break; |
249 | case MathObjectImp::Tan: |
250 | result = ::tan(arg); |
251 | break; |
252 | |
253 | //ES6 (draft 08.11.2013) |
254 | case MathObjectImp::ACosH: |
255 | result = ::acosh(arg); |
256 | break; |
257 | case MathObjectImp::ASinH: |
258 | result = ::asinh(arg); |
259 | break; |
260 | case MathObjectImp::ATanH: |
261 | result = ::atanh(arg); |
262 | break; |
263 | case MathObjectImp::Cbrt: |
264 | result = ::cbrt(arg); |
265 | break; |
266 | case MathObjectImp::CosH: |
267 | result = ::cosh(arg); |
268 | break; |
269 | case MathObjectImp::Exmp1: |
270 | result = ::expm1(arg); |
271 | break; |
272 | case MathObjectImp::Log1p: |
273 | result = ::log1p(arg); |
274 | break; |
275 | case MathObjectImp::Log10: |
276 | result = ::log10(arg); |
277 | break; |
278 | case MathObjectImp::Log2: |
279 | result = ::log2(arg); |
280 | break; |
281 | case MathObjectImp::Sign: |
282 | if (isNaN(arg)) |
283 | { |
284 | result = KJS::NaN; |
285 | } |
286 | else if (signbit(arg)) |
287 | { |
288 | if (arg == 0) |
289 | result = -0.0; |
290 | else |
291 | result = -1.0; |
292 | } |
293 | else |
294 | { |
295 | if (arg == 0) |
296 | result = 0.0; |
297 | else |
298 | result = 1.0; |
299 | } |
300 | break; |
301 | case MathObjectImp::SinH: |
302 | result = ::sinh(arg); |
303 | break; |
304 | case MathObjectImp::TanH: |
305 | result = ::tanh(arg); |
306 | break; |
307 | case MathObjectImp::Trunc: |
308 | result = ::trunc(arg); |
309 | break; |
310 | case MathObjectImp::Hypot: |
311 | { |
312 | if (args.size() == 0) |
313 | { |
314 | result = 0; |
315 | break; |
316 | } |
317 | |
318 | double sum = 0.0; |
319 | bool foundNaN = false; |
320 | for (int i = 0; i < args.size(); ++i) |
321 | { |
322 | double num = args[i]->toNumber(exec); |
323 | if (isInf(num)) |
324 | return jsNumber(KJS::Inf); |
325 | if (foundNaN) |
326 | continue; |
327 | if (isNaN(num)) |
328 | { |
329 | foundNaN = true; |
330 | continue; |
331 | } |
332 | |
333 | sum += ::pow(num, 2); |
334 | } |
335 | |
336 | if (foundNaN) |
337 | return jsNumber(KJS::NaN); |
338 | |
339 | result = ::sqrt(sum); |
340 | break; |
341 | } |
342 | case MathObjectImp::Imul: |
343 | { |
344 | if (args.size() < 2) |
345 | return jsUndefined(); |
346 | int32_t a = args[0]->toInt32(exec); |
347 | if (exec->hadException()) |
348 | return jsNumber(a); |
349 | int32_t b = args[1]->toInt32(exec); |
350 | if (exec->hadException()) |
351 | return jsNumber(b); |
352 | |
353 | result = a * b; |
354 | break; |
355 | } |
356 | case MathObjectImp::FRound: |
357 | if (isNaN(arg) || isInf(arg)) |
358 | return jsNumber(arg); |
359 | |
360 | result = static_cast<double>(static_cast<float>(arg)); |
361 | break; |
362 | |
363 | default: |
364 | result = 0.0; |
365 | assert(0); |
366 | } |
367 | |
368 | return jsNumber(result); |
369 | } |
370 | |