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 }