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, "[math_object] 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 }