math_object.cpp

00001 // -*- c-basic-offset: 2 -*-
00002 /*
00003  *  This file is part of the KDE libraries
00004  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Lesser General Public
00008  *  License as published by the Free Software Foundation; either
00009  *  version 2 of the License, or (at your option) any later version.
00010  *
00011  *  This library is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  *  Lesser General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU Lesser General Public
00017  *  License along with this library; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00019  *
00020  */
00021 
00022 #include <math.h>
00023 #include <stdlib.h>
00024 #include <stdio.h>
00025 #include <assert.h>
00026 #include <time.h>
00027 
00028 #include "value.h"
00029 #include "object.h"
00030 #include "types.h"
00031 #include "interpreter.h"
00032 #include "operations.h"
00033 #include "math_object.h"
00034 
00035 #include "math_object.lut.h"
00036 
00037 #ifndef M_PI
00038 #define M_PI 3.14159265358979323846
00039 #endif  /*  M_PI  */
00040 
00041 #ifndef signbit
00042 #define signbit(x) ((x) < 0.0 || IS_NEGATIVE_ZERO(x))
00043 #endif
00044 
00045 using namespace KJS;
00046 
00047 // ------------------------------ MathObjectImp --------------------------------
00048 
00049 const ClassInfo MathObjectImp::info = { "Math", 0, &mathTable, 0 };
00050 
00051 /* Source for math_object.lut.h
00052 @begin mathTable 31
00053   E             MathObjectImp::Euler    DontEnum|DontDelete|ReadOnly
00054   LN2           MathObjectImp::Ln2      DontEnum|DontDelete|ReadOnly
00055   LN10          MathObjectImp::Ln10     DontEnum|DontDelete|ReadOnly
00056   LOG2E         MathObjectImp::Log2E    DontEnum|DontDelete|ReadOnly
00057   LOG10E        MathObjectImp::Log10E   DontEnum|DontDelete|ReadOnly
00058   PI            MathObjectImp::Pi       DontEnum|DontDelete|ReadOnly
00059   SQRT1_2       MathObjectImp::Sqrt1_2  DontEnum|DontDelete|ReadOnly
00060   SQRT2         MathObjectImp::Sqrt2    DontEnum|DontDelete|ReadOnly
00061   abs           MathObjectImp::Abs      DontEnum|Function 1
00062   acos          MathObjectImp::ACos     DontEnum|Function 1
00063   asin          MathObjectImp::ASin     DontEnum|Function 1
00064   atan          MathObjectImp::ATan     DontEnum|Function 1
00065   atan2         MathObjectImp::ATan2    DontEnum|Function 2
00066   ceil          MathObjectImp::Ceil     DontEnum|Function 1
00067   cos           MathObjectImp::Cos      DontEnum|Function 1
00068   exp           MathObjectImp::Exp      DontEnum|Function 1
00069   floor         MathObjectImp::Floor    DontEnum|Function 1
00070   log           MathObjectImp::Log      DontEnum|Function 1
00071   max           MathObjectImp::Max      DontEnum|Function 2
00072   min           MathObjectImp::Min      DontEnum|Function 2
00073   pow           MathObjectImp::Pow      DontEnum|Function 2
00074   random        MathObjectImp::Random   DontEnum|Function 0
00075   round         MathObjectImp::Round    DontEnum|Function 1
00076   sin           MathObjectImp::Sin      DontEnum|Function 1
00077   sqrt          MathObjectImp::Sqrt     DontEnum|Function 1
00078   tan           MathObjectImp::Tan      DontEnum|Function 1
00079 @end
00080 */
00081 
00082 MathObjectImp::MathObjectImp(ExecState * /*exec*/,
00083                              ObjectPrototypeImp *objProto)
00084   : ObjectImp(objProto)
00085 {
00086    unsigned int seed = time(NULL);
00087    ::srand(seed);
00088 }
00089 
00090 // ECMA 15.8
00091 Value MathObjectImp::get(ExecState *exec, const Identifier &propertyName) const
00092 {
00093   return lookupGet<MathFuncImp, MathObjectImp, ObjectImp>( exec, propertyName, &mathTable, this );
00094 }
00095 
00096 Value MathObjectImp::getValueProperty(ExecState *, int token) const
00097 {
00098   double d = -42; // ;)
00099   switch (token) {
00100   case Euler:
00101     d = exp(1.0);
00102     break;
00103   case Ln2:
00104     d = log(2.0);
00105     break;
00106   case Ln10:
00107     d = log(10.0);
00108     break;
00109   case Log2E:
00110     d = 1.0/log(2.0);
00111     break;
00112   case Log10E:
00113     d = 1.0/log(10.0);
00114     break;
00115   case Pi:
00116     d = M_PI;
00117     break;
00118   case Sqrt1_2:
00119     d = sqrt(0.5);
00120     break;
00121   case Sqrt2:
00122     d = sqrt(2.0);
00123     break;
00124   default:
00125     fprintf( stderr, "Internal error in MathObjectImp: unhandled token %d\n", token );
00126     break;
00127   }
00128 
00129   return Number(d);
00130 }
00131 
00132 // ------------------------------ MathObjectImp --------------------------------
00133 
00134 MathFuncImp::MathFuncImp(ExecState *exec, int i, int l)
00135   : InternalFunctionImp(
00136     static_cast<FunctionPrototypeImp*>(exec->lexicalInterpreter()->builtinFunctionPrototype().imp())
00137     ), id(i)
00138 {
00139   Value protect(this);
00140   putDirect(lengthPropertyName, l, DontDelete|ReadOnly|DontEnum);
00141 }
00142 
00143 bool MathFuncImp::implementsCall() const
00144 {
00145   return true;
00146 }
00147 
00148 Value MathFuncImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
00149 {
00150   double arg = args[0].toNumber(exec);
00151   double arg2 = args[1].toNumber(exec);
00152   double result;
00153 
00154   switch (id) {
00155   case MathObjectImp::Abs:
00156     result = ( arg < 0 || arg == -0) ? (-arg) : arg;
00157     break;
00158   case MathObjectImp::ACos:
00159     result = ::acos(arg);
00160     break;
00161   case MathObjectImp::ASin:
00162     result = ::asin(arg);
00163     break;
00164   case MathObjectImp::ATan:
00165     result = ::atan(arg);
00166     break;
00167   case MathObjectImp::ATan2:
00168     result = ::atan2(arg, arg2);
00169     break;
00170   case MathObjectImp::Ceil:
00171     result = ::ceil(arg);
00172     break;
00173   case MathObjectImp::Cos:
00174     result = ::cos(arg);
00175     break;
00176   case MathObjectImp::Exp:
00177     result = ::exp(arg);
00178     break;
00179   case MathObjectImp::Floor:
00180     result = ::floor(arg);
00181     break;
00182   case MathObjectImp::Log:
00183     result = ::log(arg);
00184     break;
00185   case MathObjectImp::Max: {
00186     unsigned int argsCount = args.size();
00187     result = -Inf;
00188     for ( unsigned int k = 0 ; k < argsCount ; ++k ) {
00189       double val = args[k].toNumber(exec);
00190       if ( isNaN( val ) )
00191       {
00192         result = NaN;
00193         break;
00194       }
00195       if ( val > result || (val == 0 && result == 0 && !signbit(val)) )
00196         result = val;
00197     }
00198     break;
00199   }
00200   case MathObjectImp::Min: {
00201     unsigned int argsCount = args.size();
00202     result = +Inf;
00203     for ( unsigned int k = 0 ; k < argsCount ; ++k ) {
00204       double val = args[k].toNumber(exec);
00205       if ( isNaN( val ) )
00206       {
00207         result = NaN;
00208         break;
00209       }
00210       if ( val < result || (val == 0 && result == 0 && signbit(val)) )
00211         result = val;
00212     }
00213     break;
00214   }
00215   case MathObjectImp::Pow:
00216     // ECMA 15.8.2.1.13 (::pow takes care of most of the critera)
00217     if (KJS::isNaN(arg2))
00218       result = NaN;
00219 #ifndef APPLE_CHANGES
00220     else if (arg2 == 0)
00221       result = 1;
00222 #endif
00223     else if (KJS::isNaN(arg) && arg2 != 0)
00224       result = NaN;
00225 #ifndef APPLE_CHANGES
00226     else if (::fabs(arg) > 1 && KJS::isPosInf(arg2))
00227       result = Inf;
00228     else if (::fabs(arg) > 1 && KJS::isNegInf(arg2))
00229       result = +0;
00230 #endif
00231     else if (::fabs(arg) == 1 && KJS::isInf(arg2))
00232       result = NaN;
00233 #ifndef APPLE_CHANGES
00234     else if (::fabs(arg) < 1 && KJS::isPosInf(arg2))
00235       result = +0;
00236     else if (::fabs(arg) < 1 && KJS::isNegInf(arg2))
00237       result = Inf;
00238 #endif
00239     else
00240       result = ::pow(arg, arg2);
00241     break;
00242   case MathObjectImp::Random:
00243     result = ::rand();
00244     result = result / RAND_MAX;
00245     break;
00246   case MathObjectImp::Round:
00247     if (signbit(arg) && arg >= -0.5)
00248         result = -0.0;
00249     else
00250         result = ::floor(arg + 0.5);
00251     break;
00252   case MathObjectImp::Sin:
00253     result = ::sin(arg);
00254     break;
00255   case MathObjectImp::Sqrt:
00256     result = ::sqrt(arg);
00257     break;
00258   case MathObjectImp::Tan:
00259     result = ::tan(arg);
00260     break;
00261 
00262   default:
00263     result = 0.0;
00264     assert(0);
00265   }
00266 
00267   return Number(result);
00268 }
KDE Home | KDE Accessibility Home | Description of Access Keys