G:/ScriptBasic/source/commands/mathops.c

Go to the documentation of this file.
00001 /*mathop.c
00002 
00003 --GNU LGPL
00004 This library is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU Lesser General Public
00006 License as published by the Free Software Foundation; either
00007 version 2.1 of the License, or (at your option) any later version.
00008 
00009 This library is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 Lesser General Public License for more details.
00013 
00014 You should have received a copy of the GNU Lesser General Public
00015 License along with this library; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018 */
00019 
00020 #include <stdlib.h>
00021 #include <stdio.h>
00022 #include <math.h>
00023 /* comparision operators compare strings as well */
00024 #include <string.h>
00025 #include <limits.h>
00026 
00027 #include "../command.h"
00028 
00029 /* stringcompare two string values. The values SHOULD be string.
00030 */
00031 static int STRCMP(pExecuteObject pEo,VARIABLE Op1, VARIABLE Op2, int iCase){
00032   unsigned long n;
00033   char *a,*b;
00034   char ca,cb;
00035 
00036   if( memory_IsUndef(Op1) && memory_IsUndef(Op2) )return 0;
00037   if( memory_IsUndef(Op1) )return 1;
00038   if( memory_IsUndef(Op2) )return -1;
00039   iCase &= 1;/* only the lowest bit is about case sensitivity */
00040   n = STRLEN(Op1);
00041   if( n > STRLEN(Op2) ) n= STRLEN(Op2);
00042   a = STRINGVALUE(Op1);
00043   b = STRINGVALUE(Op2);
00044   while( n-- ){
00045     ca = *a;
00046     cb = *b;
00047     if( iCase ){
00048       if( isupper(ca) )ca = tolower(ca);
00049       if( isupper(cb) )cb = tolower(cb);
00050       }
00051     if( ca != cb )return ( (ca)-(cb) );
00052     a++;
00053     b++;
00054     }
00055   if( STRLEN(Op1) == STRLEN(Op2) )return 0;
00056   if( STRLEN(Op1) > STRLEN(Op2) )return 1;
00057   return -1;
00058   }
00059 
00060 static long longpow(long a,long b){
00061   long result;
00062 
00063   result = 1;
00064   while( b ){
00065     if( b&1 )result *= a;
00066     b /= 2;
00067     a *= a;
00068     }
00069   return result;
00070 }
00071 
00072 static double doublepow(double a,long b){
00073   double result;
00074 
00075   result = 1.0;
00076   while( b ){
00077     if( b&1 )result *= a;
00078     b /= 2;
00079     a *= a;
00080     }
00081   return result;
00082 }
00083 
00084 #define RAISEMATHERROR "raisematherror"
00085 long *RaiseError(pExecuteObject pEo){
00086   long *plCache;
00087 
00088   plCache = (long *) PARAMPTR(CMD_DIV);
00089   if( plCache == NULL ){
00090     plCache = options_GetR(pEo,RAISEMATHERROR);
00091     if( plCache == NULL )
00092       options_Set(pEo,RAISEMATHERROR,0);
00093     plCache = options_GetR(pEo,RAISEMATHERROR);
00094     }
00095   return plCache;
00096   }
00097 
00098 /*POD
00099 =H Mathematical operators
00100 
00101 This file defines all the mathematical operators that are implemented in ScriptBasic.
00102 
00103 CUT*/
00104 
00105 /*POD
00106 =section MULT
00107 =H Multiplication
00108 
00109 This operator multiplies two numbers. If one of the arguments is double then the result is double, otherwise the result is long.
00110 
00111 If one of the operators is undefined the result is undefined.
00112 
00113 CUT*/
00114 COMMAND(MULT)
00115 #if NOTIMP_MULT
00116 NOTIMPLEMENTED;
00117 #else
00118 
00119   NODE nItem;
00120   VARIABLE Op1,Op2;
00121   double dResult;
00122   long lResult,lop1,lop2;
00123 
00124   /* this is an operator and not a command, therefore we do not have our own mortal list */
00125   USE_CALLER_MORTALS;
00126 
00127   /* evaluate the parameters */
00128   nItem = PARAMETERLIST;
00129   Op1 = EVALUATEEXPRESSION(CAR(nItem));
00130   NONULOP(Op1)
00131 
00132   nItem = CDR(nItem);
00133   Op2 = EVALUATEEXPRESSION(CAR(nItem));
00134   NONULOP(Op2)
00135 
00136   /* if any of the arguments is double then the result is double */
00137   if( ! ISINTEGER(Op1) || ! ISINTEGER(Op2) ){
00138     RETURN_DOUBLE_VALUE_OR_LONG( GETDOUBLEVALUE(Op1) * GETDOUBLEVALUE(Op2) )
00139     }
00140   lop1 = GETLONGVALUE(Op1);
00141   lop2 = GETLONGVALUE(Op2);
00142   lResult = lop1 * lop2;
00143   if( 0 == lop1 ){
00144     RETURN_LONG_VALUE( lResult );
00145     }
00146   if( lResult / lop1 == lop2 ){
00147     RETURN_LONG_VALUE( lResult );
00148     }
00149   RETURN_DOUBLE_VALUE_OR_LONG( GETDOUBLEVALUE(Op1) * GETDOUBLEVALUE(Op2) )
00150 #endif
00151 END
00152 
00153 COMMAND(EQ)
00154 #if NOTIMP_EQ
00155 NOTIMPLEMENTED;
00156 #else
00157 
00158 
00159   NODE nItem;
00160   VARIABLE Op1,Op2;
00161 
00162   /* this is an operator and not a command, therefore we do not have our own mortal list */
00163   USE_CALLER_MORTALS;
00164 
00165   /* evaluate the parameters */
00166   nItem = PARAMETERLIST;
00167   Op1 = EVALUATEEXPRESSION(CAR(nItem));
00168   NONULOPE(Op1)
00169 
00170   nItem = CDR(nItem);
00171   Op2 = EVALUATEEXPRESSION(CAR(nItem));
00172   NONULOPE(Op2)
00173 
00174   /* undef is equal to undef */
00175   if( memory_IsUndef(Op1) && memory_IsUndef(Op2) ){
00176     RETURN_LONG_VALUE(-1L);
00177     }
00178 
00179   /* undef is not equal to anything else */
00180   if( memory_IsUndef(Op1) || memory_IsUndef(Op2) ){
00181     RETURN_LONG_VALUE(0)
00182     }
00183 
00184   /* if any of the arguments is string then we compare strings */
00185   if( TYPE(Op1) == VTYPE_STRING || TYPE(Op2) == VTYPE_STRING ){
00186     Op1 = CONVERT2STRING(Op1);
00187     Op2 = CONVERT2STRING(Op2);
00188     RETURN_LONG_VALUE( STRCMP(pEo,Op1,Op2,OPTION("compare")) == 0 ? -1L : 0 )
00189     }
00190 
00191   /* if any of the arguments is double then we compare double */
00192   if( TYPE(Op1) == VTYPE_DOUBLE || TYPE(Op2) == VTYPE_DOUBLE ){
00193     RETURN_LONG_VALUE( GETDOUBLEVALUE(Op1) == GETDOUBLEVALUE(Op2) ? -1L : 0L )
00194     }
00195 
00196   RETURN_LONG_VALUE( GETLONGVALUE(Op1) == GETLONGVALUE(Op2) ? -1L : 0L )
00197 
00198 #endif
00199 END
00200 
00201 COMMAND(NE)
00202 #if NOTIMP_NE
00203 NOTIMPLEMENTED;
00204 #else
00205 
00206 
00207   NODE nItem;
00208   VARIABLE Op1,Op2;
00209 
00210   /* this is an operator and not a command, therefore we do not have our own mortal list */
00211   USE_CALLER_MORTALS;
00212 
00213   /* evaluate the parameters */
00214   nItem = PARAMETERLIST;
00215   Op1 = EVALUATEEXPRESSION(CAR(nItem));
00216   NONULOPE(Op1)
00217   nItem = CDR(nItem);
00218   Op2 = EVALUATEEXPRESSION(CAR(nItem));
00219   NONULOPE(Op2)
00220 
00221   /* undef is equal to undef */
00222   if( memory_IsUndef(Op1) && memory_IsUndef(Op2) ){
00223     RETURN_LONG_VALUE( 0 )
00224     }
00225 
00226   /* undef is not equal to anything else */
00227   if( memory_IsUndef(Op1) || memory_IsUndef(Op2) ){
00228     RETURN_LONG_VALUE( -1L )
00229     }
00230 
00231   /* if any of the arguments is string then we compare strings */
00232   if( TYPE(Op1) == VTYPE_STRING || TYPE(Op2) == VTYPE_STRING ){
00233     Op1 = CONVERT2STRING(Op1);
00234     Op2 = CONVERT2STRING(Op2);
00235     RETURN_LONG_VALUE( STRCMP(pEo,Op1,Op2,OPTION("compare")) != 0 ?  -1L : 0 )
00236     }
00237 
00238   /* if any of the arguments is double then we compare double */
00239   if( TYPE(Op1) == VTYPE_DOUBLE || TYPE(Op2) == VTYPE_DOUBLE ){
00240     RETURN_LONG_VALUE( GETDOUBLEVALUE(Op1) != GETDOUBLEVALUE(Op2) ? -1L : 0L )
00241     }
00242 
00243   RETURN_LONG_VALUE( GETLONGVALUE(Op1) != GETLONGVALUE(Op2) ? -1L : 0L )
00244 
00245 #endif
00246 END
00247 
00248 #define LOGOP(NAME,OP) \
00249 COMMAND(NAME)\
00250   NODE nItem;\
00251   VARIABLE Op1,Op2;\
00252 \
00253   /* this is an operator and not a command, therefore we do not have our own mortal list */\
00254   USE_CALLER_MORTALS;\
00255 \
00256   /* evaluate the parameters */\
00257   nItem = PARAMETERLIST;\
00258   Op1 = EVALUATEEXPRESSION(CAR(nItem));\
00259   NONULOPE(Op1)\
00260   nItem = CDR(nItem);\
00261   Op2 = EVALUATEEXPRESSION(CAR(nItem));\
00262   NONULOPE(Op2)\
00263 \
00264   /* undef is not comparable except for equality */\
00265   if( memory_IsUndef(Op1) || memory_IsUndef(Op2) ){\
00266     RETURN_LONG_VALUE( 0 )\
00267     }\
00268 \
00269   /* if any of the arguments is string then we compare strings */\
00270   if( TYPE(Op1) == VTYPE_STRING || TYPE(Op2) == VTYPE_STRING ){\
00271     Op1 = CONVERT2STRING(Op1);\
00272     Op2 = CONVERT2STRING(Op2);\
00273     RETURN_LONG_VALUE( STRCMP(pEo,Op1,Op2,OPTION("compare")) OP 0 ?  -1L : 0 )\
00274     RETURN;\
00275     }\
00276 \
00277   /* if any of the arguments is double then we compare double */\
00278   if( TYPE(Op1) == VTYPE_DOUBLE || TYPE(Op2) == VTYPE_DOUBLE ){\
00279     RETURN_LONG_VALUE( GETDOUBLEVALUE(Op1) OP GETDOUBLEVALUE(Op2) ? -1L : 0L )\
00280     }\
00281   RETURN_LONG_VALUE( GETLONGVALUE(Op1) OP GETLONGVALUE(Op2) ? -1L : 0L )\
00282 END
00283 
00284 /*POD
00285 =section compare
00286 =H Comparing operators
00287 
00288 The comparing operators compare long, double and string values. Whenever any of the
00289 arguments is string the comparisionis done stringwise. If none of the arguments are strings
00290 but one of then is double then the comparision is done between doubles. Otherwise we compare
00291 long values.
00292 
00293 The comparing operators are
00294 
00295 =itemize
00296 =item = equality operator
00297 =item <> non equality operator
00298 =item < less than
00299 =item > greather than
00300 =item <= less than or equal
00301 =item >= greather than or equal
00302 =noitemize
00303 
00304 When comparing T<undef> values the following statements should be taken into account:
00305 
00306 =itemize
00307 =item T<undef> is equal to T<undef>
00308 =item T<undef> is not equal anything else than T<undef>
00309 =item T<undef> is comparable with anything only for equality or non equality. Any other comparision
00310       having an operand T<undef> results an undefined value.
00311 =noitemize
00312 
00313 
00314 CUT*/
00315 
00316 #define NOCOMMAND(XXX) \
00317 COMMAND(XXX)\
00318 NOTIMPLEMENTED;\
00319 END
00320 
00321 #if NOTIMP_LT
00322 NOCOMMAND(LT)
00323 #else
00324 LOGOP(LT,<)
00325 #endif
00326 
00327 #if NOTIMP_LE
00328 NOCOMMAND(LE)
00329 #else
00330 LOGOP(LE,<=)
00331 #endif
00332 
00333 
00334 #if NOTIMP_GT
00335 NOCOMMAND(GT)
00336 #else
00337 LOGOP(GT,>)
00338 #endif
00339 
00340 #if NOTIMP_GE
00341 NOCOMMAND(GE)
00342 #else
00343 LOGOP(GE,>=)
00344 #endif
00345 
00346 #define LONGOP(NAME,OP) \
00347 COMMAND(NAME)\
00348   NODE nItem;\
00349   VARIABLE Op1,Op2;\
00350   USE_CALLER_MORTALS;\
00351   nItem = PARAMETERLIST;\
00352   Op1 = EVALUATEEXPRESSION(CAR(nItem));\
00353   NONULOP(Op1)\
00354   nItem = CDR(nItem);\
00355   Op2 = EVALUATEEXPRESSION(CAR(nItem));\
00356   NONULOP(Op2)\
00357   RETURN_LONG_VALUE( GETLONGVALUE(Op1) OP GETLONGVALUE(Op2) )\
00358 END
00359 
00360 /*POD
00361 =section longoperators
00362 =H Long operators
00363 
00364 These operators are defined only for long arguments, and they result long value.
00365 If any of their argument is T<undef> the result is T<undef>. The operators are
00366 
00367 =itemize
00368 =item T<and> bitwise and
00369 =item T<or> bitwise or
00370 =item T<xor> bitwise xor
00371 =noitemize
00372 
00373 Note that the logical operators can be used to evaluate logical expressions as
00374 well as bitwise expressions, because logical TRUE value is -1L which means all
00375 bits set to 1. In commands that take a logical value any nonzero value is true.
00376 
00377 CUT*/
00378 
00379 #if NOTIMP_AND
00380 NOCOMMAND(AND)
00381 #else
00382 LONGOP(AND,&)
00383 #endif
00384 
00385 #if NOTIMP_OR
00386 NOCOMMAND(OR)
00387 #else
00388 LONGOP(OR,|)
00389 #endif
00390 
00391 #if NOTIMP_XOR
00392 NOCOMMAND(XOR)
00393 #else
00394 LONGOP(XOR,^)
00395 #endif
00396 
00397 /*POD
00398 =section mod
00399 =H Modulo operators
00400 
00401 This operator calculates the modulo of two numbers.
00402 CUT*/
00403 COMMAND(MOD)
00404 #if NOTIMP_MOD
00405 NOTIMPLEMENTED;
00406 #else
00407 
00408 
00409   NODE nItem;
00410   VARIABLE Op1,Op2;
00411   long lop1,lop2;
00412 
00413   /* this is an operator and not a command, therefore we do not have our own mortal list */
00414   USE_CALLER_MORTALS;
00415 
00416   /* evaluate the parameters */
00417   nItem = PARAMETERLIST;
00418   Op1 = EVALUATEEXPRESSION(CAR(nItem));
00419   NONULOP(Op1)
00420 
00421   nItem = CDR(nItem);
00422   Op2 = EVALUATEEXPRESSION(CAR(nItem));
00423   NONULOP(Op2)
00424 
00425   lop1 = GETLONGVALUE(Op1);
00426   lop2 = GETLONGVALUE(Op2);
00427 
00428   if( lop2 == 0 ){
00429     ERRORUNDEF
00430     }
00431 
00432   RETURN_LONG_VALUE( lop1 % lop2 )
00433 
00434 #endif
00435 END
00436 
00437 /*POD
00438 =section plusminus
00439 =H unary and binary plus and minus
00440 
00441 These functions implement the unary and binary plus and minus operands.
00442 
00443 If any of the arguments is T<undef> then the result is T<undef>.
00444 
00445 If any of the arguments is double or a string evaluating to a float value
00446 then the result is double.
00447 
00448 The result is long or double, never string.
00449 
00450 CUT*/
00451 COMMAND(PLUS)
00452 #if NOTIMP_PLUS
00453 NOTIMPLEMENTED;
00454 #else
00455 
00456 
00457   NODE nItem;
00458   VARIABLE Op1,Op2;
00459   double dResult;
00460   long lResult,lop1,lop2;
00461 
00462   /* this is an operator and not a command, therefore we do not have our own mortal list */
00463   USE_CALLER_MORTALS;
00464 
00465   /* evaluate the parameters */
00466   nItem = PARAMETERLIST;
00467   Op1 = EVALUATEEXPRESSION(CAR(nItem));
00468   NONULOP(Op1)
00469 
00470   nItem = CDR(nItem);
00471   /* if there is second operand then this is binary operation*/
00472   if( nItem ){
00473     Op2 = EVALUATEEXPRESSION(CAR(nItem));
00474     NONULOP(Op2)
00475 
00476     /* if any of the arguments is double then the result is double */
00477     if( ! ISINTEGER(Op1) || !ISINTEGER(Op2) ){
00478       RETURN_DOUBLE_VALUE_OR_LONG( GETDOUBLEVALUE(Op1) + GETDOUBLEVALUE(Op2) )
00479       }
00480 
00481     lop1 = GETLONGVALUE(Op1);
00482     lop2 = GETLONGVALUE(Op2);
00483     lResult = lop1 + lop2;
00484 
00485     if( lop1 == 0 || lop2 == 0 ){
00486       RETURN_LONG_VALUE( lResult );
00487       }
00488 
00489     /* if operands have different sign then there can not be overflow */
00490     if( ( lop1 < 0 && lop2 > 0 ) || ( lop1 > 0 && lop2 < 0 ) ){
00491       RETURN_LONG_VALUE( lResult );
00492       }
00493 
00494     /* if operands are positive */
00495     if( lop1 > 0 ){
00496       if( LONG_MAX - lop1 >= lop2 ){
00497         RETURN_LONG_VALUE( lResult );
00498         }
00499       RETURN_DOUBLE_VALUE_OR_LONG( GETDOUBLEVALUE(Op1) + GETDOUBLEVALUE(Op2) )
00500       }
00501 
00502     /* if operands are negative */
00503     if( lop1 < 0 ){
00504       if( LONG_MIN - lop1 <= lop2 ){
00505         RETURN_LONG_VALUE( lResult );
00506         }
00507       RETURN_DOUBLE_VALUE_OR_LONG( GETDOUBLEVALUE(Op1) + GETDOUBLEVALUE(Op2) )
00508       }
00509     /* we should not ever get here */
00510     RETURN_DOUBLE_VALUE_OR_LONG( GETDOUBLEVALUE(Op1) + GETDOUBLEVALUE(Op2) )
00511     }
00512 
00513   /* we get here if this is unary */
00514   if( ISINTEGER(Op1) ){
00515     RETURN_LONG_VALUE( GETLONGVALUE(Op1) )
00516     }
00517   RETURN_DOUBLE_VALUE_OR_LONG( GETLONGVALUE(Op1) )
00518 
00519 #endif
00520 END
00521 
00522 COMMAND(MINUS)
00523 #if NOTIMP_MINUS
00524 NOTIMPLEMENTED;
00525 #else
00526 
00527 
00528   NODE nItem;
00529   VARIABLE Op1,Op2;
00530   double dResult;
00531   long lResult,lop1,lop2;
00532 
00533   /* this is an operator and not a command, therefore we do not have our own mortal list */
00534   USE_CALLER_MORTALS;
00535 
00536   /* evaluate the parameters */
00537   nItem = PARAMETERLIST;
00538   Op1 = EVALUATEEXPRESSION(CAR(nItem));
00539   NONULOP(Op1)
00540 
00541   nItem = CDR(nItem);
00542   if( nItem ){
00543     Op2 = EVALUATEEXPRESSION(CAR(nItem));
00544     NONULOP(Op2)
00545 
00546     /* if any of the arguments is double then the result is double */
00547     if( ! ISINTEGER(Op1) || ! ISINTEGER(Op2) ){
00548       RETURN_DOUBLE_VALUE_OR_LONG( GETDOUBLEVALUE(Op1) - GETDOUBLEVALUE(Op2) )
00549       }
00550     
00551     lop1 = GETLONGVALUE(Op1);
00552     lop2 = GETLONGVALUE(Op2);
00553     lResult = lop1 - lop2;
00554 
00555     if( lop1 == 0 || lop2 == 0 ){
00556       RETURN_LONG_VALUE( lResult );
00557       }
00558 
00559     /* if operands have the same sign then there can not be overflow */
00560     if( ( lop1 < 0 && lop2 < 0 ) || ( lop1 > 0 && lop2 > 0 ) ){
00561       RETURN_LONG_VALUE( lResult );
00562       }
00563 
00564     /* if lop1 is positive and we substract a negative number from it */
00565     if( lop1 > 0 ){
00566       if( LONG_MAX - lop1 >= -lop2 ){
00567         RETURN_LONG_VALUE( lResult );
00568         }
00569       RETURN_DOUBLE_VALUE_OR_LONG( GETDOUBLEVALUE(Op1) - GETDOUBLEVALUE(Op2) )
00570       }
00571 
00572     /* if lop1 is negative and we substract from it */
00573     if( lop1 < 0 ){
00574       if( LONG_MIN - lop1 <= -lop2 ){
00575         RETURN_LONG_VALUE( lResult );
00576         }
00577       RETURN_DOUBLE_VALUE_OR_LONG( GETDOUBLEVALUE(Op1) - GETDOUBLEVALUE(Op2) )
00578       }
00579     /* we should never get here */
00580     RETURN_DOUBLE_VALUE_OR_LONG( GETDOUBLEVALUE(Op1) - GETDOUBLEVALUE(Op2) )
00581     }
00582 
00583   /* this is unary */
00584   if( ! ISINTEGER(Op1) ){
00585     RETURN_DOUBLE_VALUE_OR_LONG( - GETDOUBLEVALUE(Op1) )
00586     }
00587   RETURN_LONG_VALUE( - GETLONGVALUE(Op1) )
00588 
00589 #endif
00590 END
00591 
00592 /*POD
00593 =section NOT
00594 =H unary NOT operator
00595 
00596 This operator takes one argument converts it to long and inverts all bits.
00597 If the argument is T<undef> the result is -1L which is the absolute TRUE value,
00598 havinbg all bits set.
00599 
00600 CUT*/
00601 COMMAND(NOT)
00602 #if NOTIMP_NOT
00603 NOTIMPLEMENTED;
00604 #else
00605 
00606 
00607   NODE nItem;
00608   VARIABLE Op1;
00609 
00610   /* this is an operator and not a command, therefore we do not have our own mortal list */
00611   USE_CALLER_MORTALS;
00612 
00613   /* evaluate the parameters */
00614   nItem = PARAMETERLIST;
00615   Op1 = EVALUATEEXPRESSION(CAR(nItem));
00616   NONULOP(Op1)
00617 
00618   RETURN_LONG_VALUE( ~ GETLONGVALUE(Op1) )
00619 
00620 #endif
00621 END
00622 
00623 /*POD
00624 =section POWER
00625 =H powering operator
00626 
00627 This is a binary operator that calculates I<x> powered to I<y>.
00628 
00629 If any of the arguments is T<undef> then the result is also T<undef>.
00630 
00631 If the exponent is negative the result is double.
00632 
00633 If any of the operators is double or is a string evaluating to a non-integer
00634 value then the result is double.
00635 
00636 Otherwise the operator makes integer operations calculating the power value.
00637 CUT*/
00638 COMMAND(POWER)
00639 #if NOTIMP_POWER
00640 NOTIMPLEMENTED;
00641 #else
00642 
00643   NODE nItem;
00644   VARIABLE vMantissa,vExponent;
00645   double dMantissa,dExponent,dRoot,dResult;
00646   long lMantissa,lExponent,lRoot;
00647   int bMantIsInt,bExpIsInt;
00648 
00649   /* this is an operator and not a command, therefore we do not have our own mortal list */
00650   USE_CALLER_MORTALS;
00651 
00652   /* evaluate the parameters */
00653   nItem = PARAMETERLIST;
00654   vMantissa = EVALUATEEXPRESSION(CAR(nItem));
00655   ASSERTOKE;
00656   if( memory_IsUndef(vMantissa) ){
00657     RESULT = NULL;
00658     RETURN;
00659     }
00660 
00661   nItem = CDR(nItem);
00662   vExponent = EVALUATEEXPRESSION(CAR(nItem));
00663   ASSERTOKE;
00664   if( memory_IsUndef(vExponent) ){
00665     RESULT = NULL;
00666     RETURN;
00667     }
00668 
00669   bMantIsInt = ISINTEGER(vMantissa);
00670   bExpIsInt  = ISINTEGER(vExponent);
00671 
00672   if( bExpIsInt ){/* if the exponent is integer */
00673 
00674     lExponent = GETLONGVALUE(vExponent);
00675     if( bMantIsInt ){
00676       /* both exponent and mantissa are integer */
00677       lMantissa = GETLONGVALUE(vMantissa);
00678       /* 0 ^ 0 is undefined, because this functional has a singularity there */
00679       if( lMantissa == 0 && lExponent == 0 ){
00680         RESULT = NULL;
00681         RETURN;
00682         }
00683       if( lExponent < 0 ){
00684         if( lMantissa == 0 ){/* the result is zero */
00685           RETURN_LONG_VALUE(0);
00686           }
00687         if( lMantissa == 1 ){/* the result is 1 */
00688           RETURN_LONG_VALUE(1);
00689           }
00690         /* The result is double because it is between one and zero excluding the boundaries. */
00691         /* the value in the denominator is zero only if lMantissa is zero, but that was already handled above */
00692         RETURN_DOUBLE_VALUE( 1.0 / (double)longpow(lMantissa,-lExponent) );
00693         }else{
00694         /* if the exponent is positive (or zero) and both mantissa and exponent are integers */
00695         RETURN_LONG_VALUE(longpow(lMantissa,lExponent));
00696         }
00697       }else{
00698       /* Exponent is integer, but the mantissa is not. */
00699       dMantissa = GETDOUBLEVALUE(vMantissa);
00700       if( lExponent < 0 ){
00701         /* The demoninator can not be zero, because doublepow is zero only if the mantissa is zero.
00702            However zero is an integer value, and the mantissa is double. What about rounding errors? */
00703         dResult = 1.0 / doublepow(dMantissa,-lExponent);
00704         /* if the result is integer amd what is more: it can be stored in an integer... */
00705         if( dResult == floor(dResult) && fabs(dResult) <= LONG_MAX ){
00706           RETURN_LONG_VALUE((long)dResult);
00707           }else{
00708           RETURN_DOUBLE_VALUE(dResult);
00709           }
00710         }else{
00711         /* if the exponent is positive (or zero) */
00712         dResult = doublepow(dMantissa,lExponent);
00713         if( dResult == floor(dResult) && fabs(dResult) <= LONG_MAX ){
00714           RETURN_LONG_VALUE((long)dResult);
00715           }else{
00716           RETURN_DOUBLE_VALUE(dResult);
00717           }
00718         }
00719       }
00720 
00721     }else{ /* not bExpIsInt ***************************************************** */
00722 
00723     /* If the exponent is not integer then we can not use any kind of integer calculation. */
00724     dMantissa = GETDOUBLEVALUE(vMantissa);
00725     dExponent = GETDOUBLEVALUE(vExponent);
00726 
00727     if( dMantissa < 0.0 ){
00728       dRoot = 1.0 / dExponent;
00729       if( dRoot == floor(dRoot) && fabs(dRoot) <= LONG_MAX ){
00730         lRoot = ((long)dRoot);
00731         if( lRoot & 1 ){
00732           dResult = -pow(-dMantissa,dExponent);
00733           if( dResult == floor(dResult) && dResult >= -LONG_MAX ){
00734             RESULT = NEWMORTALLONG;
00735             ASSERTNULL(RESULT);
00736             LONGVALUE(RESULT) = ((long)dResult);
00737             RETURN;
00738             }
00739           RESULT = NEWMORTALDOUBLE;
00740           ASSERTNULL(RESULT);
00741           DOUBLEVALUE(RESULT) = dResult;
00742           RETURN;
00743           }
00744         }
00745       /* bad luck, the result is complex */
00746       RESULT = NULL;
00747       RETURN;
00748       }else{/* dMantissa is positive and the exponent is not integer */
00749       dResult = pow(dMantissa,dExponent);
00750       if( dResult == floor(dResult) && fabs(dResult) <= LONG_MAX ){
00751         RESULT = NEWMORTALLONG;
00752         ASSERTNULL(RESULT)
00753         LONGVALUE(RESULT) = ((long)dResult);
00754         RETURN;
00755         }else{
00756         RESULT = NEWMORTALDOUBLE;
00757         ASSERTNULL(RESULT)
00758         DOUBLEVALUE(RESULT) = dResult;
00759         RETURN;
00760         }
00761       }
00762 
00763     }
00764 
00765 #endif
00766 END
00767 
00768 /*POD
00769 =section IDIV
00770 =H Integer division
00771 
00772 This operator converts the arguments to long and divides the first argument with the second.
00773 The result is a truncated long. The truncation is done towards zero like it is done by the function
00774 FIX and B<unlike> by the function INT.
00775 
00776 CUT*/
00777 COMMAND(IDIV)
00778 #if NOTIMP_IDIV
00779 NOTIMPLEMENTED;
00780 #else
00781 
00782   NODE nItem;
00783   VARIABLE Op1,Op2;
00784   double dop1,dop2;
00785   long lop1,lop2;
00786 
00787   /* this is an operator and not a command, therefore we do not have our own mortal list */
00788   USE_CALLER_MORTALS;
00789 
00790   /* evaluate the parameters */
00791   nItem = PARAMETERLIST;
00792   Op1 = EVALUATEEXPRESSION(CAR(nItem));
00793   NONULOP(Op1)
00794 
00795   nItem = CDR(nItem);
00796   Op2 = EVALUATEEXPRESSION(CAR(nItem));
00797   NONULOP(Op2)
00798 
00799   /* if any of the arguments is double then the result is double */
00800   if( !ISINTEGER(Op1) || ! ISINTEGER(Op2) ){
00801     dop1 = GETDOUBLEVALUE(Op1);
00802     dop2 = GETDOUBLEVALUE(Op2);
00803 
00804     if( dop2 == 0.0 ){
00805       ERRORUNDEF
00806       }
00807     RETURN_LONG_VALUE( ((long)(dop1 / dop2)) )
00808     }
00809 
00810   lop1 = GETLONGVALUE(Op1);
00811   lop2 = GETLONGVALUE(Op2);
00812 
00813   if( lop2  == 0 ){
00814      ERRORUNDEF
00815     }
00816 
00817   RETURN_LONG_VALUE( ((long)(lop1 / lop2)) )
00818 
00819 #endif
00820 END
00821 
00822 /*POD
00823 =section DIV
00824 =H Division
00825 
00826 This operator divides two numbers. If some of the arguments are strings then they are
00827 converted to double or long. The result is double unless both operands are long and
00828 the operation can be performed to result an integer value without truncation.
00829 CUT*/
00830 COMMAND(DIV)
00831 #if NOTIMP_DIV
00832 NOTIMPLEMENTED;
00833 #else
00834 
00835 
00836   NODE nItem;
00837   VARIABLE Op1,Op2;
00838   double dop1,dop2,dResult;
00839   long lop1,lop2;
00840 
00841   /* this is an operator and not a command, therefore we do not have our own mortal list */
00842   USE_CALLER_MORTALS;
00843 
00844   /* evaluate the parameters */
00845   nItem = PARAMETERLIST;
00846   Op1 = EVALUATEEXPRESSION(CAR(nItem));
00847   NONULOP(Op1)
00848 
00849   nItem = CDR(nItem);
00850   Op2 = EVALUATEEXPRESSION(CAR(nItem));
00851   NONULOP(Op2)
00852 
00853   /* if any of the arguments is double then the result is double */
00854   if( ! ISINTEGER(Op1) || !ISINTEGER(Op2) ){
00855     dop1 = GETDOUBLEVALUE(Op1);
00856     dop2 = GETDOUBLEVALUE(Op2);
00857     if( dop2 == 0.0 ){
00858       ERRORUNDEF
00859       }
00860     RETURN_DOUBLE_VALUE_OR_LONG( dop1 / dop2 )
00861     }
00862 
00863   lop1 = GETLONGVALUE(Op1);
00864   lop2 = GETLONGVALUE(Op2);
00865   if( lop2 == 0 ){
00866     ERRORUNDEF
00867     }
00868   if( lop1 % lop2 ){
00869     RETURN_DOUBLE_VALUE( ((double)lop1) / ((double)lop2) )
00870     }
00871   RETURN_LONG_VALUE( lop1 / lop2)
00872 
00873 #endif
00874 END
00875 
00876 /*POD
00877 =section BYVAL
00878 =H unary ByVal operator
00879 
00880 This operator does nothing. Does it? It can be used to alter pass by reference
00881 variables and help the caller to pass a variable by value. Istead of writing
00882 
00883 =verbatim
00884 call sub(a)
00885 =noverbatim
00886 
00887 it can do
00888 
00889 =verbatim
00890 call sub(ByVal a)
00891 =noverbatim
00892 
00893 and this way the subroutine can NOT alter the value of the variable T<a>.
00894 
00895 CUT*/
00896 COMMAND(BYVAL)
00897 #if NOTIMP_BYVAL
00898 NOTIMPLEMENTED;
00899 #else
00900 
00901 
00902   VARIABLE Op1;
00903 
00904   /* this is an operator and not a command, therefore we do not have our own mortal list */
00905   USE_CALLER_MORTALS;
00906 
00907   /* evaluate the parameters */
00908   Op1 = EVALUATEEXPRESSION(CAR(PARAMETERLIST));
00909   ASSERTOKE;
00910 
00911   RESULT = Op1;
00912 
00913 #endif
00914 END

Generated on Sun Mar 12 23:56:27 2006 for ScriptBasic by  doxygen 1.4.6-NO