2003/05/12 05:10:30
[org.ibex.core.git] / src / org / mozilla / javascript / NativeMath.java
1 /* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*-\r
2  *\r
3  * The contents of this file are subject to the Netscape Public\r
4  * License Version 1.1 (the "License"); you may not use this file\r
5  * except in compliance with the License. You may obtain a copy of\r
6  * the License at http://www.mozilla.org/NPL/\r
7  *\r
8  * Software distributed under the License is distributed on an "AS\r
9  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
10  * implied. See the License for the specific language governing\r
11  * rights and limitations under the License.\r
12  *\r
13  * The Original Code is Rhino code, released\r
14  * May 6, 1999.\r
15  *\r
16  * The Initial Developer of the Original Code is Netscape\r
17  * Communications Corporation.  Portions created by Netscape are\r
18  * Copyright (C) 1997-1999 Netscape Communications Corporation. All\r
19  * Rights Reserved.\r
20  *\r
21  * Contributor(s):\r
22  * Norris Boyd\r
23  * Igor Bukanov\r
24  *\r
25  * Alternatively, the contents of this file may be used under the\r
26  * terms of the GNU Public License (the "GPL"), in which case the\r
27  * provisions of the GPL are applicable instead of those above.\r
28  * If you wish to allow use of your version of this file only\r
29  * under the terms of the GPL and not to allow others to use your\r
30  * version of this file under the NPL, indicate your decision by\r
31  * deleting the provisions above and replace them with the notice\r
32  * and other provisions required by the GPL.  If you do not delete\r
33  * the provisions above, a recipient may use your version of this\r
34  * file under either the NPL or the GPL.\r
35  */\r
36 \r
37 package org.mozilla.javascript;\r
38 \r
39 /**\r
40  * This class implements the Math native object.\r
41  * See ECMA 15.8.\r
42  * @author Norris Boyd\r
43  */\r
44 \r
45 public class NativeMath extends IdScriptable\r
46 {\r
47     public static void init(Context cx, Scriptable scope, boolean sealed) {\r
48         NativeMath obj = new NativeMath();\r
49         obj.setSealFunctionsFlag(sealed);\r
50         obj.setFunctionParametrs(cx);\r
51         obj.setPrototype(getObjectPrototype(scope));\r
52         obj.setParentScope(scope);\r
53         if (sealed) { obj.sealObject(); }\r
54         ScriptableObject.defineProperty(scope, "Math", obj,\r
55                                         ScriptableObject.DONTENUM);\r
56     }\r
57 \r
58     public String getClassName() { return "Math"; }\r
59 \r
60     protected int getIdDefaultAttributes(int id) {\r
61         if (id > LAST_METHOD_ID) {\r
62             return DONTENUM | READONLY | PERMANENT;\r
63         }\r
64         return super.getIdDefaultAttributes(id);\r
65     }\r
66 \r
67     protected Object getIdValue(int id) {\r
68         if (id > LAST_METHOD_ID) {\r
69             return cacheIdValue(id, wrap_double(getField(id)));\r
70         }\r
71         return super.getIdValue(id);\r
72     }\r
73 \r
74     private double getField(int fieldId) {\r
75         switch (fieldId) {\r
76             case Id_E:       return E;\r
77             case Id_PI:      return PI;\r
78             case Id_LN10:    return LN10;\r
79             case Id_LN2:     return LN2;\r
80             case Id_LOG2E:   return LOG2E;\r
81             case Id_LOG10E:  return LOG10E;\r
82             case Id_SQRT1_2: return SQRT1_2;\r
83             case Id_SQRT2:   return SQRT2;\r
84         }\r
85         return 0; // Unreachable\r
86     }\r
87 \r
88     public int methodArity(int methodId) {\r
89         switch (methodId) {\r
90             case Id_abs:      return 1;\r
91             case Id_acos:     return 1;\r
92             case Id_asin:     return 1;\r
93             case Id_atan:     return 1;\r
94             case Id_atan2:    return 2;\r
95             case Id_ceil:     return 1;\r
96             case Id_cos:      return 1;\r
97             case Id_exp:      return 1;\r
98             case Id_floor:    return 1;\r
99             case Id_log:      return 1;\r
100             case Id_max:      return 2;\r
101             case Id_min:      return 2;\r
102             case Id_pow:      return 2;\r
103             case Id_random:   return 0;\r
104             case Id_round:    return 1;\r
105             case Id_sin:      return 1;\r
106             case Id_sqrt:     return 1;\r
107             case Id_tan:      return 1;\r
108         }\r
109         return super.methodArity(methodId);\r
110     }\r
111 \r
112     public Object execMethod\r
113         (int methodId, IdFunction f,\r
114          Context cx, Scriptable scope, Scriptable thisObj, Object[] args)\r
115         throws JavaScriptException\r
116     {\r
117         switch (methodId) {\r
118             case Id_abs: return wrap_double\r
119                 (js_abs(ScriptRuntime.toNumber(args, 0)));\r
120 \r
121             case Id_acos: return wrap_double\r
122                 (js_acos(ScriptRuntime.toNumber(args, 0)));\r
123 \r
124             case Id_asin: return wrap_double\r
125                 (js_asin(ScriptRuntime.toNumber(args, 0)));\r
126 \r
127             case Id_atan: return wrap_double\r
128                 (js_atan(ScriptRuntime.toNumber(args, 0)));\r
129 \r
130             case Id_atan2: return wrap_double\r
131                 (js_atan2(ScriptRuntime.toNumber(args, 0),\r
132                           ScriptRuntime.toNumber(args, 1)));\r
133 \r
134             case Id_ceil: return wrap_double\r
135                 (js_ceil(ScriptRuntime.toNumber(args, 0)));\r
136 \r
137             case Id_cos: return wrap_double\r
138                 (js_cos(ScriptRuntime.toNumber(args, 0)));\r
139 \r
140             case Id_exp: return wrap_double\r
141                 (js_exp(ScriptRuntime.toNumber(args, 0)));\r
142 \r
143             case Id_floor: return wrap_double\r
144                 (js_floor(ScriptRuntime.toNumber(args, 0)));\r
145 \r
146             case Id_log: return wrap_double\r
147                 (js_log(ScriptRuntime.toNumber(args, 0)));\r
148 \r
149             case Id_max: return wrap_double\r
150                 (js_max(args));\r
151 \r
152             case Id_min: return wrap_double\r
153                 (js_min(args));\r
154 \r
155             case Id_pow: return wrap_double\r
156                 (js_pow(ScriptRuntime.toNumber(args, 0),\r
157                         ScriptRuntime.toNumber(args, 1)));\r
158 \r
159             case Id_random: return wrap_double\r
160                 (js_random());\r
161 \r
162             case Id_round: return wrap_double\r
163                 (js_round(ScriptRuntime.toNumber(args, 0)));\r
164 \r
165             case Id_sin: return wrap_double\r
166                 (js_sin(ScriptRuntime.toNumber(args, 0)));\r
167 \r
168             case Id_sqrt: return wrap_double\r
169                 (js_sqrt(ScriptRuntime.toNumber(args, 0)));\r
170 \r
171             case Id_tan: return wrap_double\r
172                 (js_tan(ScriptRuntime.toNumber(args, 0)));\r
173         }\r
174         return super.execMethod(methodId, f, cx, scope, thisObj, args);\r
175     }\r
176 \r
177     private double js_abs(double x) {\r
178         // abs(-0.0) should be 0.0, but -0.0 < 0.0 == false\r
179         return (x == 0.0) ? 0.0 : (x < 0.0) ? -x : x;\r
180     }\r
181 \r
182     private double js_acos(double x) {\r
183         return (x == x && -1.0 <= x && x <= 1.0) ? Math.acos(x) : Double.NaN;\r
184     }\r
185 \r
186     private double js_asin(double x) {\r
187         return (x == x && -1.0 <= x && x <= 1.0) ? Math.asin(x) : Double.NaN;\r
188     }\r
189 \r
190     private double js_atan(double x) { return Math.atan(x); }\r
191 \r
192     private double js_atan2(double x, double y) { return Math.atan2(x, y); }\r
193 \r
194     private double js_ceil(double x) { return Math.ceil(x); }\r
195 \r
196     private double js_cos(double x) { return Math.cos(x); }\r
197 \r
198     private double js_exp(double x) {\r
199         return (x == Double.POSITIVE_INFINITY) ? x\r
200             : (x == Double.NEGATIVE_INFINITY) ? 0.0\r
201             : Math.exp(x);\r
202     }\r
203 \r
204     private double js_floor(double x) { return Math.floor(x); }\r
205 \r
206     private double js_log(double x) {\r
207         // Java's log(<0) = -Infinity; we need NaN\r
208         return (x < 0) ? Double.NaN : Math.log(x);\r
209     }\r
210 \r
211     private double js_max(Object[] args) {\r
212         double result = Double.NEGATIVE_INFINITY;\r
213         if (args.length == 0)\r
214             return result;\r
215         for (int i = 0; i < args.length; i++) {\r
216             double d = ScriptRuntime.toNumber(args[i]);\r
217             if (d != d) return d;\r
218             // if (result < d) result = d; does not work due to -0.0 >= +0.0\r
219             result = Math.max(result, d);\r
220         }\r
221         return result;\r
222     }\r
223 \r
224     private double js_min(Object[] args) {\r
225         double result = Double.POSITIVE_INFINITY;\r
226         if (args.length == 0)\r
227             return result;\r
228         for (int i = 0; i < args.length; i++) {\r
229             double d = ScriptRuntime.toNumber(args[i]);\r
230             if (d != d) return d;\r
231             // if (result > d) result = d; does not work due to -0.0 >= +0.0\r
232             result = Math.min(result, d);\r
233         }\r
234         return result;\r
235     }\r
236 \r
237     private double js_pow(double x, double y) {\r
238         if (y == 0) return 1.0;   // Java's pow(NaN, 0) = NaN; we need 1\r
239         if ((x == 0) && (y < 0)) {\r
240             if (1 / x > 0) {\r
241                 // x is +0, Java is -oo, we need +oo\r
242                 return Double.POSITIVE_INFINITY;\r
243             }\r
244             /* if x is -0 and y is an odd integer, -oo */\r
245             int y_int = (int)y;\r
246             if (y_int == y && (y_int & 0x1) != 0)\r
247                 return Double.NEGATIVE_INFINITY;\r
248             return Double.POSITIVE_INFINITY;\r
249         }\r
250         return Math.pow(x, y);\r
251     }\r
252 \r
253     private double js_random() { return Math.random(); }\r
254 \r
255     private double js_round(double d) {\r
256         if (d != d)\r
257             return d;   // NaN\r
258         if (d == Double.POSITIVE_INFINITY || d == Double.NEGATIVE_INFINITY)\r
259             return d;\r
260         long l = Math.round(d);\r
261         if (l == 0) {\r
262             // We must propagate the sign of d into the result\r
263             if (d < 0.0)\r
264                 return ScriptRuntime.negativeZero;\r
265             return d == 0.0 ? d : 0.0;\r
266         }\r
267         return (double) l;\r
268     }\r
269 \r
270     private double js_sin(double x) { return Math.sin(x); }\r
271 \r
272     private double js_sqrt(double x) { return Math.sqrt(x); }\r
273 \r
274     private double js_tan(double x) { return Math.tan(x); }\r
275 \r
276     protected int maxInstanceId() { return MAX_INSTANCE_ID; }\r
277 \r
278     protected String getIdName(int id) {\r
279         switch (id) {\r
280             case Id_abs:      return "abs";\r
281             case Id_acos:     return "acos";\r
282             case Id_asin:     return "asin";\r
283             case Id_atan:     return "atan";\r
284             case Id_atan2:    return "atan2";\r
285             case Id_ceil:     return "ceil";\r
286             case Id_cos:      return "cos";\r
287             case Id_exp:      return "exp";\r
288             case Id_floor:    return "floor";\r
289             case Id_log:      return "log";\r
290             case Id_max:      return "max";\r
291             case Id_min:      return "min";\r
292             case Id_pow:      return "pow";\r
293             case Id_random:   return "random";\r
294             case Id_round:    return "round";\r
295             case Id_sin:      return "sin";\r
296             case Id_sqrt:     return "sqrt";\r
297             case Id_tan:      return "tan";\r
298 \r
299             case Id_E:        return "E";\r
300             case Id_PI:       return "PI";\r
301             case Id_LN10:     return "LN10";\r
302             case Id_LN2:      return "LN2";\r
303             case Id_LOG2E:    return "LOG2E";\r
304             case Id_LOG10E:   return "LOG10E";\r
305             case Id_SQRT1_2:  return "SQRT1_2";\r
306             case Id_SQRT2:    return "SQRT2";\r
307         }\r
308         return null;\r
309     }\r
310 \r
311 // #string_id_map#\r
312 \r
313     protected int mapNameToId(String s) {\r
314         int id;\r
315 // #generated# Last update: 2001-03-23 13:50:14 GMT+01:00\r
316         L0: { id = 0; String X = null; int c;\r
317             L: switch (s.length()) {\r
318             case 1: if (s.charAt(0)=='E') {id=Id_E; break L0;} break L;\r
319             case 2: if (s.charAt(0)=='P' && s.charAt(1)=='I') {id=Id_PI; break L0;} break L;\r
320             case 3: switch (s.charAt(0)) {\r
321                 case 'L': if (s.charAt(2)=='2' && s.charAt(1)=='N') {id=Id_LN2; break L0;} break L;\r
322                 case 'a': if (s.charAt(2)=='s' && s.charAt(1)=='b') {id=Id_abs; break L0;} break L;\r
323                 case 'c': if (s.charAt(2)=='s' && s.charAt(1)=='o') {id=Id_cos; break L0;} break L;\r
324                 case 'e': if (s.charAt(2)=='p' && s.charAt(1)=='x') {id=Id_exp; break L0;} break L;\r
325                 case 'l': if (s.charAt(2)=='g' && s.charAt(1)=='o') {id=Id_log; break L0;} break L;\r
326                 case 'm': c=s.charAt(2);\r
327                     if (c=='n') { if (s.charAt(1)=='i') {id=Id_min; break L0;} }\r
328                     else if (c=='x') { if (s.charAt(1)=='a') {id=Id_max; break L0;} }\r
329                     break L;\r
330                 case 'p': if (s.charAt(2)=='w' && s.charAt(1)=='o') {id=Id_pow; break L0;} break L;\r
331                 case 's': if (s.charAt(2)=='n' && s.charAt(1)=='i') {id=Id_sin; break L0;} break L;\r
332                 case 't': if (s.charAt(2)=='n' && s.charAt(1)=='a') {id=Id_tan; break L0;} break L;\r
333                 } break L;\r
334             case 4: switch (s.charAt(1)) {\r
335                 case 'N': X="LN10";id=Id_LN10; break L;\r
336                 case 'c': X="acos";id=Id_acos; break L;\r
337                 case 'e': X="ceil";id=Id_ceil; break L;\r
338                 case 'q': X="sqrt";id=Id_sqrt; break L;\r
339                 case 's': X="asin";id=Id_asin; break L;\r
340                 case 't': X="atan";id=Id_atan; break L;\r
341                 } break L;\r
342             case 5: switch (s.charAt(0)) {\r
343                 case 'L': X="LOG2E";id=Id_LOG2E; break L;\r
344                 case 'S': X="SQRT2";id=Id_SQRT2; break L;\r
345                 case 'a': X="atan2";id=Id_atan2; break L;\r
346                 case 'f': X="floor";id=Id_floor; break L;\r
347                 case 'r': X="round";id=Id_round; break L;\r
348                 } break L;\r
349             case 6: c=s.charAt(0);\r
350                 if (c=='L') { X="LOG10E";id=Id_LOG10E; }\r
351                 else if (c=='r') { X="random";id=Id_random; }\r
352                 break L;\r
353             case 7: X="SQRT1_2";id=Id_SQRT1_2; break L;\r
354             }\r
355             if (X!=null && X!=s && !X.equals(s)) id = 0;\r
356         }\r
357 // #/generated#\r
358         return id;\r
359     }\r
360 \r
361     private static final int\r
362         Id_abs          =  1,\r
363         Id_acos         =  2,\r
364         Id_asin         =  3,\r
365         Id_atan         =  4,\r
366         Id_atan2        =  5,\r
367         Id_ceil         =  6,\r
368         Id_cos          =  7,\r
369         Id_exp          =  8,\r
370         Id_floor        =  9,\r
371         Id_log          = 10,\r
372         Id_max          = 11,\r
373         Id_min          = 12,\r
374         Id_pow          = 13,\r
375         Id_random       = 14,\r
376         Id_round        = 15,\r
377         Id_sin          = 16,\r
378         Id_sqrt         = 17,\r
379         Id_tan          = 18,\r
380 \r
381         LAST_METHOD_ID  = 18,\r
382 \r
383         Id_E            = 19,\r
384         Id_PI           = 20,\r
385         Id_LN10         = 21,\r
386         Id_LN2          = 22,\r
387         Id_LOG2E        = 23,\r
388         Id_LOG10E       = 24,\r
389         Id_SQRT1_2      = 25,\r
390         Id_SQRT2        = 26,\r
391 \r
392         MAX_INSTANCE_ID = 26;\r
393 \r
394 // #/string_id_map#\r
395 \r
396     private static final double\r
397         E       = Math.E,\r
398         PI      = Math.PI,\r
399         LN10    = 2.302585092994046,\r
400         LN2     = 0.6931471805599453,\r
401         LOG2E   = 1.4426950408889634,\r
402         LOG10E  = 0.4342944819032518,\r
403         SQRT1_2 = 0.7071067811865476,\r
404         SQRT2   = 1.4142135623730951;\r
405 }\r