mux/src/funmath.cpp

Go to the documentation of this file.
00001 // funmath.cpp -- MUX math function handlers.
00002 //
00003 // $Id: funmath.cpp,v 1.8 2007/04/07 17:19:30 sdennis Exp $
00004 //
00005 // MUX 2.4
00006 // Copyright (C) 1998 through 2005 Solid Vertical Domains, Ltd. All
00007 // rights not explicitly given are reserved.
00008 //
00009 #include "copyright.h"
00010 #include "autoconf.h"
00011 #include "config.h"
00012 #include "externs.h"
00013 
00014 #include <float.h>
00015 #include <limits.h>
00016 #include <math.h>
00017 
00018 #include "functions.h"
00019 #include "funmath.h"
00020 #include "sha1.h"
00021 
00022 #ifdef HAVE_IEEE_FP_FORMAT
00023 
00024 static const char *mux_FPStrings[] = { "+Inf", "-Inf", "Ind", "NaN", "0", "0", "0", "0" };
00025 
00026 #define MUX_FPGROUP_PASS  0x00 // Pass-through to printf
00027 #define MUX_FPGROUP_ZERO  0x10 // Force to be zero.
00028 #define MUX_FPGROUP_PINF  0x20 // "+Inf"
00029 #define MUX_FPGROUP_NINF  0x30 // "-Inf"
00030 #define MUX_FPGROUP_IND   0x40 // "Ind"
00031 #define MUX_FPGROUP_NAN   0x50 // "NaN"
00032 #define MUX_FPGROUP(x) ((x) & 0xF0)
00033 
00034 // mux_fpclass returns an integer that is one of the following:
00035 //
00036 #define MUX_FPCLASS_PINF  (MUX_FPGROUP_PINF|0) // Positive infinity (+INF)
00037 #define MUX_FPCLASS_NINF  (MUX_FPGROUP_NINF|1) // Negative infinity (-INF)
00038 #define MUX_FPCLASS_QNAN  (MUX_FPGROUP_IND |2) // Quiet NAN (Indefinite)
00039 #define MUX_FPCLASS_SNAN  (MUX_FPGROUP_NAN |3) // Signaling NAN
00040 #define MUX_FPCLASS_ND    (MUX_FPGROUP_ZERO|4) // Negative denormalized
00041 #define MUX_FPCLASS_NZ    (MUX_FPGROUP_ZERO|5) // Negative zero (-0)
00042 #define MUX_FPCLASS_PZ    (MUX_FPGROUP_ZERO|6) // Positive zero (+0)
00043 #define MUX_FPCLASS_PD    (MUX_FPGROUP_ZERO|7) // Positive denormalized
00044 #define MUX_FPCLASS_PN    (MUX_FPGROUP_PASS|8) // Positive normalized non-zero
00045 #define MUX_FPCLASS_NN    (MUX_FPGROUP_PASS|9) // Negative normalized non-zero
00046 #define MUX_FPCLASS(x)    ((x) & 0x0F)
00047 
00048 #ifdef WIN32
00049 #define IEEE_MASK_SIGN     0x8000000000000000ui64
00050 #define IEEE_MASK_EXPONENT 0x7FF0000000000000ui64
00051 #define IEEE_MASK_MANTISSA 0x000FFFFFFFFFFFFFui64
00052 #define IEEE_MASK_QNAN     0x0008000000000000ui64
00053 #else
00054 #define IEEE_MASK_SIGN     0x8000000000000000ull
00055 #define IEEE_MASK_EXPONENT 0x7FF0000000000000ull
00056 #define IEEE_MASK_MANTISSA 0x000FFFFFFFFFFFFFull
00057 #define IEEE_MASK_QNAN     0x0008000000000000ull
00058 #endif
00059 
00060 #define ARBITRARY_NUMBER 1
00061 #define IEEE_MAKE_TABLESIZE 5
00062 typedef union
00063 {
00064     INT64  i64;
00065     double d;
00066 } SpecialFloatUnion;
00067 
00068 // We return a Quiet NAN when a Signalling NAN is requested because
00069 // any operation on a Signalling NAN will result in a Quiet NAN anyway.
00070 // MUX doesn't catch SIGFPE, but if it did, a Signalling NAN would
00071 // generate a SIGFPE.
00072 //
00073 static SpecialFloatUnion SpecialFloatTable[IEEE_MAKE_TABLESIZE] =
00074 {
00075     { 0 }, // Unused.
00076     { IEEE_MASK_EXPONENT | IEEE_MASK_QNAN | ARBITRARY_NUMBER },
00077     { IEEE_MASK_EXPONENT | IEEE_MASK_QNAN | ARBITRARY_NUMBER },
00078     { IEEE_MASK_EXPONENT },
00079     { IEEE_MASK_EXPONENT | IEEE_MASK_SIGN }
00080 };
00081 
00082 double MakeSpecialFloat(int iWhich)
00083 {
00084     return SpecialFloatTable[iWhich].d;
00085 }
00086 
00087 static int mux_fpclass(double result)
00088 {
00089     union
00090     {
00091         UINT64 i64;
00092         double d;
00093     } u;
00094 
00095     u.d = result;
00096   
00097     if ((u.i64 & IEEE_MASK_EXPONENT) == 0)
00098     {
00099         if (u.i64 & IEEE_MASK_MANTISSA)
00100         {
00101             if (u.i64 & IEEE_MASK_SIGN) return MUX_FPCLASS_ND;
00102             else                        return MUX_FPCLASS_PD;
00103         }
00104         else
00105         {
00106             if (u.i64 & IEEE_MASK_SIGN) return MUX_FPCLASS_NZ;
00107             else                        return MUX_FPCLASS_PZ;
00108         }
00109     }
00110     else if ((u.i64 & IEEE_MASK_EXPONENT) == IEEE_MASK_EXPONENT)
00111     {
00112         if (u.i64 & IEEE_MASK_MANTISSA)
00113         {
00114             if (u.i64 & IEEE_MASK_QNAN) return MUX_FPCLASS_QNAN;
00115             else                        return MUX_FPCLASS_SNAN;
00116         }
00117         else
00118         {
00119             if (u.i64 & IEEE_MASK_SIGN) return MUX_FPCLASS_NINF;
00120             else                        return MUX_FPCLASS_PINF;
00121         }
00122     }
00123     else
00124     {
00125         if (u.i64 & IEEE_MASK_SIGN)     return MUX_FPCLASS_NN;
00126         else                            return MUX_FPCLASS_PN;
00127     }
00128 }
00129 #endif // HAVE_IEEE_FP_FORMAT
00130 
00131 static double AddWithError(double& err, double a, double b)
00132 {
00133     double sum = a+b;
00134     err = b-(sum-a);
00135     return sum;
00136 }
00137 
00138 // Typically, we are within 1ulp of an exact answer, find the shortest answer
00139 // within that 1 ulp (that is, within 0, +ulp, and -ulp).
00140 //
00141 static double NearestPretty(double R)
00142 {
00143     char *rve = NULL;
00144     int decpt;
00145     int bNegative;
00146     const int mode = 0;
00147 
00148     double ulpR = ulp(R);
00149     double R0 = R-ulpR;
00150     double R1 = R+ulpR;
00151 
00152     // R.
00153     //
00154     char *p = mux_dtoa(R, mode, 50, &decpt, &bNegative, &rve);
00155     int nDigits = rve - p;
00156 
00157     // R-ulp(R)
00158     //
00159     p = mux_dtoa(R0, mode, 50, &decpt, &bNegative, &rve);
00160     if (rve - p < nDigits)
00161     {
00162         nDigits = rve - p;
00163         R  = R0;
00164     }
00165 
00166     // R+ulp(R)
00167     //
00168     p = mux_dtoa(R1, mode, 50, &decpt, &bNegative, &rve);
00169     if (rve - p < nDigits)
00170     {
00171         nDigits = rve - p;
00172         R = R1;
00173     }
00174     return R;
00175 }
00176 
00177 // Compare for decreasing order by absolute value.
00178 //
00179 static int DCL_CDECL f_comp_abs(const void *s1, const void *s2)
00180 {
00181     double a = fabs(*(double *)s1);
00182     double b = fabs(*(double *)s2);
00183 
00184     if (a > b)
00185     {
00186         return -1;
00187     }
00188     else if (a < b)
00189     {
00190         return 1;
00191     }
00192     return 0;
00193 }
00194 
00195 // Double compensation method. Extended by Priest from Knuth and Kahan.
00196 //
00197 // Error of sum is less than 2*epsilon or 1 ulp except for very large n.
00198 // Return the result that yields the shortest number of base-10 digits.
00199 //
00200 static double AddDoubles(int n, double pd[])
00201 {
00202     qsort(pd, n, sizeof(double), f_comp_abs);
00203     double sum = 0.0;
00204     if (0 < n)
00205     {
00206         sum = pd[0];
00207         double sum_err = 0.0;
00208         int i;
00209         for (i = 1; i < n; i++)
00210         {
00211             double addend_err;
00212             double addend = AddWithError(addend_err, sum_err, pd[i]);
00213             double sum1_err;
00214             double sum1 = AddWithError(sum1_err, sum, addend);
00215             sum = AddWithError(sum_err, sum1, addend_err + sum1_err);
00216         }
00217     }
00218     return NearestPretty(sum);
00219 }
00220 
00221 /* ---------------------------------------------------------------------------
00222  * fval: copy the floating point value into a buffer and make it presentable
00223  */
00224 static void fval(char *buff, char **bufc, double result)
00225 {
00226     // Get double val into buffer.
00227     //
00228 #ifdef HAVE_IEEE_FP_FORMAT
00229     int fpc = mux_fpclass(result);
00230     if (MUX_FPGROUP(fpc) == MUX_FPGROUP_PASS)
00231     {
00232 #endif // HAVE_IEEE_FP_FORMAT
00233         double rIntegerPart;
00234         double rFractionalPart = modf(result, &rIntegerPart);
00235         if (  0.0 == rFractionalPart
00236            && LONG_MIN <= rIntegerPart
00237            && rIntegerPart <= LONG_MAX)
00238         {
00239             long i = (long)rIntegerPart;
00240             safe_ltoa(i, buff, bufc);
00241         }
00242         else
00243         {
00244             safe_str(mux_ftoa(result, false, 0), buff, bufc);
00245         }
00246 #ifdef HAVE_IEEE_FP_FORMAT
00247     }
00248     else
00249     {
00250         safe_str(mux_FPStrings[MUX_FPCLASS(fpc)], buff, bufc);
00251     }
00252 #endif // HAVE_IEEE_FP_FORMAT
00253 }
00254 
00255 static const long nMaximums[10] =
00256 {
00257     0, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999
00258 };
00259 
00260 static double g_aDoubles[LBUF_SIZE];
00261 int const g_nDoubles = sizeof(g_aDoubles)/sizeof(double);
00262 
00263 FUNCTION(fun_add)
00264 {
00265     UNUSED_PARAMETER(executor);
00266     UNUSED_PARAMETER(caller);
00267     UNUSED_PARAMETER(enactor);
00268     UNUSED_PARAMETER(cargs);
00269     UNUSED_PARAMETER(ncargs);
00270 
00271     int nArgs = nfargs;
00272     if (g_nDoubles < nArgs)
00273     {
00274         nArgs = g_nDoubles;
00275     }
00276 
00277     int i;
00278     for (i = 0; i < nArgs; i++)
00279     {
00280         int nDigits;
00281         long nMaxValue = 0;
00282         if (  !is_integer(fargs[i], &nDigits)
00283            || nDigits > 9
00284            || (nMaxValue += nMaximums[nDigits]) > 999999999L)
00285         {
00286             // Do it the slow way.
00287             //
00288             for (int j = 0; j < nArgs; j++)
00289             {
00290                 g_aDoubles[j] = mux_atof(fargs[j]);
00291             }
00292 
00293             fval(buff, bufc, AddDoubles(nArgs, g_aDoubles));
00294             return;
00295         }
00296     }
00297 
00298     // We can do it the fast way.
00299     //
00300     long sum = 0;
00301     for (i = 0; i < nArgs; i++)
00302     {
00303         sum += mux_atol(fargs[i]);
00304     }
00305     safe_ltoa(sum, buff, bufc);
00306 }
00307 
00308 FUNCTION(fun_ladd)
00309 {
00310     UNUSED_PARAMETER(executor);
00311     UNUSED_PARAMETER(caller);
00312     UNUSED_PARAMETER(enactor);
00313     UNUSED_PARAMETER(cargs);
00314     UNUSED_PARAMETER(ncargs);
00315 
00316     int n = 0;
00317     if (0 < nfargs)
00318     {
00319         SEP sep;
00320         if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT|DELIM_STRING))
00321         {
00322             return;
00323         }
00324 
00325         char *cp = trim_space_sep(fargs[0], &sep);
00326         while (  cp
00327               && n < g_nDoubles)
00328         {
00329             char *curr = split_token(&cp, &sep);
00330             g_aDoubles[n++] = mux_atof(curr);
00331         }
00332     }
00333     fval(buff, bufc, AddDoubles(n, g_aDoubles));
00334 }
00335 
00337 // Function : iadd(Arg[0], Arg[1],..,Arg[n])
00338 //
00339 // Written by : Chris Rouse (Seraphim) 04/04/2000
00341 
00342 FUNCTION(fun_iadd)
00343 {
00344     UNUSED_PARAMETER(executor);
00345     UNUSED_PARAMETER(caller);
00346     UNUSED_PARAMETER(enactor);
00347     UNUSED_PARAMETER(cargs);
00348     UNUSED_PARAMETER(ncargs);
00349 
00350     INT64 sum = 0;
00351     for (int i = 0; i < nfargs; i++)
00352     {
00353         sum += mux_atoi64(fargs[i]);
00354     }
00355     safe_i64toa(sum, buff, bufc);
00356 }
00357 
00358 FUNCTION(fun_sub)
00359 {
00360     UNUSED_PARAMETER(executor);
00361     UNUSED_PARAMETER(caller);
00362     UNUSED_PARAMETER(enactor);
00363     UNUSED_PARAMETER(nfargs);
00364     UNUSED_PARAMETER(cargs);
00365     UNUSED_PARAMETER(ncargs);
00366 
00367     int nDigits;
00368     if (  is_integer(fargs[0], &nDigits)
00369        && nDigits <= 9
00370        && is_integer(fargs[1], &nDigits)
00371        && nDigits <= 9)
00372     {
00373         int iResult;
00374         iResult = mux_atol(fargs[0]) - mux_atol(fargs[1]);
00375         safe_ltoa(iResult, buff, bufc);
00376     }
00377     else
00378     {
00379         g_aDoubles[0] = mux_atof(fargs[0]);
00380         g_aDoubles[1] = -mux_atof(fargs[1]);
00381         fval(buff, bufc, AddDoubles(2, g_aDoubles));
00382     }
00383 }
00384 
00386 // Function : isub(Arg[0], Arg[1])
00387 //
00388 // Written by : Chris Rouse (Seraphim) 04/04/2000
00390 
00391 FUNCTION(fun_isub)
00392 {
00393     UNUSED_PARAMETER(executor);
00394     UNUSED_PARAMETER(caller);
00395     UNUSED_PARAMETER(enactor);
00396     UNUSED_PARAMETER(nfargs);
00397     UNUSED_PARAMETER(cargs);
00398     UNUSED_PARAMETER(ncargs);
00399 
00400     INT64 diff = mux_atoi64(fargs[0]) - mux_atoi64(fargs[1]);
00401     safe_i64toa(diff, buff, bufc);
00402 }
00403 
00404 FUNCTION(fun_mul)
00405 {
00406     UNUSED_PARAMETER(executor);
00407     UNUSED_PARAMETER(caller);
00408     UNUSED_PARAMETER(enactor);
00409     UNUSED_PARAMETER(cargs);
00410     UNUSED_PARAMETER(ncargs);
00411 
00412     double prod = 1.0;
00413     for (int i = 0; i < nfargs; i++)
00414     {
00415         prod *= mux_atof(fargs[i]);
00416     }
00417     fval(buff, bufc, NearestPretty(prod));
00418 }
00419 
00421 // Function : imul(Arg[0], Arg[1], ... , Arg[n])
00422 //
00423 // Written by : Chris Rouse (Seraphim) 04/04/2000
00425 
00426 FUNCTION(fun_imul)
00427 {
00428     UNUSED_PARAMETER(executor);
00429     UNUSED_PARAMETER(caller);
00430     UNUSED_PARAMETER(enactor);
00431     UNUSED_PARAMETER(cargs);
00432     UNUSED_PARAMETER(ncargs);
00433 
00434     INT64 prod = 1;
00435     for (int i = 0; i < nfargs; i++)
00436     {
00437         prod *= mux_atoi64(fargs[i]);
00438     }
00439     safe_i64toa(prod, buff, bufc);
00440 }
00441 
00442 FUNCTION(fun_gt)
00443 {
00444     UNUSED_PARAMETER(executor);
00445     UNUSED_PARAMETER(caller);
00446     UNUSED_PARAMETER(enactor);
00447     UNUSED_PARAMETER(nfargs);
00448     UNUSED_PARAMETER(cargs);
00449     UNUSED_PARAMETER(ncargs);
00450 
00451     bool bResult = false;
00452     int nDigits;
00453     if (  is_integer(fargs[0], &nDigits)
00454        && nDigits <= 9
00455        && is_integer(fargs[1], &nDigits)
00456        && nDigits <= 9)
00457     {
00458         bResult = (mux_atol(fargs[0]) > mux_atol(fargs[1]));
00459     }
00460     else
00461     {
00462         bResult = (mux_atof(fargs[0]) > mux_atof(fargs[1]));
00463     }
00464     safe_bool(bResult, buff, bufc);
00465 }
00466 
00467 FUNCTION(fun_gte)
00468 {
00469     UNUSED_PARAMETER(executor);
00470     UNUSED_PARAMETER(caller);
00471     UNUSED_PARAMETER(enactor);
00472     UNUSED_PARAMETER(nfargs);
00473     UNUSED_PARAMETER(cargs);
00474     UNUSED_PARAMETER(ncargs);
00475 
00476     bool bResult = false;
00477     int nDigits;
00478     if (  is_integer(fargs[0], &nDigits)
00479        && nDigits <= 9
00480        && is_integer(fargs[1], &nDigits)
00481        && nDigits <= 9)
00482     {
00483         bResult = (mux_atol(fargs[0]) >= mux_atol(fargs[1]));
00484     }
00485     else
00486     {
00487         bResult = (mux_atof(fargs[0]) >= mux_atof(fargs[1]));
00488     }
00489     safe_bool(bResult, buff, bufc);
00490 }
00491 
00492 FUNCTION(fun_lt)
00493 {
00494     UNUSED_PARAMETER(executor);
00495     UNUSED_PARAMETER(caller);
00496     UNUSED_PARAMETER(enactor);
00497     UNUSED_PARAMETER(nfargs);
00498     UNUSED_PARAMETER(cargs);
00499     UNUSED_PARAMETER(ncargs);
00500 
00501     bool bResult = false;
00502     int nDigits;
00503     if (  is_integer(fargs[0], &nDigits)
00504        && nDigits <= 9
00505        && is_integer(fargs[1], &nDigits)
00506        && nDigits <= 9)
00507     {
00508         bResult = (mux_atol(fargs[0]) < mux_atol(fargs[1]));
00509     }
00510     else
00511     {
00512         bResult = (mux_atof(fargs[0]) < mux_atof(fargs[1]));
00513     }
00514     safe_bool(bResult, buff, bufc);
00515 }
00516 
00517 FUNCTION(fun_lte)
00518 {
00519     UNUSED_PARAMETER(executor);
00520     UNUSED_PARAMETER(caller);
00521     UNUSED_PARAMETER(enactor);
00522     UNUSED_PARAMETER(nfargs);
00523     UNUSED_PARAMETER(cargs);
00524     UNUSED_PARAMETER(ncargs);
00525 
00526     bool bResult = false;
00527     int nDigits;
00528     if (  is_integer(fargs[0], &nDigits)
00529        && nDigits <= 9
00530        && is_integer(fargs[1], &nDigits)
00531        && nDigits <= 9)
00532     {
00533         bResult = (mux_atol(fargs[0]) <= mux_atol(fargs[1]));
00534     }
00535     else
00536     {
00537         bResult = (mux_atof(fargs[0]) <= mux_atof(fargs[1]));
00538     }
00539     safe_bool(bResult, buff, bufc);
00540 }
00541 
00542 FUNCTION(fun_eq)
00543 {
00544     UNUSED_PARAMETER(executor);
00545     UNUSED_PARAMETER(caller);
00546     UNUSED_PARAMETER(enactor);
00547     UNUSED_PARAMETER(nfargs);
00548     UNUSED_PARAMETER(cargs);
00549     UNUSED_PARAMETER(ncargs);
00550 
00551     bool bResult = false;
00552     int nDigits;
00553     if (  is_integer(fargs[0], &nDigits)
00554        && nDigits <= 9
00555        && is_integer(fargs[1], &nDigits)
00556        && nDigits <= 9)
00557     {
00558         bResult = (mux_atol(fargs[0]) == mux_atol(fargs[1]));
00559     }
00560     else
00561     {
00562         bResult = (  strcmp(fargs[0], fargs[1]) == 0
00563                   || mux_atof(fargs[0]) == mux_atof(fargs[1]));
00564     }
00565     safe_bool(bResult, buff, bufc);
00566 }
00567 
00568 FUNCTION(fun_neq)
00569 {
00570     UNUSED_PARAMETER(executor);
00571     UNUSED_PARAMETER(caller);
00572     UNUSED_PARAMETER(enactor);
00573     UNUSED_PARAMETER(nfargs);
00574     UNUSED_PARAMETER(cargs);
00575     UNUSED_PARAMETER(ncargs);
00576 
00577     bool bResult = false;
00578     int nDigits;
00579     if (  is_integer(fargs[0], &nDigits)
00580        && nDigits <= 9
00581        && is_integer(fargs[1], &nDigits)
00582        && nDigits <= 9)
00583     {
00584         bResult = (mux_atol(fargs[0]) != mux_atol(fargs[1]));
00585     }
00586     else
00587     {
00588         bResult = (  strcmp(fargs[0], fargs[1]) != 0
00589                   && mux_atof(fargs[0]) != mux_atof(fargs[1]));
00590     }
00591     safe_bool(bResult, buff, bufc);
00592 }
00593 
00594 /*
00595  * ---------------------------------------------------------------------------
00596  * * fun_max, fun_min: Return maximum (minimum) value.
00597  */
00598 
00599 FUNCTION(fun_max)
00600 {
00601     UNUSED_PARAMETER(executor);
00602     UNUSED_PARAMETER(caller);
00603     UNUSED_PARAMETER(enactor);
00604     UNUSED_PARAMETER(cargs);
00605     UNUSED_PARAMETER(ncargs);
00606 
00607     double maximum = 0.0;
00608     for (int i = 0; i < nfargs; i++)
00609     {
00610         double tval = mux_atof(fargs[i]);
00611         if (  i == 0
00612            || tval > maximum)
00613         {
00614             maximum = tval;
00615         }
00616     }
00617     fval(buff, bufc, maximum);
00618 }
00619 
00620 FUNCTION(fun_min)
00621 {
00622     UNUSED_PARAMETER(executor);
00623     UNUSED_PARAMETER(caller);
00624     UNUSED_PARAMETER(enactor);
00625     UNUSED_PARAMETER(cargs);
00626     UNUSED_PARAMETER(ncargs);
00627 
00628     double minimum = 0.0;
00629     for (int i = 0; i < nfargs; i++)
00630     {
00631         double tval = mux_atof(fargs[i]);
00632         if (  i == 0
00633            || tval < minimum)
00634         {
00635             minimum = tval;
00636         }
00637     }
00638     fval(buff, bufc, minimum);
00639 }
00640 
00641 /* ---------------------------------------------------------------------------
00642  * fun_sign: Returns -1, 0, or 1 based on the the sign of its argument.
00643  */
00644 
00645 FUNCTION(fun_sign)
00646 {
00647     UNUSED_PARAMETER(executor);
00648     UNUSED_PARAMETER(caller);
00649     UNUSED_PARAMETER(enactor);
00650     UNUSED_PARAMETER(nfargs);
00651     UNUSED_PARAMETER(cargs);
00652     UNUSED_PARAMETER(ncargs);
00653 
00654     double num = mux_atof(fargs[0]);
00655     if (num < 0)
00656     {
00657         safe_str("-1", buff, bufc);
00658     }
00659     else
00660     {
00661         safe_bool(num > 0, buff, bufc);
00662     }
00663 }
00664 
00665 // fun_isign: Returns -1, 0, or 1 based on the the sign of its argument.
00666 //
00667 FUNCTION(fun_isign)
00668 {
00669     UNUSED_PARAMETER(executor);
00670     UNUSED_PARAMETER(caller);
00671     UNUSED_PARAMETER(enactor);
00672     UNUSED_PARAMETER(nfargs);
00673     UNUSED_PARAMETER(cargs);
00674     UNUSED_PARAMETER(ncargs);
00675 
00676     INT64 num = mux_atoi64(fargs[0]);
00677 
00678     if (num < 0)
00679     {
00680         safe_str("-1", buff, bufc);
00681     }
00682     else
00683     {
00684         safe_bool(num > 0, buff, bufc);
00685     }
00686 }
00687 
00688 // shl() and shr() borrowed from PennMUSH 1.50
00689 //
00690 FUNCTION(fun_shl)
00691 {
00692     UNUSED_PARAMETER(executor);
00693     UNUSED_PARAMETER(caller);
00694     UNUSED_PARAMETER(enactor);
00695     UNUSED_PARAMETER(nfargs);
00696     UNUSED_PARAMETER(cargs);
00697     UNUSED_PARAMETER(ncargs);
00698 
00699     if (  is_integer(fargs[0], NULL)
00700        && is_integer(fargs[1], NULL))
00701     {
00702         INT64 a = mux_atoi64(fargs[0]);
00703         long  b = mux_atol(fargs[1]);
00704         safe_i64toa(a << b, buff, bufc);
00705     }
00706     else
00707     {
00708         safe_str("#-1 ARGUMENTS MUST BE INTEGERS", buff, bufc);
00709     }
00710 }
00711 
00712 FUNCTION(fun_shr)
00713 {
00714     UNUSED_PARAMETER(executor);
00715     UNUSED_PARAMETER(caller);
00716     UNUSED_PARAMETER(enactor);
00717     UNUSED_PARAMETER(nfargs);
00718     UNUSED_PARAMETER(cargs);
00719     UNUSED_PARAMETER(ncargs);
00720 
00721     if (  is_integer(fargs[0], NULL)
00722        && is_integer(fargs[1], NULL))
00723     {
00724         INT64 a = mux_atoi64(fargs[0]);
00725         long  b = mux_atol(fargs[1]);
00726         safe_i64toa(a >> b, buff, bufc);
00727     }
00728     else
00729     {
00730         safe_str("#-1 ARGUMENTS MUST BE INTEGERS", buff, bufc);
00731     }
00732 }
00733 
00734 FUNCTION(fun_inc)
00735 {
00736     UNUSED_PARAMETER(executor);
00737     UNUSED_PARAMETER(caller);
00738     UNUSED_PARAMETER(enactor);
00739     UNUSED_PARAMETER(cargs);
00740     UNUSED_PARAMETER(ncargs);
00741 
00742     if (nfargs == 1)
00743     {
00744         safe_i64toa(mux_atoi64(fargs[0]) + 1, buff, bufc);
00745     }
00746     else
00747     {
00748         safe_chr('1', buff, bufc);
00749     }
00750 }
00751 
00752 FUNCTION(fun_dec)
00753 {
00754     UNUSED_PARAMETER(executor);
00755     UNUSED_PARAMETER(caller);
00756     UNUSED_PARAMETER(enactor);
00757     UNUSED_PARAMETER(cargs);
00758     UNUSED_PARAMETER(ncargs);
00759 
00760     if (nfargs == 1)
00761     {
00762         safe_i64toa(mux_atoi64(fargs[0]) - 1, buff, bufc);
00763     }
00764     else
00765     {
00766         safe_str("-1", buff, bufc);
00767     }
00768 }
00769 
00770 FUNCTION(fun_trunc)
00771 {
00772     UNUSED_PARAMETER(executor);
00773     UNUSED_PARAMETER(caller);
00774     UNUSED_PARAMETER(enactor);
00775     UNUSED_PARAMETER(nfargs);
00776     UNUSED_PARAMETER(cargs);
00777     UNUSED_PARAMETER(ncargs);
00778 
00779     double rArg = mux_atof(fargs[0]);
00780     double rIntegerPart;
00781 
00782     mux_FPRestore();
00783     (void)modf(rArg, &rIntegerPart);
00784     mux_FPSet();
00785 
00786 #ifdef HAVE_IEEE_FP_FORMAT
00787     int fpc = mux_fpclass(rIntegerPart);
00788     if (MUX_FPGROUP(fpc) == MUX_FPGROUP_PASS)
00789     {
00790 #endif // HAVE_IEEE_FP_FORMAT
00791         safe_tprintf_str(buff, bufc, "%.0f", rIntegerPart);
00792 #ifdef HAVE_IEEE_FP_FORMAT
00793     }
00794     else
00795     {
00796         safe_str(mux_FPStrings[MUX_FPCLASS(fpc)], buff, bufc);
00797     }
00798 #endif // HAVE_IEEE_FP_FORMAT
00799 }
00800 
00801 FUNCTION(fun_fdiv)
00802 {
00803     UNUSED_PARAMETER(executor);
00804     UNUSED_PARAMETER(caller);
00805     UNUSED_PARAMETER(enactor);
00806     UNUSED_PARAMETER(nfargs);
00807     UNUSED_PARAMETER(cargs);
00808     UNUSED_PARAMETER(ncargs);
00809 
00810     double bot = mux_atof(fargs[1]);
00811     double top = mux_atof(fargs[0]);
00812 #ifndef HAVE_IEEE_FP_SNAN
00813     if (bot == 0.0)
00814     {
00815         if (top > 0.0)
00816         {
00817             safe_str("+Inf", buff, bufc);
00818         }
00819         else if (top < 0.0)
00820         {
00821             safe_str("-Inf", buff, bufc);
00822         }
00823         else
00824         {
00825             safe_str("Ind", buff, bufc);
00826         }
00827     }
00828     else
00829     {
00830         fval(buff, bufc, top/bot);
00831     }
00832 #else
00833     fval(buff, bufc, top/bot);
00834 #endif
00835 }
00836 
00837 FUNCTION(fun_idiv)
00838 {
00839     UNUSED_PARAMETER(executor);
00840     UNUSED_PARAMETER(caller);
00841     UNUSED_PARAMETER(enactor);
00842     UNUSED_PARAMETER(nfargs);
00843     UNUSED_PARAMETER(cargs);
00844     UNUSED_PARAMETER(ncargs);
00845 
00846     INT64 bot, top;
00847 
00848     bot = mux_atoi64(fargs[1]);
00849     if (bot == 0)
00850     {
00851         safe_str("#-1 DIVIDE BY ZERO", buff, bufc);
00852     }
00853     else
00854     {
00855         top = mux_atoi64(fargs[0]);
00856         top = i64Division(top, bot);
00857         safe_i64toa(top, buff, bufc);
00858     }
00859 }
00860 
00861 FUNCTION(fun_floordiv)
00862 {
00863     UNUSED_PARAMETER(executor);
00864     UNUSED_PARAMETER(caller);
00865     UNUSED_PARAMETER(enactor);
00866     UNUSED_PARAMETER(nfargs);
00867     UNUSED_PARAMETER(cargs);
00868     UNUSED_PARAMETER(ncargs);
00869 
00870     INT64 bot, top;
00871 
00872     bot = mux_atoi64(fargs[1]);
00873     if (bot == 0)
00874     {
00875         safe_str("#-1 DIVIDE BY ZERO", buff, bufc);
00876     }
00877     else
00878     {
00879         top = mux_atoi64(fargs[0]);
00880         top = i64FloorDivision(top, bot);
00881         safe_i64toa(top, buff, bufc);
00882     }
00883 }
00884 
00885 FUNCTION(fun_mod)
00886 {
00887     UNUSED_PARAMETER(executor);
00888     UNUSED_PARAMETER(caller);
00889     UNUSED_PARAMETER(enactor);
00890     UNUSED_PARAMETER(nfargs);
00891     UNUSED_PARAMETER(cargs);
00892     UNUSED_PARAMETER(ncargs);
00893 
00894     INT64 bot, top;
00895 
00896     bot = mux_atoi64(fargs[1]);
00897     if (bot == 0)
00898     {
00899         bot = 1;
00900     }
00901     top = mux_atoi64(fargs[0]);
00902     top = i64Mod(top, bot);
00903     safe_i64toa(top, buff, bufc);
00904 }
00905 
00906 FUNCTION(fun_remainder)
00907 {
00908     UNUSED_PARAMETER(executor);
00909     UNUSED_PARAMETER(caller);
00910     UNUSED_PARAMETER(enactor);
00911     UNUSED_PARAMETER(nfargs);
00912     UNUSED_PARAMETER(cargs);
00913     UNUSED_PARAMETER(ncargs);
00914 
00915     INT64 bot, top;
00916 
00917     bot = mux_atoi64(fargs[1]);
00918     if (bot == 0)
00919     {
00920         bot = 1;
00921     }
00922     top = mux_atoi64(fargs[0]);
00923     top = i64Remainder(top, bot);
00924     safe_i64toa(top, buff, bufc);
00925 }
00926 
00927 /* ---------------------------------------------------------------------------
00928  * fun_abs: Returns the absolute value of its argument.
00929  */
00930 
00931 FUNCTION(fun_abs)
00932 {
00933     UNUSED_PARAMETER(executor);
00934     UNUSED_PARAMETER(caller);
00935     UNUSED_PARAMETER(enactor);
00936     UNUSED_PARAMETER(nfargs);
00937     UNUSED_PARAMETER(cargs);
00938     UNUSED_PARAMETER(ncargs);
00939 
00940     double num = mux_atof(fargs[0]);
00941     if (num == 0.0)
00942     {
00943         safe_chr('0', buff, bufc);
00944     }
00945     else if (num < 0.0)
00946     {
00947         fval(buff, bufc, -num);
00948     }
00949     else
00950     {
00951         fval(buff, bufc, num);
00952     }
00953 }
00954 
00955 // fun_iabs: Returns the absolute value of its argument.
00956 //
00957 FUNCTION(fun_iabs)
00958 {
00959     UNUSED_PARAMETER(executor);
00960     UNUSED_PARAMETER(caller);
00961     UNUSED_PARAMETER(enactor);
00962     UNUSED_PARAMETER(nfargs);
00963     UNUSED_PARAMETER(cargs);
00964     UNUSED_PARAMETER(ncargs);
00965 
00966     INT64 num = mux_atoi64(fargs[0]);
00967 
00968     if (num == 0)
00969     {
00970         safe_chr('0', buff, bufc);
00971     }
00972     else if (num < 0)
00973     {
00974         safe_i64toa(-num, buff, bufc);
00975     }
00976     else
00977     {
00978         safe_i64toa(num, buff, bufc);
00979     }
00980 }
00981 
00982 FUNCTION(fun_dist2d)
00983 {
00984     UNUSED_PARAMETER(executor);
00985     UNUSED_PARAMETER(caller);
00986     UNUSED_PARAMETER(enactor);
00987     UNUSED_PARAMETER(nfargs);
00988     UNUSED_PARAMETER(cargs);
00989     UNUSED_PARAMETER(ncargs);
00990 
00991     double d;
00992     double sum;
00993 
00994     d = mux_atof(fargs[0]) - mux_atof(fargs[2]);
00995     sum  = d * d;
00996     d = mux_atof(fargs[1]) - mux_atof(fargs[3]);
00997     sum += d * d;
00998 
00999     mux_FPRestore();
01000     double result = sqrt(sum);
01001     mux_FPSet();
01002 
01003     fval(buff, bufc, result);
01004 }
01005 
01006 FUNCTION(fun_dist3d)
01007 {
01008     UNUSED_PARAMETER(executor);
01009     UNUSED_PARAMETER(caller);
01010     UNUSED_PARAMETER(enactor);
01011     UNUSED_PARAMETER(nfargs);
01012     UNUSED_PARAMETER(cargs);
01013     UNUSED_PARAMETER(ncargs);
01014 
01015     double d;
01016     double sum;
01017 
01018     d = mux_atof(fargs[0]) - mux_atof(fargs[3]);
01019     sum  = d * d;
01020     d = mux_atof(fargs[1]) - mux_atof(fargs[4]);
01021     sum += d * d;
01022     d = mux_atof(fargs[2]) - mux_atof(fargs[5]);
01023     sum += d * d;
01024 
01025     mux_FPRestore();
01026     double result = sqrt(sum);
01027     mux_FPSet();
01028 
01029     fval(buff, bufc, result);
01030 }
01031 
01032 //------------------------------------------------------------------------
01033 // Vector functions: VADD, VSUB, VMUL, VCROSS, VMAG, VUNIT, VDIM
01034 // Vectors are space-separated numbers.
01035 //
01036 #define VADD_F   0
01037 #define VSUB_F   1
01038 #define VMUL_F   2
01039 #define VDOT_F   3
01040 #define VCROSS_F 4
01041 
01042 static void handle_vectors
01043 (
01044     char *vecarg1, char *vecarg2, char *buff, char **bufc, SEP *psep,
01045     SEP *posep, int flag
01046 )
01047 {
01048     char *v1[(LBUF_SIZE+1)/2], *v2[(LBUF_SIZE+1)/2];
01049     double scalar;
01050     int n, m, i;
01051 
01052     // Split the list up, or return if the list is empty.
01053     //
01054     if (!vecarg1 || !*vecarg1 || !vecarg2 || !*vecarg2)
01055     {
01056         return;
01057     }
01058     n = list2arr(v1, (LBUF_SIZE+1)/2, vecarg1, psep);
01059     m = list2arr(v2, (LBUF_SIZE+1)/2, vecarg2, psep);
01060 
01061     // vmul() and vadd() accepts a scalar in the first or second arg,
01062     // but everything else has to be same-dimensional.
01063     //
01064     if (  n != m
01065        && !(  (  flag == VMUL_F
01066               || flag == VADD_F
01067               || flag == VSUB_F)
01068            && (  n == 1
01069               || m == 1)))
01070     {
01071         safe_str("#-1 VECTORS MUST BE SAME DIMENSIONS", buff, bufc);
01072         return;
01073     }
01074 
01075     switch (flag)
01076     {
01077     case VADD_F:
01078 
01079         // If n or m is 1, this is scalar addition.
01080         // otherwise, add element-wise.
01081         //
01082         if (n == 1)
01083         {
01084             scalar = mux_atof(v1[0]);
01085             for (i = 0; i < m; i++)
01086             {
01087                 if (i != 0)
01088                 {
01089                     print_sep(posep, buff, bufc);
01090                 }
01091                 fval(buff, bufc, mux_atof(v2[i]) + scalar);
01092             }
01093             n = m;
01094         }
01095         else if (m == 1)
01096         {
01097             scalar = mux_atof(v2[0]);
01098             for (i = 0; i < n; i++)
01099             {
01100                 if (i != 0)
01101                 {
01102                     print_sep(posep, buff, bufc);
01103                 }
01104                 fval(buff, bufc, mux_atof(v1[i]) + scalar);
01105             }
01106         }
01107         else
01108         {
01109             for (i = 0; i < n; i++)
01110             {
01111                 if (i != 0)
01112                 {
01113                     print_sep(posep, buff, bufc);
01114                 }
01115                 double a = mux_atof(v1[i]);
01116                 double b = mux_atof(v2[i]);
01117                 fval(buff, bufc, a + b);
01118             }
01119         }
01120         break;
01121 
01122     case VSUB_F:
01123 
01124         if (n == 1)
01125         {
01126             // This is a scalar minus a vector.
01127             //
01128             scalar = mux_atof(v1[0]);
01129             for (i = 0; i < m; i++)
01130             {
01131                 if (i != 0)
01132                 {
01133                     print_sep(posep, buff, bufc);
01134                 }
01135                 fval(buff, bufc, scalar - mux_atof(v2[i]));
01136             }
01137         }
01138         else if (m == 1)
01139         {
01140             // This is a vector minus a scalar.
01141             //
01142             scalar = mux_atof(v2[0]);
01143             for (i = 0; i < n; i++)
01144             {
01145                 if (i != 0)
01146                 {
01147                     print_sep(posep, buff, bufc);
01148                 }
01149                 fval(buff, bufc, mux_atof(v1[i]) - scalar);
01150             }
01151         }
01152         else
01153         {
01154             // This is a vector minus a vector.
01155             //
01156             for (i = 0; i < n; i++)
01157             {
01158                 if (i != 0)
01159                 {
01160                     print_sep(posep, buff, bufc);
01161                 }
01162                 double a = mux_atof(v1[i]);
01163                 double b = mux_atof(v2[i]);
01164                 fval(buff, bufc, a - b);
01165             }
01166         }
01167         break;
01168 
01169     case VMUL_F:
01170 
01171         // If n or m is 1, this is scalar multiplication.
01172         // otherwise, multiply elementwise.
01173         //
01174         if (n == 1)
01175         {
01176             scalar = mux_atof(v1[0]);
01177             for (i = 0; i < m; i++)
01178             {
01179                 if (i != 0)
01180                 {
01181                     print_sep(posep, buff, bufc);
01182                 }
01183                 fval(buff, bufc, mux_atof(v2[i]) * scalar);
01184             }
01185         }
01186         else if (m == 1)
01187         {
01188             scalar = mux_atof(v2[0]);
01189             for (i = 0; i < n; i++)
01190             {
01191                 if (i != 0)
01192                 {
01193                     print_sep(posep, buff, bufc);
01194                 }
01195                 fval(buff, bufc, mux_atof(v1[i]) * scalar);
01196             }
01197         }
01198         else
01199         {
01200             // Vector element-wise product.
01201             //
01202             for (i = 0; i < n; i++)
01203             {
01204                 if (i != 0)
01205                 {
01206                     print_sep(posep, buff, bufc);
01207                 }
01208                 double a = mux_atof(v1[i]);
01209                 double b = mux_atof(v2[i]);
01210                 fval(buff, bufc, a * b);
01211             }
01212         }
01213         break;
01214 
01215     case VDOT_F:
01216 
01217         scalar = 0.0;
01218         for (i = 0; i < n; i++)
01219         {
01220             double a = mux_atof(v1[i]);
01221             double b = mux_atof(v2[i]);
01222             scalar +=  a * b;
01223         }
01224         fval(buff, bufc, scalar);
01225         break;
01226 
01227     case VCROSS_F:
01228 
01229         // cross product: (a,b,c) x (d,e,f) = (bf - ce, cd - af, ae - bd)
01230         //
01231         // Or in other words:
01232         //
01233         //      | a  b  c |
01234         //  det | d  e  f | = i(bf-ce) + j(cd-af) + k(ae-bd)
01235         //      | i  j  k |
01236         //
01237         // where i, j, and k are unit vectors in the x, y, and z
01238         // cartisian coordinate space and are understood when expressed
01239         // in vector form.
01240         //
01241         if (n != 3)
01242         {
01243             safe_str("#-1 VECTORS MUST BE DIMENSION OF 3", buff, bufc);
01244         }
01245         else
01246         {
01247             double a[2][3];
01248             for (i = 0; i < 3; i++)
01249             {
01250                 a[0][i] = mux_atof(v1[i]);
01251                 a[1][i] = mux_atof(v2[i]);
01252             }
01253             fval(buff, bufc, (a[0][1] * a[1][2]) - (a[0][2] * a[1][1]));
01254             print_sep(posep, buff, bufc);
01255             fval(buff, bufc, (a[0][2] * a[1][0]) - (a[0][0] * a[1][2]));
01256             print_sep(posep, buff, bufc);
01257             fval(buff, bufc, (a[0][0] * a[1][1]) - (a[0][1] * a[1][0]));
01258         }
01259         break;
01260 
01261     default:
01262 
01263         // If we reached this, we're in trouble.
01264         //
01265         safe_str("#-1 UNIMPLEMENTED", buff, bufc);
01266     }
01267 }
01268 
01269 FUNCTION(fun_vadd)
01270 {
01271     SEP sep;
01272     if (!