1 /* Digital Mars DMDScript source code.
2  * Copyright (c) 2000-2002 by Chromium Communications
3  * D version Copyright (c) 2004-2010 by Digital Mars
4  * Distributed under the Boost Software License, Version 1.0.
5  * (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  * written by Walter Bright
7  * http://www.digitalmars.com
8  *
9  * D2 port by Dmitry Olshansky 
10  *
11  * DMDScript is implemented in the D Programming Language,
12  * http://www.digitalmars.com/d/
13  *
14  * For a C++ implementation of DMDScript, including COM support, see
15  * http://www.digitalmars.com/dscript/cppscript.html
16  */
17 
18 module dmdscript.dmath;
19 
20 import std.math;
21 import std.random;
22 
23 import dmdscript.script;
24 import dmdscript.value;
25 import dmdscript.dobject;
26 import dmdscript.dnative;
27 import dmdscript.threadcontext;
28 import dmdscript.text;
29 import dmdscript.property;
30 
31 d_number math_helper(Value[] arglist, CallContext* cc)
32 {
33     Value *v;
34 
35     v = arglist.length ? &arglist[0] : &vundefined;
36     return v.toNumber(cc);
37 }
38 
39 void* Dmath_abs(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
40 {
41     // ECMA 15.8.2.1
42     d_number result;
43 
44     result = fabs(math_helper(arglist, cc));
45     ret.putVnumber(result);
46     return null;
47 }
48 
49 void* Dmath_acos(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
50 {
51     // ECMA 15.8.2.2
52     d_number result;
53 
54     result = acos(math_helper(arglist, cc));
55     ret.putVnumber(result);
56     return null;
57 }
58 
59 void* Dmath_asin(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
60 {
61     // ECMA 15.8.2.3
62     d_number result;
63 
64     result = asin(math_helper(arglist, cc));
65     ret.putVnumber(result);
66     return null;
67 }
68 
69 void* Dmath_atan(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
70 {
71     // ECMA 15.8.2.4
72     d_number result;
73 
74     result = atan(math_helper(arglist, cc));
75     ret.putVnumber(result);
76     return null;
77 }
78 
79 void* Dmath_atan2(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
80 {
81     // ECMA 15.8.2.5
82     d_number n1;
83     Value *v2;
84     d_number result;
85 
86     n1 = math_helper(arglist, cc);
87     v2 = (arglist.length >= 2) ? &arglist[1] : &vundefined;
88     result = atan2(n1, v2.toNumber(cc));
89     ret.putVnumber(result);
90     return null;
91 }
92 
93 void* Dmath_ceil(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
94 {
95     // ECMA 15.8.2.6
96     d_number result;
97 
98     result = ceil(math_helper(arglist, cc));
99     ret.putVnumber(result);
100     return null;
101 }
102 
103 void* Dmath_cos(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
104 {
105     // ECMA 15.8.2.7
106     d_number result;
107 
108     result = cos(math_helper(arglist, cc));
109     ret.putVnumber(result);
110     return null;
111 }
112 
113 void* Dmath_exp(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
114 {
115     // ECMA 15.8.2.8
116     d_number result;
117 
118     result = std.math.exp(math_helper(arglist, cc));
119     ret.putVnumber(result);
120     return null;
121 }
122 
123 void* Dmath_floor(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
124 {
125     // ECMA 15.8.2.9
126     d_number result;
127 
128     result = std.math.floor(math_helper(arglist, cc));
129     ret.putVnumber(result);
130     return null;
131 }
132 
133 void* Dmath_log(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
134 {
135     // ECMA 15.8.2.10
136     d_number result;
137 
138     result = log(math_helper(arglist, cc));
139     ret.putVnumber(result);
140     return null;
141 }
142 
143 void* Dmath_max(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
144 {
145     // ECMA v3 15.8.2.11
146     d_number n;
147     d_number result;
148     uint a;
149 
150     result = -d_number.infinity;
151     foreach(Value v; arglist)
152     {
153         n = v.toNumber(cc);
154         if(isNaN(n))
155         {
156             result = d_number.nan;
157             break;
158         }
159         if(result == n)
160         {
161             // if n is +0 and result is -0, pick n
162             if(n == 0 && !signbit(n))
163                 result = n;
164         }
165         else if(n > result)
166             result = n;
167     }
168     ret.putVnumber(result);
169     return null;
170 }
171 
172 void* Dmath_min(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
173 {
174     // ECMA v3 15.8.2.12
175     d_number n;
176     d_number result;
177     uint a;
178 
179     result = d_number.infinity;
180     foreach(Value v; arglist)
181     {
182         n = v.toNumber(cc);
183         if(isNaN(n))
184         {
185             result = d_number.nan;
186             break;
187         }
188         if(result == n)
189         {
190             // if n is -0 and result is +0, pick n
191             if(n == 0 && signbit(n))
192                 result = n;
193         }
194         else if(n < result)
195             result = n;
196     }
197     ret.putVnumber(result);
198     return null;
199 }
200 
201 void* Dmath_pow(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
202 {
203     // ECMA 15.8.2.13
204     d_number n1;
205     Value *v2;
206     d_number result;
207 
208     n1 = math_helper(arglist, cc);
209     v2 = (arglist.length >= 2) ? &arglist[1] : &vundefined;
210     result = pow(n1, v2.toNumber(cc));
211     ret.putVnumber(result);
212     return null;
213 }
214 
215 void* Dmath_random(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
216 {
217     // ECMA 15.8.2.14
218     // 0.0 <= result < 1.0
219     d_number result;
220     //+++ old random +++
221     version(none)
222     {
223         ulong x;
224 
225         // Only want 53 bits of precision
226         x = (cast(ulong)std.random.rand() << 32) + std.random.rand();
227         //PRINTF("x = x%016llx\n",x);
228         x &= 0xFFFFFFFFFFFFF800L;
229         result = x * (1 / (0x100000000L * cast(double)0x100000000L))
230                  + (1 / (0x200000000L * cast(double)0x100000000L));
231 
232         // Experiments on linux show that this will never be exactly
233         // 1.0, so is the assert() worth it?
234         assert(result >= 0 && result < 1.0);
235     }
236     //+++ patched random +++
237     result = std.random.uniform(0.0, 1.0);
238     assert(result >= 0 && result < 1.0);
239     ret.putVnumber(result);
240     return null;
241 }
242 
243 void* Dmath_round(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
244 {
245     // ECMA 15.8.2.15
246     d_number result;
247 
248     result = math_helper(arglist, cc);
249     if(!isNaN(result))
250         result = copysign(std.math.floor(result + .5), result);
251     ret.putVnumber(result);
252     return null;
253 }
254 
255 void* Dmath_sin(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
256 {
257     // ECMA 15.8.2.16
258     d_number result;
259 
260     result = sin(math_helper(arglist, cc));
261     ret.putVnumber(result);
262     return null;
263 }
264 
265 void* Dmath_sqrt(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
266 {
267     // ECMA 15.8.2.17
268     d_number result;
269 
270     result = sqrt(math_helper(arglist, cc));
271     ret.putVnumber(result);
272     return null;
273 }
274 
275 void* Dmath_tan(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
276 {
277     // ECMA 15.8.2.18
278     d_number result;
279 
280     result = tan(math_helper(arglist, cc));
281     ret.putVnumber(result);
282     return null;
283 }
284 
285 /* ===================== Dmath ==================== */
286 
287 class Dmath : Dobject
288 {
289     this(CallContext* cc)
290     {
291         super(cc, cc.tc.Dobject_prototype);
292 
293         //writef("Dmath::Dmath(%x)\n", this);
294         uint attributes = DontEnum | DontDelete | ReadOnly;
295 
296         struct MathConst
297         { d_string name;
298           d_number  value; }
299 
300         static enum MathConst[] table =
301         [
302             { TEXT_E, std.math.E },
303             { TEXT_LN10, std.math.LN10 },
304             { TEXT_LN2, std.math.LN2 },
305             { TEXT_LOG2E, std.math.LOG2E },
306             { TEXT_LOG10E, std.math.LOG10E },
307             { TEXT_PI, std.math.PI },
308             { TEXT_SQRT1_2, std.math.SQRT1_2 },
309             { TEXT_SQRT2, std.math.SQRT2 },
310         ];
311 
312         for(size_t u = 0; u < table.length; u++)
313         {
314             Value *v;
315 
316             v = Put(cc, table[u].name, table[u].value, attributes);
317             //writef("Put(%s,%.5g) = %x\n", *table[u].name, table[u].value, v);
318         }
319 
320         classname = TEXT_Math;
321 
322         static enum NativeFunctionData[] nfd =
323         [
324             { TEXT_abs, &Dmath_abs, 1 },
325             { TEXT_acos, &Dmath_acos, 1 },
326             { TEXT_asin, &Dmath_asin, 1 },
327             { TEXT_atan, &Dmath_atan, 1 },
328             { TEXT_atan2, &Dmath_atan2, 2 },
329             { TEXT_ceil, &Dmath_ceil, 1 },
330             { TEXT_cos, &Dmath_cos, 1 },
331             { TEXT_exp, &Dmath_exp, 1 },
332             { TEXT_floor, &Dmath_floor, 1 },
333             { TEXT_log, &Dmath_log, 1 },
334             { TEXT_max, &Dmath_max, 2 },
335             { TEXT_min, &Dmath_min, 2 },
336             { TEXT_pow, &Dmath_pow, 2 },
337             { TEXT_random, &Dmath_random, 0 },
338             { TEXT_round, &Dmath_round, 1 },
339             { TEXT_sin, &Dmath_sin, 1 },
340             { TEXT_sqrt, &Dmath_sqrt, 1 },
341             { TEXT_tan, &Dmath_tan, 1 },
342         ];
343 
344         DnativeFunction.initialize(this, cc, nfd, attributes);
345     }
346 
347     static void initialize(CallContext* cc)
348     {
349         cc.tc.Dmath_object = new Dmath(cc);
350     }
351 }
352