File indexing completed on 2024-05-12 15:43:26
0001 /* 0002 * This file is part of the KDE libraries 0003 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Lesser General Public 0007 * License as published by the Free Software Foundation; either 0008 * version 2 of the License, or (at your option) any later version. 0009 * 0010 * This library is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 * Lesser General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU Lesser General Public 0016 * License along with this library; if not, write to the Free Software 0017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 0018 * 0019 */ 0020 0021 #include "math_object.h" 0022 #include "math_object.lut.h" 0023 #include "wtf/MathExtras.h" 0024 0025 #include "operations.h" 0026 #include <math.h> 0027 #include <time.h> 0028 0029 #ifndef M_PI 0030 #define M_PI 3.14159265358979323846 0031 #endif /* M_PI */ 0032 0033 using namespace KJS; 0034 0035 // ------------------------------ MathObjectImp -------------------------------- 0036 0037 const ClassInfo MathObjectImp::info = { "Math", nullptr, &mathTable, nullptr }; 0038 0039 /* Source for math_object.lut.h 0040 @begin mathTable 21 0041 E MathObjectImp::Euler DontEnum|DontDelete|ReadOnly 0042 LN2 MathObjectImp::Ln2 DontEnum|DontDelete|ReadOnly 0043 LN10 MathObjectImp::Ln10 DontEnum|DontDelete|ReadOnly 0044 LOG2E MathObjectImp::Log2E DontEnum|DontDelete|ReadOnly 0045 LOG10E MathObjectImp::Log10E DontEnum|DontDelete|ReadOnly 0046 PI MathObjectImp::Pi DontEnum|DontDelete|ReadOnly 0047 SQRT1_2 MathObjectImp::Sqrt1_2 DontEnum|DontDelete|ReadOnly 0048 SQRT2 MathObjectImp::Sqrt2 DontEnum|DontDelete|ReadOnly 0049 abs MathObjectImp::Abs DontEnum|Function 1 0050 acos MathObjectImp::ACos DontEnum|Function 1 0051 asin MathObjectImp::ASin DontEnum|Function 1 0052 atan MathObjectImp::ATan DontEnum|Function 1 0053 atan2 MathObjectImp::ATan2 DontEnum|Function 2 0054 ceil MathObjectImp::Ceil DontEnum|Function 1 0055 cos MathObjectImp::Cos DontEnum|Function 1 0056 exp MathObjectImp::Exp DontEnum|Function 1 0057 floor MathObjectImp::Floor DontEnum|Function 1 0058 log MathObjectImp::Log DontEnum|Function 1 0059 max MathObjectImp::Max DontEnum|Function 2 0060 min MathObjectImp::Min DontEnum|Function 2 0061 pow MathObjectImp::Pow DontEnum|Function 2 0062 random MathObjectImp::Random DontEnum|Function 0 0063 round MathObjectImp::Round DontEnum|Function 1 0064 sin MathObjectImp::Sin DontEnum|Function 1 0065 sqrt MathObjectImp::Sqrt DontEnum|Function 1 0066 tan MathObjectImp::Tan DontEnum|Function 1 0067 acosh MathObjectImp::ACosH DontEnum|Function 1 0068 acosh MathObjectImp::ASinH DontEnum|Function 1 0069 atanh MathObjectImp::ATanH DontEnum|Function 1 0070 cbrt MathObjectImp::Cbrt DontEnum|Function 1 0071 cosh MathObjectImp::CosH DontEnum|Function 1 0072 exmp1 MathObjectImp::Exmp1 DontEnum|Function 1 0073 log1p MathObjectImp::Log1p DontEnum|Function 1 0074 log10 MathObjectImp::Log10 DontEnum|Function 1 0075 log2 MathObjectImp::Log2 DontEnum|Function 1 0076 sign MathObjectImp::Sign DontEnum|Function 1 0077 sinh MathObjectImp::SinH DontEnum|Function 1 0078 tanh MathObjectImp::TanH DontEnum|Function 1 0079 trunc MathObjectImp::Trunc DontEnum|Function 1 0080 hypot MathObjectImp::Hypot DontEnum|Function 0 0081 imul MathObjectImp::Imul DontEnum|Function 2 0082 fround MathObjectImp::FRound DontEnum|Function 1 0083 clz32 MathObjectImp::Clz32 DontEnum|Function 1 0084 @end 0085 */ 0086 0087 MathObjectImp::MathObjectImp(ExecState * /*exec*/, 0088 ObjectPrototype *objProto) 0089 : JSObject(objProto) 0090 { 0091 } 0092 0093 // ECMA 15.8 0094 0095 bool MathObjectImp::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot) 0096 { 0097 return getStaticPropertySlot<MathFuncImp, MathObjectImp, JSObject>(exec, &mathTable, this, propertyName, slot); 0098 } 0099 0100 JSValue *MathObjectImp::getValueProperty(ExecState *, int token) const 0101 { 0102 switch (token) { 0103 case Euler: 0104 return jsNumber(exp(1.0)); 0105 case Ln2: 0106 return jsNumber(log(2.0)); 0107 case Ln10: 0108 return jsNumber(log(10.0)); 0109 case Log2E: 0110 return jsNumber(1.0 / log(2.0)); 0111 case Log10E: 0112 return jsNumber(1.0 / log(10.0)); 0113 case Pi: 0114 return jsNumber(piDouble); 0115 case Sqrt1_2: 0116 return jsNumber(sqrt(0.5)); 0117 case Sqrt2: 0118 return jsNumber(sqrt(2.0)); 0119 } 0120 0121 assert(0); 0122 return nullptr; 0123 } 0124 0125 // ------------------------------ MathObjectImp -------------------------------- 0126 0127 static bool randomSeeded = false; 0128 0129 MathFuncImp::MathFuncImp(ExecState *exec, int i, int l, const Identifier &name) 0130 : InternalFunctionImp(static_cast<FunctionPrototype *>(exec->lexicalInterpreter()->builtinFunctionPrototype()), name) 0131 , id(i) 0132 { 0133 putDirect(exec->propertyNames().length, l, DontDelete | ReadOnly | DontEnum); 0134 } 0135 0136 JSValue *MathFuncImp::callAsFunction(ExecState *exec, JSObject * /*thisObj*/, const List &args) 0137 { 0138 using namespace std; 0139 double arg = JSValue::toNumber(args[0], exec); 0140 double arg2 = JSValue::toNumber(args[1], exec); 0141 double result; 0142 0143 switch (id) { 0144 case MathObjectImp::Abs: 0145 result = (arg < 0 || arg == -0) ? (-arg) : arg; 0146 break; 0147 case MathObjectImp::ACos: 0148 result = ::acos(arg); 0149 break; 0150 case MathObjectImp::ASin: 0151 result = ::asin(arg); 0152 break; 0153 case MathObjectImp::ATan: 0154 result = ::atan(arg); 0155 break; 0156 case MathObjectImp::ATan2: 0157 result = ::atan2(arg, arg2); 0158 break; 0159 case MathObjectImp::Ceil: 0160 result = ::ceil(arg); 0161 break; 0162 case MathObjectImp::Cos: 0163 result = ::cos(arg); 0164 break; 0165 case MathObjectImp::Exp: 0166 result = ::exp(arg); 0167 break; 0168 case MathObjectImp::Floor: 0169 result = ::floor(arg); 0170 break; 0171 case MathObjectImp::Log: 0172 result = ::log(arg); 0173 break; 0174 case MathObjectImp::Max: { 0175 unsigned int argsCount = args.size(); 0176 result = -Inf; 0177 for (unsigned int k = 0; k < argsCount; ++k) { 0178 double val = JSValue::toNumber(args[k], exec); 0179 if (isNaN(val)) { 0180 result = NaN; 0181 break; 0182 } 0183 if (val > result || (val == 0 && result == 0 && !signbit(val))) { 0184 result = val; 0185 } 0186 } 0187 break; 0188 } 0189 case MathObjectImp::Min: { 0190 unsigned int argsCount = args.size(); 0191 result = +Inf; 0192 for (unsigned int k = 0; k < argsCount; ++k) { 0193 double val = JSValue::toNumber(args[k], exec); 0194 if (isNaN(val)) { 0195 result = NaN; 0196 break; 0197 } 0198 if (val < result || (val == 0 && result == 0 && signbit(val))) { 0199 result = val; 0200 } 0201 } 0202 break; 0203 } 0204 case MathObjectImp::Pow: 0205 // ECMA 15.8.2.1.13 (::pow takes care of most of the criteria) 0206 if (isNaN(arg2)) { 0207 result = NaN; 0208 } else if (isNaN(arg) && arg2 != 0) { 0209 result = NaN; 0210 } else if (::fabs(arg) == 1 && isInf(arg2)) { 0211 result = NaN; 0212 } else if (arg2 == 0 && arg != 0) { 0213 result = 1; 0214 } else { 0215 result = ::pow(arg, arg2); 0216 } 0217 break; 0218 case MathObjectImp::Random: 0219 if (!randomSeeded) { 0220 srand(static_cast<unsigned>(time(nullptr))); 0221 randomSeeded = true; 0222 } 0223 result = (double)rand() / RAND_MAX; 0224 break; 0225 case MathObjectImp::Round: 0226 if (signbit(arg) && arg >= -0.5) { 0227 result = -0.0; 0228 } else { 0229 result = ::floor(arg + 0.5); 0230 } 0231 break; 0232 case MathObjectImp::Sin: 0233 result = ::sin(arg); 0234 break; 0235 case MathObjectImp::Sqrt: 0236 result = ::sqrt(arg); 0237 break; 0238 case MathObjectImp::Tan: 0239 result = ::tan(arg); 0240 break; 0241 0242 //ES6 (draft 08.11.2013) 0243 case MathObjectImp::ACosH: 0244 result = ::acosh(arg); 0245 break; 0246 case MathObjectImp::ASinH: 0247 result = ::asinh(arg); 0248 break; 0249 case MathObjectImp::ATanH: 0250 result = ::atanh(arg); 0251 break; 0252 case MathObjectImp::Cbrt: 0253 result = ::cbrt(arg); 0254 break; 0255 case MathObjectImp::CosH: 0256 result = ::cosh(arg); 0257 break; 0258 case MathObjectImp::Exmp1: 0259 result = ::expm1(arg); 0260 break; 0261 case MathObjectImp::Log1p: 0262 result = ::log1p(arg); 0263 break; 0264 case MathObjectImp::Log10: 0265 result = ::log10(arg); 0266 break; 0267 case MathObjectImp::Log2: 0268 result = ::log2(arg); 0269 break; 0270 case MathObjectImp::Sign: 0271 if (isNaN(arg)) 0272 { 0273 result = KJS::NaN; 0274 } 0275 else if (signbit(arg)) 0276 { 0277 if (arg == 0) 0278 result = -0.0; 0279 else 0280 result = -1.0; 0281 } 0282 else 0283 { 0284 if (arg == 0) 0285 result = 0.0; 0286 else 0287 result = 1.0; 0288 } 0289 break; 0290 case MathObjectImp::SinH: 0291 result = ::sinh(arg); 0292 break; 0293 case MathObjectImp::TanH: 0294 result = ::tanh(arg); 0295 break; 0296 case MathObjectImp::Trunc: 0297 result = ::trunc(arg); 0298 break; 0299 case MathObjectImp::Hypot: 0300 { 0301 if (args.size() == 0) 0302 { 0303 result = 0; 0304 break; 0305 } 0306 0307 double sum = 0.0; 0308 bool foundNaN = false; 0309 for (int i = 0; i < args.size(); ++i) 0310 { 0311 double num = JSValue::toNumber(args[i], exec); 0312 if (isInf(num)) 0313 return jsNumber(KJS::Inf); 0314 if (foundNaN) 0315 continue; 0316 if (isNaN(num)) 0317 { 0318 foundNaN = true; 0319 continue; 0320 } 0321 0322 sum += ::pow(num, 2); 0323 } 0324 0325 if (foundNaN) 0326 return jsNumber(KJS::NaN); 0327 0328 result = ::sqrt(sum); 0329 break; 0330 } 0331 case MathObjectImp::Imul: 0332 { 0333 if (args.size() < 2) 0334 return jsUndefined(); 0335 int32_t a = JSValue::toInt32(args[0], exec); 0336 if (exec->hadException()) 0337 return jsNumber(a); 0338 int32_t b = JSValue::toInt32(args[1], exec); 0339 if (exec->hadException()) 0340 return jsNumber(b); 0341 0342 result = a * b; 0343 break; 0344 } 0345 case MathObjectImp::FRound: 0346 if (isNaN(arg) || isInf(arg)) 0347 return jsNumber(arg); 0348 0349 result = static_cast<double>(static_cast<float>(arg)); 0350 break; 0351 case MathObjectImp::Clz32: 0352 { 0353 uint32_t n = JSValue::toUInt32(args[0], exec); 0354 if (exec->hadException()) 0355 return jsUndefined(); 0356 return jsNumber(clz32(n)); 0357 } 0358 default: 0359 result = 0.0; 0360 assert(0); 0361 } 0362 0363 return jsNumber(result); 0364 }