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