mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 14:51:51 +00:00
- implemented '**' (power) operator. To ensure reliability, acustom 'pow' function will be used to calculate it.
- fixed: FxBinary::ResolveLR' check for numeric operations was incomplete. Like far too many other places it just assumed that everything with ValueType->GetRegType() == REGT_INT is a numeric type, but for names this is not the case.
This commit is contained in:
parent
d0a8960f61
commit
938ab4ca70
10 changed files with 1033 additions and 10 deletions
|
@ -1287,6 +1287,8 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
|
|||
math/log10.c
|
||||
math/mtherr.c
|
||||
math/polevl.c
|
||||
math/pow.c
|
||||
math/powi.c
|
||||
math/sin.c
|
||||
math/sinh.c
|
||||
math/sqrt.c
|
||||
|
|
|
@ -3636,7 +3636,7 @@ void FParser::SF_Pow()
|
|||
{
|
||||
if (CheckArgs(2))
|
||||
{
|
||||
t_return.setDouble(pow(floatvalue(t_argv[0]), floatvalue(t_argv[1])));
|
||||
t_return.setDouble(g_pow(floatvalue(t_argv[0]), floatvalue(t_argv[1])));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ double c_tanh(double);
|
|||
double c_exp(double);
|
||||
double c_log(double);
|
||||
double c_log10(double);
|
||||
double c_pow(double, double);
|
||||
}
|
||||
|
||||
|
||||
|
@ -114,6 +115,7 @@ inline double cosdeg(double v)
|
|||
#define g_exp exp
|
||||
#define g_log log
|
||||
#define g_log10 log10
|
||||
#define g_pow pow
|
||||
#else
|
||||
#define g_asin c_asin
|
||||
#define g_acos c_acos
|
||||
|
@ -139,6 +141,7 @@ inline double cosdeg(double v)
|
|||
#define g_exp c_exp
|
||||
#define g_log c_log
|
||||
#define g_log10 c_log10
|
||||
#define g_pow c_pow
|
||||
#endif
|
||||
|
||||
|
||||
|
|
756
src/math/pow.c
Normal file
756
src/math/pow.c
Normal file
|
@ -0,0 +1,756 @@
|
|||
/* pow.c
|
||||
*
|
||||
* Power function
|
||||
*
|
||||
*
|
||||
*
|
||||
* SYNOPSIS:
|
||||
*
|
||||
* double x, y, z, pow();
|
||||
*
|
||||
* z = pow( x, y );
|
||||
*
|
||||
*
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Computes x raised to the yth power. Analytically,
|
||||
*
|
||||
* x**y = exp( y log(x) ).
|
||||
*
|
||||
* Following Cody and Waite, this program uses a lookup table
|
||||
* of 2**-i/16 and pseudo extended precision arithmetic to
|
||||
* obtain an extra three bits of accuracy in both the logarithm
|
||||
* and the exponential.
|
||||
*
|
||||
*
|
||||
*
|
||||
* ACCURACY:
|
||||
*
|
||||
* Relative error:
|
||||
* arithmetic domain # trials peak rms
|
||||
* IEEE -26,26 30000 4.2e-16 7.7e-17
|
||||
* DEC -26,26 60000 4.8e-17 9.1e-18
|
||||
* 1/26 < x < 26, with log(x) uniformly distributed.
|
||||
* -26 < y < 26, y uniformly distributed.
|
||||
* IEEE 0,8700 30000 1.5e-14 2.1e-15
|
||||
* 0.99 < x < 1.01, 0 < y < 8700, uniformly distributed.
|
||||
*
|
||||
*
|
||||
* ERROR MESSAGES:
|
||||
*
|
||||
* message condition value returned
|
||||
* pow overflow x**y > MAXNUM INFINITY
|
||||
* pow underflow x**y < 1/MAXNUM 0.0
|
||||
* pow domain x<0 and y noninteger 0.0
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
Cephes Math Library Release 2.8: June, 2000
|
||||
Copyright 1984, 1995, 2000 by Stephen L. Moshier
|
||||
*/
|
||||
|
||||
|
||||
#include "mconf.h"
|
||||
static char fname[] = {"pow"};
|
||||
|
||||
#define SQRTH 0.70710678118654752440
|
||||
|
||||
#ifdef UNK
|
||||
static double P[] = {
|
||||
4.97778295871696322025E-1,
|
||||
3.73336776063286838734E0,
|
||||
7.69994162726912503298E0,
|
||||
4.66651806774358464979E0
|
||||
};
|
||||
static double Q[] = {
|
||||
/* 1.00000000000000000000E0, */
|
||||
9.33340916416696166113E0,
|
||||
2.79999886606328401649E1,
|
||||
3.35994905342304405431E1,
|
||||
1.39995542032307539578E1
|
||||
};
|
||||
/* 2^(-i/16), IEEE precision */
|
||||
static double A[] = {
|
||||
1.00000000000000000000E0,
|
||||
9.57603280698573700036E-1,
|
||||
9.17004043204671215328E-1,
|
||||
8.78126080186649726755E-1,
|
||||
8.40896415253714502036E-1,
|
||||
8.05245165974627141736E-1,
|
||||
7.71105412703970372057E-1,
|
||||
7.38413072969749673113E-1,
|
||||
7.07106781186547572737E-1,
|
||||
6.77127773468446325644E-1,
|
||||
6.48419777325504820276E-1,
|
||||
6.20928906036742001007E-1,
|
||||
5.94603557501360513449E-1,
|
||||
5.69394317378345782288E-1,
|
||||
5.45253866332628844837E-1,
|
||||
5.22136891213706877402E-1,
|
||||
5.00000000000000000000E-1
|
||||
};
|
||||
static double B[] = {
|
||||
0.00000000000000000000E0,
|
||||
1.64155361212281360176E-17,
|
||||
4.09950501029074826006E-17,
|
||||
3.97491740484881042808E-17,
|
||||
-4.83364665672645672553E-17,
|
||||
1.26912513974441574796E-17,
|
||||
1.99100761573282305549E-17,
|
||||
-1.52339103990623557348E-17,
|
||||
0.00000000000000000000E0
|
||||
};
|
||||
static double R[] = {
|
||||
1.49664108433729301083E-5,
|
||||
1.54010762792771901396E-4,
|
||||
1.33335476964097721140E-3,
|
||||
9.61812908476554225149E-3,
|
||||
5.55041086645832347466E-2,
|
||||
2.40226506959099779976E-1,
|
||||
6.93147180559945308821E-1
|
||||
};
|
||||
|
||||
#define douba(k) A[k]
|
||||
#define doubb(k) B[k]
|
||||
#define MEXP 16383.0
|
||||
#ifdef DENORMAL
|
||||
#define MNEXP -17183.0
|
||||
#else
|
||||
#define MNEXP -16383.0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef DEC
|
||||
static unsigned short P[] = {
|
||||
0037776,0156313,0175332,0163602,
|
||||
0040556,0167577,0052366,0174245,
|
||||
0040766,0062753,0175707,0055564,
|
||||
0040625,0052035,0131344,0155636,
|
||||
};
|
||||
static unsigned short Q[] = {
|
||||
/*0040200,0000000,0000000,0000000,*/
|
||||
0041025,0052644,0154404,0105155,
|
||||
0041337,0177772,0007016,0047646,
|
||||
0041406,0062740,0154273,0020020,
|
||||
0041137,0177054,0106127,0044555,
|
||||
};
|
||||
static unsigned short A[] = {
|
||||
0040200,0000000,0000000,0000000,
|
||||
0040165,0022575,0012444,0103314,
|
||||
0040152,0140306,0163735,0022071,
|
||||
0040140,0146336,0166052,0112341,
|
||||
0040127,0042374,0145326,0116553,
|
||||
0040116,0022214,0012437,0102201,
|
||||
0040105,0063452,0010525,0003333,
|
||||
0040075,0004243,0117530,0006067,
|
||||
0040065,0002363,0031771,0157145,
|
||||
0040055,0054076,0165102,0120513,
|
||||
0040045,0177326,0124661,0050471,
|
||||
0040036,0172462,0060221,0120422,
|
||||
0040030,0033760,0050615,0134251,
|
||||
0040021,0141723,0071653,0010703,
|
||||
0040013,0112701,0161752,0105727,
|
||||
0040005,0125303,0063714,0044173,
|
||||
0040000,0000000,0000000,0000000
|
||||
};
|
||||
static unsigned short B[] = {
|
||||
0000000,0000000,0000000,0000000,
|
||||
0021473,0040265,0153315,0140671,
|
||||
0121074,0062627,0042146,0176454,
|
||||
0121413,0003524,0136332,0066212,
|
||||
0121767,0046404,0166231,0012553,
|
||||
0121257,0015024,0002357,0043574,
|
||||
0021736,0106532,0043060,0056206,
|
||||
0121310,0020334,0165705,0035326,
|
||||
0000000,0000000,0000000,0000000
|
||||
};
|
||||
|
||||
static unsigned short R[] = {
|
||||
0034173,0014076,0137624,0115771,
|
||||
0035041,0076763,0003744,0111311,
|
||||
0035656,0141766,0041127,0074351,
|
||||
0036435,0112533,0073611,0116664,
|
||||
0037143,0054106,0134040,0152223,
|
||||
0037565,0176757,0176026,0025551,
|
||||
0040061,0071027,0173721,0147572
|
||||
};
|
||||
|
||||
/*
|
||||
static double R[] = {
|
||||
0.14928852680595608186e-4,
|
||||
0.15400290440989764601e-3,
|
||||
0.13333541313585784703e-2,
|
||||
0.96181290595172416964e-2,
|
||||
0.55504108664085595326e-1,
|
||||
0.24022650695909537056e0,
|
||||
0.69314718055994529629e0
|
||||
};
|
||||
*/
|
||||
#define douba(k) (*(double *)&A[(k)<<2])
|
||||
#define doubb(k) (*(double *)&B[(k)<<2])
|
||||
#define MEXP 2031.0
|
||||
#define MNEXP -2031.0
|
||||
#endif
|
||||
|
||||
#ifdef IBMPC
|
||||
static unsigned short P[] = {
|
||||
0x5cf0,0x7f5b,0xdb99,0x3fdf,
|
||||
0xdf15,0xea9e,0xddef,0x400d,
|
||||
0xeb6f,0x7f78,0xccbd,0x401e,
|
||||
0x9b74,0xb65c,0xaa83,0x4012,
|
||||
};
|
||||
static unsigned short Q[] = {
|
||||
/*0x0000,0x0000,0x0000,0x3ff0,*/
|
||||
0x914e,0x9b20,0xaab4,0x4022,
|
||||
0xc9f5,0x41c1,0xffff,0x403b,
|
||||
0x6402,0x1b17,0xccbc,0x4040,
|
||||
0xe92e,0x918a,0xffc5,0x402b,
|
||||
};
|
||||
static unsigned short A[] = {
|
||||
0x0000,0x0000,0x0000,0x3ff0,
|
||||
0x90da,0xa2a4,0xa4af,0x3fee,
|
||||
0xa487,0xdcfb,0x5818,0x3fed,
|
||||
0x529c,0xdd85,0x199b,0x3fec,
|
||||
0xd3ad,0x995a,0xe89f,0x3fea,
|
||||
0xf090,0x82a3,0xc491,0x3fe9,
|
||||
0xa0db,0x422a,0xace5,0x3fe8,
|
||||
0x0187,0x73eb,0xa114,0x3fe7,
|
||||
0x3bcd,0x667f,0xa09e,0x3fe6,
|
||||
0x5429,0xdd48,0xab07,0x3fe5,
|
||||
0x2a27,0xd536,0xbfda,0x3fe4,
|
||||
0x3422,0x4c12,0xdea6,0x3fe3,
|
||||
0xb715,0x0a31,0x06fe,0x3fe3,
|
||||
0x6238,0x6e75,0x387a,0x3fe2,
|
||||
0x517b,0x3c7d,0x72b8,0x3fe1,
|
||||
0x890f,0x6cf9,0xb558,0x3fe0,
|
||||
0x0000,0x0000,0x0000,0x3fe0
|
||||
};
|
||||
static unsigned short B[] = {
|
||||
0x0000,0x0000,0x0000,0x0000,
|
||||
0x3707,0xd75b,0xed02,0x3c72,
|
||||
0xcc81,0x345d,0xa1cd,0x3c87,
|
||||
0x4b27,0x5686,0xe9f1,0x3c86,
|
||||
0x6456,0x13b2,0xdd34,0xbc8b,
|
||||
0x42e2,0xafec,0x4397,0x3c6d,
|
||||
0x82e4,0xd231,0xf46a,0x3c76,
|
||||
0x8a76,0xb9d7,0x9041,0xbc71,
|
||||
0x0000,0x0000,0x0000,0x0000
|
||||
};
|
||||
static unsigned short R[] = {
|
||||
0x937f,0xd7f2,0x6307,0x3eef,
|
||||
0x9259,0x60fc,0x2fbe,0x3f24,
|
||||
0xef1d,0xc84a,0xd87e,0x3f55,
|
||||
0x33b7,0x6ef1,0xb2ab,0x3f83,
|
||||
0x1a92,0xd704,0x6b08,0x3fac,
|
||||
0xc56d,0xff82,0xbfbd,0x3fce,
|
||||
0x39ef,0xfefa,0x2e42,0x3fe6
|
||||
};
|
||||
|
||||
#define douba(k) (*(double *)&A[(k)<<2])
|
||||
#define doubb(k) (*(double *)&B[(k)<<2])
|
||||
#define MEXP 16383.0
|
||||
#ifdef DENORMAL
|
||||
#define MNEXP -17183.0
|
||||
#else
|
||||
#define MNEXP -16383.0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MIEEE
|
||||
static unsigned short P[] = {
|
||||
0x3fdf,0xdb99,0x7f5b,0x5cf0,
|
||||
0x400d,0xddef,0xea9e,0xdf15,
|
||||
0x401e,0xccbd,0x7f78,0xeb6f,
|
||||
0x4012,0xaa83,0xb65c,0x9b74
|
||||
};
|
||||
static unsigned short Q[] = {
|
||||
0x4022,0xaab4,0x9b20,0x914e,
|
||||
0x403b,0xffff,0x41c1,0xc9f5,
|
||||
0x4040,0xccbc,0x1b17,0x6402,
|
||||
0x402b,0xffc5,0x918a,0xe92e
|
||||
};
|
||||
static unsigned short A[] = {
|
||||
0x3ff0,0x0000,0x0000,0x0000,
|
||||
0x3fee,0xa4af,0xa2a4,0x90da,
|
||||
0x3fed,0x5818,0xdcfb,0xa487,
|
||||
0x3fec,0x199b,0xdd85,0x529c,
|
||||
0x3fea,0xe89f,0x995a,0xd3ad,
|
||||
0x3fe9,0xc491,0x82a3,0xf090,
|
||||
0x3fe8,0xace5,0x422a,0xa0db,
|
||||
0x3fe7,0xa114,0x73eb,0x0187,
|
||||
0x3fe6,0xa09e,0x667f,0x3bcd,
|
||||
0x3fe5,0xab07,0xdd48,0x5429,
|
||||
0x3fe4,0xbfda,0xd536,0x2a27,
|
||||
0x3fe3,0xdea6,0x4c12,0x3422,
|
||||
0x3fe3,0x06fe,0x0a31,0xb715,
|
||||
0x3fe2,0x387a,0x6e75,0x6238,
|
||||
0x3fe1,0x72b8,0x3c7d,0x517b,
|
||||
0x3fe0,0xb558,0x6cf9,0x890f,
|
||||
0x3fe0,0x0000,0x0000,0x0000
|
||||
};
|
||||
static unsigned short B[] = {
|
||||
0x0000,0x0000,0x0000,0x0000,
|
||||
0x3c72,0xed02,0xd75b,0x3707,
|
||||
0x3c87,0xa1cd,0x345d,0xcc81,
|
||||
0x3c86,0xe9f1,0x5686,0x4b27,
|
||||
0xbc8b,0xdd34,0x13b2,0x6456,
|
||||
0x3c6d,0x4397,0xafec,0x42e2,
|
||||
0x3c76,0xf46a,0xd231,0x82e4,
|
||||
0xbc71,0x9041,0xb9d7,0x8a76,
|
||||
0x0000,0x0000,0x0000,0x0000
|
||||
};
|
||||
static unsigned short R[] = {
|
||||
0x3eef,0x6307,0xd7f2,0x937f,
|
||||
0x3f24,0x2fbe,0x60fc,0x9259,
|
||||
0x3f55,0xd87e,0xc84a,0xef1d,
|
||||
0x3f83,0xb2ab,0x6ef1,0x33b7,
|
||||
0x3fac,0x6b08,0xd704,0x1a92,
|
||||
0x3fce,0xbfbd,0xff82,0xc56d,
|
||||
0x3fe6,0x2e42,0xfefa,0x39ef
|
||||
};
|
||||
|
||||
#define douba(k) (*(double *)&A[(k)<<2])
|
||||
#define doubb(k) (*(double *)&B[(k)<<2])
|
||||
#define MEXP 16383.0
|
||||
#ifdef DENORMAL
|
||||
#define MNEXP -17183.0
|
||||
#else
|
||||
#define MNEXP -16383.0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* log2(e) - 1 */
|
||||
#define LOG2EA 0.44269504088896340736
|
||||
|
||||
#define F W
|
||||
#define Fa Wa
|
||||
#define Fb Wb
|
||||
#define G W
|
||||
#define Ga Wa
|
||||
#define Gb u
|
||||
#define H W
|
||||
#define Ha Wb
|
||||
#define Hb Wb
|
||||
|
||||
#ifdef ANSIPROT
|
||||
extern double floor ( double );
|
||||
extern double fabs ( double );
|
||||
extern double frexp ( double, int * );
|
||||
extern double ldexp ( double, int );
|
||||
extern double polevl ( double, void *, int );
|
||||
extern double p1evl ( double, void *, int );
|
||||
extern double c_powi ( double, int );
|
||||
extern int signbit ( double );
|
||||
extern int isnan ( double );
|
||||
extern int isfinite ( double );
|
||||
static double reduc ( double );
|
||||
#else
|
||||
double floor(), fabs(), frexp(), ldexp();
|
||||
double polevl(), p1evl(), c_powi();
|
||||
int signbit(), isnan(), isfinite();
|
||||
static double reduc();
|
||||
#endif
|
||||
extern double MAXNUM;
|
||||
#ifdef INFINITIES
|
||||
extern double INFINITY;
|
||||
#endif
|
||||
#ifdef NANS
|
||||
extern double NAN;
|
||||
#endif
|
||||
#ifdef MINUSZERO
|
||||
extern double NEGZERO;
|
||||
#endif
|
||||
|
||||
double c_pow( x, y )
|
||||
double x, y;
|
||||
{
|
||||
double w, z, W, Wa, Wb, ya, yb, u;
|
||||
/* double F, Fa, Fb, G, Ga, Gb, H, Ha, Hb */
|
||||
double aw, ay, wy;
|
||||
int e, i, nflg, iyflg, yoddint;
|
||||
|
||||
if( y == 0.0 )
|
||||
return( 1.0 );
|
||||
#ifdef NANS
|
||||
if( isnan(x) )
|
||||
return( x );
|
||||
if( isnan(y) )
|
||||
return( y );
|
||||
#endif
|
||||
if( y == 1.0 )
|
||||
return( x );
|
||||
|
||||
|
||||
#ifdef INFINITIES
|
||||
if( !isfinite(y) && (x == 1.0 || x == -1.0) )
|
||||
{
|
||||
mtherr( "pow", DOMAIN );
|
||||
#ifdef NANS
|
||||
return( NAN );
|
||||
#else
|
||||
return( INFINITY );
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if( x == 1.0 )
|
||||
return( 1.0 );
|
||||
|
||||
if( y >= MAXNUM )
|
||||
{
|
||||
#ifdef INFINITIES
|
||||
if( x > 1.0 )
|
||||
return( INFINITY );
|
||||
#else
|
||||
if( x > 1.0 )
|
||||
return( MAXNUM );
|
||||
#endif
|
||||
if( x > 0.0 && x < 1.0 )
|
||||
return( 0.0);
|
||||
if( x < -1.0 )
|
||||
{
|
||||
#ifdef INFINITIES
|
||||
return( INFINITY );
|
||||
#else
|
||||
return( MAXNUM );
|
||||
#endif
|
||||
}
|
||||
if( x > -1.0 && x < 0.0 )
|
||||
return( 0.0 );
|
||||
}
|
||||
if( y <= -MAXNUM )
|
||||
{
|
||||
if( x > 1.0 )
|
||||
return( 0.0 );
|
||||
#ifdef INFINITIES
|
||||
if( x > 0.0 && x < 1.0 )
|
||||
return( INFINITY );
|
||||
#else
|
||||
if( x > 0.0 && x < 1.0 )
|
||||
return( MAXNUM );
|
||||
#endif
|
||||
if( x < -1.0 )
|
||||
return( 0.0 );
|
||||
#ifdef INFINITIES
|
||||
if( x > -1.0 && x < 0.0 )
|
||||
return( INFINITY );
|
||||
#else
|
||||
if( x > -1.0 && x < 0.0 )
|
||||
return( MAXNUM );
|
||||
#endif
|
||||
}
|
||||
if( x >= MAXNUM )
|
||||
{
|
||||
#if INFINITIES
|
||||
if( y > 0.0 )
|
||||
return( INFINITY );
|
||||
#else
|
||||
if( y > 0.0 )
|
||||
return( MAXNUM );
|
||||
#endif
|
||||
return(0.0);
|
||||
}
|
||||
/* Set iyflg to 1 if y is an integer. */
|
||||
iyflg = 0;
|
||||
w = floor(y);
|
||||
if( w == y )
|
||||
iyflg = 1;
|
||||
|
||||
/* Test for odd integer y. */
|
||||
yoddint = 0;
|
||||
if( iyflg )
|
||||
{
|
||||
ya = fabs(y);
|
||||
ya = floor(0.5 * ya);
|
||||
yb = 0.5 * fabs(w);
|
||||
if( ya != yb )
|
||||
yoddint = 1;
|
||||
}
|
||||
|
||||
if( x <= -MAXNUM )
|
||||
{
|
||||
if( y > 0.0 )
|
||||
{
|
||||
#ifdef INFINITIES
|
||||
if( yoddint )
|
||||
return( -INFINITY );
|
||||
return( INFINITY );
|
||||
#else
|
||||
if( yoddint )
|
||||
return( -MAXNUM );
|
||||
return( MAXNUM );
|
||||
#endif
|
||||
}
|
||||
if( y < 0.0 )
|
||||
{
|
||||
#ifdef MINUSZERO
|
||||
if( yoddint )
|
||||
return( NEGZERO );
|
||||
#endif
|
||||
return( 0.0 );
|
||||
}
|
||||
}
|
||||
|
||||
nflg = 0; /* flag = 1 if x<0 raised to integer power */
|
||||
if( x <= 0.0 )
|
||||
{
|
||||
if( x == 0.0 )
|
||||
{
|
||||
if( y < 0.0 )
|
||||
{
|
||||
#ifdef MINUSZERO
|
||||
if( signbit(x) && yoddint )
|
||||
return( -INFINITY );
|
||||
#endif
|
||||
#ifdef INFINITIES
|
||||
return( INFINITY );
|
||||
#else
|
||||
return( MAXNUM );
|
||||
#endif
|
||||
}
|
||||
if( y > 0.0 )
|
||||
{
|
||||
#ifdef MINUSZERO
|
||||
if( signbit(x) && yoddint )
|
||||
return( NEGZERO );
|
||||
#endif
|
||||
return( 0.0 );
|
||||
}
|
||||
return( 1.0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( iyflg == 0 )
|
||||
{ /* noninteger power of negative number */
|
||||
mtherr( fname, DOMAIN );
|
||||
#ifdef NANS
|
||||
return(NAN);
|
||||
#else
|
||||
return(0.0L);
|
||||
#endif
|
||||
}
|
||||
nflg = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Integer power of an integer. */
|
||||
|
||||
if( iyflg )
|
||||
{
|
||||
i = (int)w;
|
||||
w = floor(x);
|
||||
if( (w == x) && (fabs(y) < 32768.0) )
|
||||
{
|
||||
w = c_powi( x, (int) y );
|
||||
return( w );
|
||||
}
|
||||
}
|
||||
|
||||
if( nflg )
|
||||
x = fabs(x);
|
||||
|
||||
/* For results close to 1, use a series expansion. */
|
||||
w = x - 1.0;
|
||||
aw = fabs(w);
|
||||
ay = fabs(y);
|
||||
wy = w * y;
|
||||
ya = fabs(wy);
|
||||
if((aw <= 1.0e-3 && ay <= 1.0)
|
||||
|| (ya <= 1.0e-3 && ay >= 1.0))
|
||||
{
|
||||
z = (((((w*(y-5.)/720. + 1./120.)*w*(y-4.) + 1./24.)*w*(y-3.)
|
||||
+ 1./6.)*w*(y-2.) + 0.5)*w*(y-1.) )*wy + wy + 1.;
|
||||
goto done;
|
||||
}
|
||||
/* These are probably too much trouble. */
|
||||
#if 0
|
||||
w = y * log(x);
|
||||
if (aw > 1.0e-3 && fabs(w) < 1.0e-3)
|
||||
{
|
||||
z = ((((((
|
||||
w/7. + 1.)*w/6. + 1.)*w/5. + 1.)*w/4. + 1.)*w/3. + 1.)*w/2. + 1.)*w + 1.;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if(ya <= 1.0e-3 && aw <= 1.0e-4)
|
||||
{
|
||||
z = (((((
|
||||
wy*1./720.
|
||||
+ (-w*1./48. + 1./120.) )*wy
|
||||
+ ((w*17./144. - 1./12.)*w + 1./24.) )*wy
|
||||
+ (((-w*5./16. + 7./24.)*w - 1./4.)*w + 1./6.) )*wy
|
||||
+ ((((w*137./360. - 5./12.)*w + 11./24.)*w - 1./2.)*w + 1./2.) )*wy
|
||||
+ (((((-w*1./6. + 1./5.)*w - 1./4)*w + 1./3.)*w -1./2.)*w ) )*wy
|
||||
+ wy + 1.0;
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* separate significand from exponent */
|
||||
x = frexp( x, &e );
|
||||
|
||||
#if 0
|
||||
/* For debugging, check for gross overflow. */
|
||||
if( (e * y) > (MEXP + 1024) )
|
||||
goto overflow;
|
||||
#endif
|
||||
|
||||
/* Find significand of x in antilog table A[]. */
|
||||
i = 1;
|
||||
if( x <= douba(9) )
|
||||
i = 9;
|
||||
if( x <= douba(i+4) )
|
||||
i += 4;
|
||||
if( x <= douba(i+2) )
|
||||
i += 2;
|
||||
if( x >= douba(1) )
|
||||
i = -1;
|
||||
i += 1;
|
||||
|
||||
|
||||
/* Find (x - A[i])/A[i]
|
||||
* in order to compute log(x/A[i]):
|
||||
*
|
||||
* log(x) = log( a x/a ) = log(a) + log(x/a)
|
||||
*
|
||||
* log(x/a) = log(1+v), v = x/a - 1 = (x-a)/a
|
||||
*/
|
||||
x -= douba(i);
|
||||
x -= doubb(i/2);
|
||||
x /= douba(i);
|
||||
|
||||
|
||||
/* rational approximation for log(1+v):
|
||||
*
|
||||
* log(1+v) = v - v**2/2 + v**3 P(v) / Q(v)
|
||||
*/
|
||||
z = x*x;
|
||||
w = x * ( z * polevl( x, P, 3 ) / p1evl( x, Q, 4 ) );
|
||||
w = w - ldexp( z, -1 ); /* w - 0.5 * z */
|
||||
|
||||
/* Convert to base 2 logarithm:
|
||||
* multiply by log2(e)
|
||||
*/
|
||||
w = w + LOG2EA * w;
|
||||
/* Note x was not yet added in
|
||||
* to above rational approximation,
|
||||
* so do it now, while multiplying
|
||||
* by log2(e).
|
||||
*/
|
||||
z = w + LOG2EA * x;
|
||||
z = z + x;
|
||||
|
||||
/* Compute exponent term of the base 2 logarithm. */
|
||||
w = -i;
|
||||
w = ldexp( w, -4 ); /* divide by 16 */
|
||||
w += e;
|
||||
/* Now base 2 log of x is w + z. */
|
||||
|
||||
/* Multiply base 2 log by y, in extended precision. */
|
||||
|
||||
/* separate y into large part ya
|
||||
* and small part yb less than 1/16
|
||||
*/
|
||||
ya = reduc(y);
|
||||
yb = y - ya;
|
||||
|
||||
|
||||
F = z * y + w * yb;
|
||||
Fa = reduc(F);
|
||||
Fb = F - Fa;
|
||||
|
||||
G = Fa + w * ya;
|
||||
Ga = reduc(G);
|
||||
Gb = G - Ga;
|
||||
|
||||
H = Fb + Gb;
|
||||
Ha = reduc(H);
|
||||
w = ldexp( Ga+Ha, 4 );
|
||||
|
||||
/* Test the power of 2 for overflow */
|
||||
if( w > MEXP )
|
||||
{
|
||||
#ifndef INFINITIES
|
||||
mtherr( fname, OVERFLOW );
|
||||
#endif
|
||||
#ifdef INFINITIES
|
||||
if( nflg && yoddint )
|
||||
return( -INFINITY );
|
||||
return( INFINITY );
|
||||
#else
|
||||
if( nflg && yoddint )
|
||||
return( -MAXNUM );
|
||||
return( MAXNUM );
|
||||
#endif
|
||||
}
|
||||
|
||||
if( w < (MNEXP - 1) )
|
||||
{
|
||||
#ifndef DENORMAL
|
||||
mtherr( fname, UNDERFLOW );
|
||||
#endif
|
||||
#ifdef MINUSZERO
|
||||
if( nflg && yoddint )
|
||||
return( NEGZERO );
|
||||
#endif
|
||||
return( 0.0 );
|
||||
}
|
||||
|
||||
e = (int)w;
|
||||
Hb = H - Ha;
|
||||
|
||||
if( Hb > 0.0 )
|
||||
{
|
||||
e += 1;
|
||||
Hb -= 0.0625;
|
||||
}
|
||||
|
||||
/* Now the product y * log2(x) = Hb + e/16.0.
|
||||
*
|
||||
* Compute base 2 exponential of Hb,
|
||||
* where -0.0625 <= Hb <= 0.
|
||||
*/
|
||||
z = Hb * polevl( Hb, R, 6 ); /* z = 2**Hb - 1 */
|
||||
|
||||
/* Express e/16 as an integer plus a negative number of 16ths.
|
||||
* Find lookup table entry for the fractional power of 2.
|
||||
*/
|
||||
if( e < 0 )
|
||||
i = 0;
|
||||
else
|
||||
i = 1;
|
||||
i = e/16 + i;
|
||||
e = 16*i - e;
|
||||
w = douba( e );
|
||||
z = w + w * z; /* 2**-e * ( 1 + (2**Hb-1) ) */
|
||||
z = ldexp( z, i ); /* multiply by integer power of 2 */
|
||||
|
||||
done:
|
||||
|
||||
/* Negate if odd integer power of negative number */
|
||||
if( nflg && yoddint )
|
||||
{
|
||||
#ifdef MINUSZERO
|
||||
if( z == 0.0 )
|
||||
z = NEGZERO;
|
||||
else
|
||||
#endif
|
||||
z = -z;
|
||||
}
|
||||
return( z );
|
||||
}
|
||||
|
||||
|
||||
/* Find a multiple of 1/16 that is within 1/16 of x. */
|
||||
static double reduc(x)
|
||||
double x;
|
||||
{
|
||||
double t;
|
||||
|
||||
t = ldexp( x, 4 );
|
||||
t = floor( t );
|
||||
t = ldexp( t, -4 );
|
||||
return(t);
|
||||
}
|
186
src/math/powi.c
Normal file
186
src/math/powi.c
Normal file
|
@ -0,0 +1,186 @@
|
|||
/* powi.c
|
||||
*
|
||||
* Real raised to integer power
|
||||
*
|
||||
*
|
||||
*
|
||||
* SYNOPSIS:
|
||||
*
|
||||
* double x, y, powi();
|
||||
* int n;
|
||||
*
|
||||
* y = powi( x, n );
|
||||
*
|
||||
*
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Returns argument x raised to the nth power.
|
||||
* The routine efficiently decomposes n as a sum of powers of
|
||||
* two. The desired power is a product of two-to-the-kth
|
||||
* powers of x. Thus to compute the 32767 power of x requires
|
||||
* 28 multiplications instead of 32767 multiplications.
|
||||
*
|
||||
*
|
||||
*
|
||||
* ACCURACY:
|
||||
*
|
||||
*
|
||||
* Relative error:
|
||||
* arithmetic x domain n domain # trials peak rms
|
||||
* DEC .04,26 -26,26 100000 2.7e-16 4.3e-17
|
||||
* IEEE .04,26 -26,26 50000 2.0e-15 3.8e-16
|
||||
* IEEE 1,2 -1022,1023 50000 8.6e-14 1.6e-14
|
||||
*
|
||||
* Returns MAXNUM on overflow, zero on underflow.
|
||||
*
|
||||
*/
|
||||
|
||||
/* powi.c */
|
||||
|
||||
/*
|
||||
Cephes Math Library Release 2.8: June, 2000
|
||||
Copyright 1984, 1995, 2000 by Stephen L. Moshier
|
||||
*/
|
||||
|
||||
#include "mconf.h"
|
||||
#ifdef ANSIPROT
|
||||
extern double log ( double );
|
||||
extern double frexp ( double, int * );
|
||||
extern int signbit ( double );
|
||||
#else
|
||||
double log(), frexp();
|
||||
int signbit();
|
||||
#endif
|
||||
extern double NEGZERO, INFINITY, MAXNUM, MAXLOG, MINLOG, LOGE2;
|
||||
|
||||
double c_powi( x, nn )
|
||||
double x;
|
||||
int nn;
|
||||
{
|
||||
int n, e, sign, asign, lx;
|
||||
double w, y, s;
|
||||
|
||||
/* See pow.c for these tests. */
|
||||
if( x == 0.0 )
|
||||
{
|
||||
if( nn == 0 )
|
||||
return( 1.0 );
|
||||
else if( nn < 0 )
|
||||
return( INFINITY );
|
||||
else
|
||||
{
|
||||
if( nn & 1 )
|
||||
return( x );
|
||||
else
|
||||
return( 0.0 );
|
||||
}
|
||||
}
|
||||
|
||||
if( nn == 0 )
|
||||
return( 1.0 );
|
||||
|
||||
if( nn == -1 )
|
||||
return( 1.0/x );
|
||||
|
||||
if( x < 0.0 )
|
||||
{
|
||||
asign = -1;
|
||||
x = -x;
|
||||
}
|
||||
else
|
||||
asign = 0;
|
||||
|
||||
|
||||
if( nn < 0 )
|
||||
{
|
||||
sign = -1;
|
||||
n = -nn;
|
||||
}
|
||||
else
|
||||
{
|
||||
sign = 1;
|
||||
n = nn;
|
||||
}
|
||||
|
||||
/* Even power will be positive. */
|
||||
if( (n & 1) == 0 )
|
||||
asign = 0;
|
||||
|
||||
/* Overflow detection */
|
||||
|
||||
/* Calculate approximate logarithm of answer */
|
||||
s = frexp( x, &lx );
|
||||
e = (lx - 1)*n;
|
||||
if( (e == 0) || (e > 64) || (e < -64) )
|
||||
{
|
||||
s = (s - 7.0710678118654752e-1) / (s + 7.0710678118654752e-1);
|
||||
s = (2.9142135623730950 * s - 0.5 + lx) * nn * LOGE2;
|
||||
}
|
||||
else
|
||||
{
|
||||
s = LOGE2 * e;
|
||||
}
|
||||
|
||||
if( s > MAXLOG )
|
||||
{
|
||||
mtherr( "powi", OVERFLOW );
|
||||
y = INFINITY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
#if DENORMAL
|
||||
if( s < MINLOG )
|
||||
{
|
||||
y = 0.0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Handle tiny denormal answer, but with less accuracy
|
||||
* since roundoff error in 1.0/x will be amplified.
|
||||
* The precise demarcation should be the gradual underflow threshold.
|
||||
*/
|
||||
if( (s < (-MAXLOG+2.0)) && (sign < 0) )
|
||||
{
|
||||
x = 1.0/x;
|
||||
sign = -sign;
|
||||
}
|
||||
#else
|
||||
/* do not produce denormal answer */
|
||||
if( s < -MAXLOG )
|
||||
return(0.0);
|
||||
#endif
|
||||
|
||||
|
||||
/* First bit of the power */
|
||||
if( n & 1 )
|
||||
y = x;
|
||||
|
||||
else
|
||||
y = 1.0;
|
||||
|
||||
w = x;
|
||||
n >>= 1;
|
||||
while( n )
|
||||
{
|
||||
w = w * w; /* arg to the 2-to-the-kth power */
|
||||
if( n & 1 ) /* if that bit is set, then include in product */
|
||||
y *= w;
|
||||
n >>= 1;
|
||||
}
|
||||
|
||||
if( sign < 0 )
|
||||
y = 1.0/y;
|
||||
|
||||
done:
|
||||
|
||||
if( asign )
|
||||
{
|
||||
/* odd power of negative number */
|
||||
if( y == 0.0 )
|
||||
y = NEGZERO;
|
||||
else
|
||||
y = -y;
|
||||
}
|
||||
return(y);
|
||||
}
|
|
@ -1824,14 +1824,17 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric)
|
|||
{
|
||||
ValueType = TypeBool;
|
||||
}
|
||||
else if (left->IsNumeric() && right->IsNumeric())
|
||||
{
|
||||
if (left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_INT)
|
||||
{
|
||||
ValueType = TypeSInt32;
|
||||
}
|
||||
else if (left->IsNumeric() && right->IsNumeric())
|
||||
else
|
||||
{
|
||||
ValueType = TypeFloat64;
|
||||
}
|
||||
}
|
||||
else if (left->ValueType->GetRegType() == REGT_POINTER && left->ValueType == right->ValueType)
|
||||
{
|
||||
ValueType = left->ValueType;
|
||||
|
@ -2137,6 +2140,60 @@ ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FxPow::FxPow(FxExpression *l, FxExpression *r)
|
||||
: FxBinary(TK_MulMul, new FxFloatCast(l), new FxFloatCast(r))
|
||||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxExpression *FxPow::Resolve(FCompileContext& ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
|
||||
if (!ResolveLR(ctx, true)) return NULL;
|
||||
|
||||
if (left->isConstant() && right->isConstant())
|
||||
{
|
||||
double v1 = static_cast<FxConstant *>(left)->GetValue().GetFloat();
|
||||
double v2 = static_cast<FxConstant *>(right)->GetValue().GetFloat();
|
||||
return new FxConstant(g_pow(v1, v2), left->ScriptPosition);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
ExpEmit FxPow::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
ExpEmit op1 = left->Emit(build);
|
||||
ExpEmit op2 = right->Emit(build);
|
||||
|
||||
// Pow is not commutative, so either side may be constant (but not both).
|
||||
assert(!op1.Konst || !op2.Konst);
|
||||
op1.Free(build);
|
||||
op2.Free(build);
|
||||
assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT);
|
||||
ExpEmit to(build, REGT_FLOAT);
|
||||
build->Emit((op1.Konst ? OP_POWF_KR : op2.Konst ? OP_POWF_RK : OP_POWF_RR), to.RegNum, op1.RegNum, op2.RegNum);
|
||||
return to;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxCompareRel::FxCompareRel(int o, FxExpression *l, FxExpression *r)
|
||||
: FxBinary(o, l, r)
|
||||
{
|
||||
|
|
|
@ -686,6 +686,21 @@ public:
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxPow : public FxBinary
|
||||
{
|
||||
public:
|
||||
|
||||
FxPow(FxExpression*, FxExpression*);
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxBinary
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxCompareRel : public FxBinary
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -1055,15 +1055,15 @@ begin:
|
|||
|
||||
OP(POWF_RR):
|
||||
ASSERTF(a); ASSERTF(B); ASSERTF(C);
|
||||
reg.f[a] = pow(reg.f[B], reg.f[C]);
|
||||
reg.f[a] = g_pow(reg.f[B], reg.f[C]);
|
||||
NEXTOP;
|
||||
OP(POWF_RK):
|
||||
ASSERTF(a); ASSERTF(B); ASSERTKF(C);
|
||||
reg.f[a] = pow(reg.f[B], konstf[C]);
|
||||
reg.f[a] = g_pow(reg.f[B], konstf[C]);
|
||||
NEXTOP;
|
||||
OP(POWF_KR):
|
||||
ASSERTF(a); ASSERTKF(B); ASSERTF(C);
|
||||
reg.f[a] = pow(konstf[B], reg.f[C]);
|
||||
reg.f[a] = g_pow(konstf[B], reg.f[C]);
|
||||
NEXTOP;
|
||||
|
||||
OP(MINF_RR):
|
||||
|
|
|
@ -2422,6 +2422,9 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
|
|||
case PEX_Mod:
|
||||
return new FxMulDiv(op == PEX_Mul ? '*' : op == PEX_Div ? '/' : '%', left, right);
|
||||
|
||||
case PEX_Pow:
|
||||
return new FxPow(left, right);
|
||||
|
||||
default:
|
||||
I_Error("Binary operator %d not implemented yet", op);
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "m_alloc.h"
|
||||
#include "zcc_parser.h"
|
||||
#include "templates.h"
|
||||
#include "math/cmath.h"
|
||||
|
||||
#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b))
|
||||
|
||||
|
@ -332,7 +333,7 @@ void ZCC_InitOperators()
|
|||
{ PEX_Mod , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal %= r->UIntVal; return l; } },
|
||||
{ PEX_Mod , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal = luai_nummod(l->DoubleVal, r->DoubleVal); return l; } },
|
||||
|
||||
{ PEX_Pow , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal = pow(l->DoubleVal, r->DoubleVal); return l; } },
|
||||
{ PEX_Pow , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal = g_pow(l->DoubleVal, r->DoubleVal); return l; } },
|
||||
|
||||
{ PEX_Concat , (PType **)&TypeString, (PType **)&TypeString, (PType **)&TypeString, EvalConcat },
|
||||
|
||||
|
|
Loading…
Reference in a new issue