Cosmos/source/Cosmos.System2_Plugs/System/MathImpl.cs

1733 lines
61 KiB
C#

using System;
using Cosmos.Debug.Kernel;
using IL2CPU.API;
using IL2CPU.API.Attribs;
namespace Cosmos.System_Plugs.System
{
[Plug(Target = typeof(Math))]
public static class MathImpl
{
/* @(#)fdlibm.h 1.5 04/04/22 */
/*
* ====================================================
* Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
*
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
//Following functions which have been implemented in this file are functions taken from http://www.netlib.org/fdlibm/ and have then be changed to work in C#
//Acos, Asin, Cos, _cos, __ieee754_rem_pio2, __kernel_rem_pio2, Scalbn, Log base e, Sin, _sin, exp, atan
internal static Debugger mDebugger = new Debugger("System", "Math Plugs");
#region Internal Constants
private const double sq2p1 = 2.414213562373095048802e0F;
private const double sq2m1 = .414213562373095048802e0F;
private const double pio2 = 1.570796326794896619231e0F;
private const double pio4 = .785398163397448309615e0F;
private const double log2e = 1.4426950408889634073599247F;
private const double sqrt2 = 1.4142135623730950488016887F;
private const double ln2 = 6.93147180559945286227e-01F;
private const double atan_p4 = .161536412982230228262e2F;
private const double atan_p3 = .26842548195503973794141e3F;
private const double atan_p2 = .11530293515404850115428136e4F;
private const double atan_p1 = .178040631643319697105464587e4F;
private const double atan_p0 = .89678597403663861959987488e3F;
private const double atan_q4 = .5895697050844462222791e2F;
private const double atan_q3 = .536265374031215315104235e3F;
private const double atan_q2 = .16667838148816337184521798e4F;
private const double atan_q1 = .207933497444540981287275926e4F;
private const double atan_q0 = .89678597403663861962481162e3F;
#endregion Internal Constants
public const double PI = 3.1415926535897932384626433832795;
public const double E = 2.71828182845904523536;
#region Abs
public static double Abs(double value)
{
if (value < 0)
{
return -value;
}
else
{
return value;
}
}
public static float Abs(float value)
{
if (value < 0)
{
return -value;
}
else
{
return value;
}
}
#endregion Abs
#region Acos
public static double Acos(double x)
{
double pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
double z, p, q, r, w, s, c, df;
int hx, ix;
hx = HighWord(x);
ix = hx & 0x7fffffff;
if (ix >= 0x3ff00000)
{ /* |x| >= 1 */
if (((ix - 0x3ff00000) | LowWord(x)) == 0)
{ /* |x|==1 */
if (hx > 0)
return 0.0; /* acos(1) = 0 */
else
return Math.PI + 2.0 * pio2_lo; /* acos(-1)= pi */
}
return (x - x) / (x - x); /* acos(|x|>1) is NaN */
}
if (ix < 0x3fe00000)
{ /* |x| < 0.5 */
if (ix <= 0x3c600000)
return pio2_hi + pio2_lo;/*if|x|<2**-57*/
z = x * x;
p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
q = 1 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
r = p / q;
return pio2_hi - (x - (pio2_lo - x * r));
}
else if (hx < 0)
{ /* x < -0.5 */
z = (1 + x) * 0.5;
p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
q = 1 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
s = Sqrt(z);
r = p / q;
w = r * s - pio2_lo;
return Math.PI - 2.0 * (s + w);
}
else
{ /* x > 0.5 */
z = (1 - x) * 0.5;
s = Sqrt(z);
df = s;
//__LO(df) = 0;
Byte[] bdf = BitConverter.GetBytes(BitConverter.DoubleToInt64Bits(df));
for (int i = 0; i < 4; i++)
{
bdf[i + (BitConverter.IsLittleEndian ? 4 : 0)] = 0;
}
df = BitConverter.ToDouble(bdf, 0);
c = (z - df * df) / (s + df);
p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
q = 1 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
r = p / q;
w = r * s + c;
return 2.0 * (df + w);
}
}
#endregion Acos
#region Asin
public static double Asin(double x)
{
double huge = 1.000e+300,
pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
pio4_hi = 7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */
/* coefficient for R(x^2) */
pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
double t = 0, w, p, q, c, r, s;
int hx, ix;
hx = HighWord(x);
ix = hx & 0x7fffffff;
if (ix >= 0x3ff00000)
{ /* |x|>= 1 */
if (((ix - 0x3ff00000) | LowWord(x)) == 0)
/* asin(1)=+-pi/2 with inexact */
return x * pio2_hi + x * pio2_lo;
return (x - x) / (x - x); /* asin(|x|>1) is NaN */
}
else if (ix < 0x3fe00000)
{ /* |x|<0.5 */
if (ix < 0x3e400000)
{ /* if |x| < 2**-27 */
if (huge + x > 1) return x;/* return x with inexact if x!=0*/
}
else
t = x * x;
p = t * (pS0 + t * (pS1 + t * (pS2 + t * (pS3 + t * (pS4 + t * pS5)))));
q = 1 + t * (qS1 + t * (qS2 + t * (qS3 + t * qS4)));
w = p / q;
return x + x * w;
}
/* 1> |x|>= 0.5 */
w = 1 - Abs(x);
t = w * 0.5;
p = t * (pS0 + t * (pS1 + t * (pS2 + t * (pS3 + t * (pS4 + t * pS5)))));
q = 1 + t * (qS1 + t * (qS2 + t * (qS3 + t * qS4)));
s = Sqrt(t);
if (ix >= 0x3FEF3333)
{ /* if |x| > 0.975 */
w = p / q;
t = pio2_hi - (2.0 * (s + s * w) - pio2_lo);
}
else
{
w = s;
//__LO(w) = 0;
Byte[] bw = BitConverter.GetBytes(BitConverter.DoubleToInt64Bits(w));
for (int i = 0; i < 4; i++)
{
bw[i + (BitConverter.IsLittleEndian ? 4 : 0)] = 0;
}
w = BitConverter.ToDouble(bw, 0);
c = (t - w * w) / (s + w);
r = p / q;
p = 2.0 * s * r - (pio2_lo - 2.0 * c);
q = pio4_hi - 2.0 * w;
t = pio4_hi - (p - q);
}
if (hx > 0) return t; else return -t;
}
#endregion Asin
#region Atan
public static double Atan(double x)
{
if (double.IsNaN(x)) return double.NaN;
if (double.IsPositiveInfinity(x)) return Math.PI / 2;
if (double.IsNegativeInfinity(x)) return -Math.PI / 2;
double w, s1, s2, z;
int ix, hx, id;
double[] atanhi = {
4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */
7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */
9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */
1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */
};
double[] atanlo = {
2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */
3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */
1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */
6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */
};
double[] aT = {
3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */
-1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */
1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */
-1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */
9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */
-7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */
6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */
-5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */
4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */
-3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */
1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */
};
hx = HighWord(x);
ix = hx & 0x7fffffff;
if (ix >= 0x44100000)
{ /* if |x| >= 2^66 */
if (ix > 0x7ff00000 ||
(ix == 0x7ff00000 && (LowWord(x) != 0)))
return x + x; /* NaN */
if (hx > 0) return atanhi[3] + atanlo[3];
else return -atanhi[3] - atanlo[3];
}
if (ix < 0x3fdc0000)
{ /* |x| < 0.4375 */
if (ix < 0x3e200000)
{ /* |x| < 2^-29 */
if (1.0e+300 + x > 1) return x; /* raise inexact */
}
id = -1;
}
else
{
x = Math.Abs(x);
if (ix < 0x3ff30000)
{ /* |x| < 1.1875 */
if (ix < 0x3fe60000)
{ /* 7/16 <=|x|<11/16 */
id = 0; x = (2.0 * x - 1) / (2.0 + x);
}
else
{ /* 11/16<=|x|< 19/16 */
id = 1; x = (x - 1) / (x + 1);
}
}
else
{
if (ix < 0x40038000)
{ /* |x| < 2.4375 */
id = 2; x = (x - 1.5) / (1 + 1.5 * x);
}
else
{ /* 2.4375 <= |x| < 2^66 */
id = 3; x = -1.0 / x;
}
}
}
/* end of argument reduction */
z = x * x;
w = z * z;
/* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
s1 = z * (aT[0] + w * (aT[2] + w * (aT[4] + w * (aT[6] + w * (aT[8] + w * aT[10])))));
s2 = w * (aT[1] + w * (aT[3] + w * (aT[5] + w * (aT[7] + w * aT[9]))));
if (id < 0) return x - x * (s1 + s2);
else
{
z = atanhi[id] - ((x * (s1 + s2) - atanlo[id]) - x);
return (hx < 0) ? -z : z;
}
}
#endregion Atan
#region Atan2
public static double Atan2(double x, double y)
{
if ((x + y) == x)
{
if ((x == 0F) & (y == 0F))
return 0F;
if (x >= 0.0F)
return pio2;
return (-pio2);
}
if (y < 0.0F)
{
if (x >= 0.0F)
return ((pio2 * 2) - atans((-x) / y));
return (((-pio2) * 2) + atans(x / y));
}
if (x > 0.0F)
{
return (atans(x / y));
}
return (-atans((-x) / y));
//return (((x + y) == x) ? (((x == 0F) & (y == 0F)) ? 0F : ((x >= 0F) ? pio2 : (-pio2))) : ((y < 0F) ? ((x >= 0F) ? ((pio2 * 2) - atans((-x) / y)) : (((-pio2) * 2) + atans(x / y))) : ((x > 0F) ? atans(x / y) : -atans((-x) / y))));
}
#endregion Atan2
#region Ceiling
public static double Ceiling(double x)
{
if (double.IsNaN(x) || double.IsInfinity(x)) return x;
double huge = 1.0e+300;
int i0, i1, j0;
uint i, j;
i0 = HighWord(x);
i1 = LowWord(x);
j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
if (j0 < 20)
{
if (j0 < 0)
{ /* raise inexact if x != 0 */
if (huge + x > 0.0)
{/* return 0*sign(x) if |x|<1 */
if (i0 < 0)
{
i0 = (int)(0x80000000 - 1); //Cant set 0x80000000 to int
i1 = 0;
}
else if ((i0 | i1) != 0)
{
i0 = 0x3ff00000;
i1 = 0;
}
}
}
else
{
i = (uint)(0x000fffff) >> j0;
if (((i0 & i) | i1) == 0) return x; /* x is integral */
if (huge + x > 0.0)
{ /* raise inexact flag */
if (i0 > 0)
i0 += (0x00100000) >> j0;
i0 &= (int)~i;
i1 = 0;
}
}
}
else if (j0 > 51)
{
if (j0 == 0x400) return x + x; /* inf or NaN */
else return x; /* x is integral */
}
else
{
i = 0xffffffff >> (j0 - 20);
if ((i1 & i) == 0) return x; /* x is integral */
if (huge + x > 0.0)
{ /* raise inexact flag */
if (i0 > 0)
{
if (j0 == 20) i0 += 1;
else
{
j = (uint)(i1 + (1 << (52 - j0)));
if (j < i1) i0 += 1; /* got a carry */
i1 = (int)j;
}
}
i1 &= (int)~i;
}
}
Byte[] returnBytes = BitConverter.GetBytes(0d);
Byte[] highWord = BitConverter.GetBytes(i0);
Byte[] lowWord = BitConverter.GetBytes(i1);
for (int c = 0; c < 4; c++)
{
returnBytes[c + (BitConverter.IsLittleEndian ? 4 : 0)] = highWord[c];
}
for (int c = 0; c < 4; c++)
{
returnBytes[c + (BitConverter.IsLittleEndian ? 0 : 4)] = lowWord[c];
}
return BitConverter.ToDouble(returnBytes, 0);
}
#endregion Ceiling
#region Cos
public static double Cos(double x)
{
double[] y = new double[2];
double z = 0.0;
int n, ix;
/* High word of x. */
ix = HighWord(x);
/* |x| ~< pi/4 */
ix &= 0x7fffffff;
if (ix <= 0x3fe921fb) return _cos(x, z);
/* cos(Inf or NaN) is NaN */
else if (ix >= 0x7ff00000) return x - x;
/* argument reduction needed */
else
{
n = __ieee754_rem_pio2(x, y);
switch (n & 3)
{
case 0:
return _cos(y[0], y[1]);
case 1:
return -_sin(y[0], y[1], 1);
case 2:
return -_cos(y[0], y[1]);
default:
return _sin(y[0], y[1], 1);
}
}
}
private static double _cos(double x, double y)
{
const double one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */
C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */
C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */
C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */
C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */
C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
double a, hz, z, r, qx = 0;
int ix;
ix = HighWord(x) & 0x7fffffff; /* ix = |x|'s high word*/
if (ix < 0x3e400000)
{ /* if x < 2**27 */
if (((int)x) == 0)
return one; /* generate inexact */
}
z = x * x;
r = z * (C1 + z * (C2 + z * (C3 + z * (C4 + z * (C5 + z * C6)))));
if (ix < 0x3FD33333) /* if |x| < 0.3 */
return one - (0.5 * z - (z * r - x * y));
else
{
if (ix > 0x3fe90000)
{ /* x > 0.78125 */
qx = 0.28125;
}
else
{
//__HI(qx) = ix - 0x00200000; /* x/4 */
Byte[] bqx = BitConverter.GetBytes(BitConverter.DoubleToInt64Bits(qx));
Byte[] bvh = BitConverter.GetBytes(ix - 0x00200000);
for (int i = 0; i < 4; i++)
{
bqx[i + (BitConverter.IsLittleEndian ? 4 : 0)] = bvh[i];
}
//__LO(qx) = 0;
for (int i = 0; i < 4; i++)
{
bqx[i + (BitConverter.IsLittleEndian ? 4 : 0)] = 0;
}
}
hz = 0.5 * z - qx;
a = one - qx;
return a - (hz - (z * r - x * y));
}
}
#endregion Cos
#region Cosh
public static double Cosh(double x)
{
if (x < 0.0F)
x = -x;
return ((x == 0F) ? 1F : ((x <= (ln2 / 2)) ? (1 + (_power((Exp(x) - 1), 2) / (2 * Exp(x)))) : ((x <= 22F) ? ((Exp(x) + (1 / Exp(x))) / 2) : (0.5F * (Exp(x) + Exp(-x))))));
}
#endregion Cosh
#region Exp
public static double Exp(double x)
{
double y, hi = 0, lo = 0, c, t;
int k = 0, xsb;
const double o_threshold = 7.09782712893383973096e+02;
const double u_threshold = -7.45133219101941108420e+02;
const double invln2 = 1.44269504088896338700e+00;
const double twom1000 = 9.33263618503218878990e-302;
const double P1 = 1.66666666666666019037e-01;
const double P2 = -2.77777777770155933842e-03;
const double P3 = 6.61375632143793436117e-05;
const double P4 = -1.65339022054652515390e-06;
const double P5 = 4.13813679705723846039e-08;
const double huge = 1.0e+300;
int hx = HighWord(x); //Highword of x
xsb = ((int)hx >> 31) & 1; //Get sign of x
hx &= 0x7fffffff; //Get the abs(x) of the highword
//Check if non-finite argument
if (hx >= 0x40862E42)
{ /* if |x|>=709.78... */
if (hx >= 0x7ff00000)
{
if (((hx & 0xfffff) | LowWord(x)) != 0) //Assume that __Lo(x) is lower word of x
return x; /* NaN */
else
return (xsb == 0) ? x : 0.0; /* exp(+-inf)={inf,0} */
}
if (x > o_threshold)
return double.PositiveInfinity; /* overflow */
if (x < u_threshold)
return 0; /* underflow */
}
/* argument reduction */
if (hx > 0x3fd62e42)
{ /* if |x| > 0.5 ln2 */
if (hx < 0x3FF0A2B2)
{ /* and |x| < 1.5 ln2 */
if (xsb == 0)
{
hi = x - 6.93147180369123816490e-01;
lo = 1.90821492927058770002e-10;
}
else
{
hi = x - -6.93147180369123816490e-01;
lo = -1.90821492927058770002e-10;
}
k = 1 - xsb - xsb;
}
else
{
if (xsb == 0)
k = (int)(invln2 * x + 0.5);
else
k = (int)(invln2 * x + -0.5);
t = k;
hi = x - t * 6.93147180369123816490e-01;
lo = t * 1.90821492927058770002e-10;
}
x = hi - lo;
}
else if (hx < 0x3e300000)
{ /* when |x|<2**-28 */
if (huge + x > 1)
return 1 + x;/* trigger inexact */
}
else
k = 0;
/* x is now in primary range */
t = x * x;
c = x - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5))));
if (k == 0)
return 1 - ((x * c) / (c - 2.0) - x);
else
y = 1 - ((lo - (x * c) / (2.0 - c)) - hi);
if (k >= -1021)
{
//The idea is to add hy to the exponent of y
long _y = BitConverter.DoubleToInt64Bits(y);
/* add k to y's exponent */
if (BitConverter.IsLittleEndian)
_y += ((long)k << 52);
else
_y += ((long)k << 20);
y = BitConverter.Int64BitsToDouble(_y);
return y;
}
else
{
//The idea is to add hy to the exponent of y
long _y = BitConverter.DoubleToInt64Bits(y);
if (BitConverter.IsLittleEndian)
_y += ((long)k + 1000 << 52);
else
_y += ((long)k + 1000 << 20);
y = BitConverter.Int64BitsToDouble(_y);
return y * twom1000;
}
}
#endregion Exp
#region Floor
public static double Floor(double x)
{
if (double.IsInfinity(x) || double.IsNaN(x)) return x;
int i0, i1, j0;
uint i, j;
i0 = HighWord(x);
i1 = LowWord(x);
j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
if (j0 < 20)
{
if (j0 < 0)
{ /* raise inexact if x != 0 */
if (1.0e+300 + x > 0.0)
{/* return 0*sign(x) if |x|<1 */
if (i0 >= 0)
{
i0 = i1 = 0;
}
else if (((i0 & 0x7fffffff) | i1) != 0)
{
i0 = Int32.MaxValue;
i1 = 0;
}
}
}
else
{
i = (uint)0x000fffff >> j0;
if ((((uint)i0 & i) | (uint)i1) == 0)
return x; /* x is integral */
if (1.0e+300 + x > 0.0)
{ /* raise inexact flag */
if (i0 < 0)
i0 += (0x00100000) >> j0;
i0 &= (int)~i;
i1 = 0;
}
}
}
else if (j0 > 51)
{
if (j0 == 0x400) return x + x; /* inf or NaN */
else return x; /* x is integral */
}
else
{
i = ((uint)(0xffffffff)) >> (j0 - 20);
if ((i1 & i) == 0) return x; /* x is integral */
if (1.0e+300 + x > 0.0)
{ /* raise inexact flag */
if (i0 < 0)
{
if (j0 == 20) i0 += 1;
else
{
j = (uint)i1 + (uint)(1 << (52 - j0));
if (j < i1) i0 += 1; /* got a carry */
i1 = (int)j;
}
}
i1 &= (int)~i;
}
}
Byte[] returnBytes = BitConverter.GetBytes(0d);
Byte[] highWord = BitConverter.GetBytes(i0);
Byte[] lowWord = BitConverter.GetBytes(i1);
for (int c = 0; c < 4; c++)
{
returnBytes[c + (BitConverter.IsLittleEndian ? 4 : 0)] = highWord[c];
}
for (int c = 0; c < 4; c++)
{
returnBytes[c + (BitConverter.IsLittleEndian ? 0 : 4)] = lowWord[c];
}
return BitConverter.ToDouble(returnBytes, 0);
}
#endregion Floor
#region Log (base e)
public static double Log(double x)
{
double ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */
Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
double hfsq, f, s, z, R, w, t1, t2, dk;
int k, hx, i, j;
uint lx;
hx = HighWord(x); /* high word of x */
lx = (uint)LowWord(x); /* low word of x */
k = 0;
if (hx < 0x00100000)
{ /* x < 2**-1022 */
if (x < 0 || double.IsNaN(x))
return double.NaN; /* log(-#) = NaN */
if (((hx & (uint)0x7fff) | lx) == 0)
return double.NegativeInfinity; /* log(+-0)=-inf */
k -= 54; x *= two54; /* subnormal number, scale up x */
hx = HighWord(x); /* high word of x */
}
if (hx >= 0x7ff00000) return x + x;
k += (hx >> 20) - 1023;
hx &= 0x000fffff;
i = (hx + 0x95f64) & 0x100000;
//__HI(x) = hx | (i ^ 0x3ff00000); /* normalize x or x/2 */
Byte[] bx = BitConverter.GetBytes(BitConverter.DoubleToInt64Bits(x));
Byte[] bv = BitConverter.GetBytes(hx | (i ^ 0x3ff00000));
for (int _i = 0; _i < 4; _i++)
{
bx[_i + (BitConverter.IsLittleEndian ? 4 : 0)] = bv[_i];
}
x = BitConverter.ToDouble(bx, 0);
k += (i >> 20);
f = x - 1.0;
if ((0x000fffff & (2 + hx)) < 3)
{ /* |f| < 2**-20 */
if (f == 0)
if (k == 0)
return 0;
else
{
dk = k;
return dk * ln2_hi + dk * ln2_lo;
}
R = f * f * (0.5 - 0.33333333333333333 * f);
if (k == 0)
return f - R;
else
{
dk = k;
return dk * ln2_hi - ((R - dk * ln2_lo) - f);
}
}
s = f / (2.0 + f);
dk = k;
z = s * s;
i = hx - 0x6147a;
w = z * z;
j = 0x6b851 - hx;
t1 = w * (Lg2 + w * (Lg4 + w * Lg6));
t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7)));
i |= j;
R = t2 + t1;
if (i > 0)
{
hfsq = 0.5 * f * f;
if (k == 0)
return f - (hfsq - s * (hfsq + R));
else
return dk * ln2_hi - ((hfsq - (s * (hfsq + R) + dk * ln2_lo)) - f);
}
else
{
if (k == 0)
return f - s * (f - R);
else
return dk * ln2_hi - ((s * (f - R) - dk * ln2_lo) - f);
}
}
#endregion Log (base e)
#region Log (base specified)
public static double Log(double Exponent, double Base)
{
if (double.IsNaN(Exponent) || Exponent < 0)
return double.NaN;
if (Exponent == 0)
return double.NegativeInfinity;
return Log(Exponent) / Log(Base);
}
#endregion Log (base specified)
#region Log10
public static double Log10(double x)
{
//Use change of base formula
return Log(x, 10F);
}
#endregion Log10
#region Pow
public static double Pow(double b, double e)
{
if (e == 0) return 1;
if (e == 1) return b;
if (double.IsNaN(b) || double.IsNaN(e)) return double.NaN;
if (double.IsNegativeInfinity(b))
{
if (e < 0)
return 0;
if ((long)e % 2 == 0)
return double.PositiveInfinity;
else
return double.NegativeInfinity;
}
if (double.IsPositiveInfinity(b))
{
if (e < 0)
return 0;
else
return double.PositiveInfinity;
}
if (double.IsInfinity(e))
{
bool t = -1 < b;
bool t1 = 1 > b;
if (t && t1)
if (double.IsPositiveInfinity(e))
return 0;
else
return double.PositiveInfinity;
else
{
bool v = b < -1;
bool v1 = 1 < b;
if (v || v1)
{
if (double.IsPositiveInfinity(e))
return double.PositiveInfinity;
else
return 0;
}
else
return double.NaN;
}
}
if (b < 0)
{
if (Abs(e) - Abs((int)e) > (Double.Epsilon * 100)) return double.NaN;
double logedBase = Log(Abs(b));
double pow = Exp(logedBase * e);
if ((long)e % 2 == 0) return pow;
else return -1 * pow;
}
else
{
if (e < 0)
{
e = Abs(e);
double logedBase = Log(b);
return 1 / Exp(logedBase * e);
}
else
{
double logedBase = Log(b);
return Exp(logedBase * e);
}
}
}
#endregion Pow
#region Round
public static double Round(double d)
{
return ((Floor(d) % 2 == 0) ? Floor(d) : Ceiling(d));
}
#endregion Round
#region Sin
public static double Sin(double x)
{
double[] y = new double[2];
double z = 0.0;
int n, ix;
/* High word of x. */
ix = HighWord(x);
/* |x| ~< pi/4 */
ix &= 0x7fffffff;
if (ix <= 0x3fe921fb)
return _sin(x, z, 0);
/* sin(Inf or NaN) is NaN */
else if (ix >= 0x7ff00000)
return x - x;
/* argument reduction needed */
else
{
n = __ieee754_rem_pio2(x, y);
switch (n & 3)
{
case 0:
return _sin(y[0], y[1], 1);
case 1:
return _cos(y[0], y[1]);
case 2:
return -_sin(y[0], y[1], 1);
default:
return -_cos(y[0], y[1]);
}
}
}
private static double _sin(double x, double y, int iy)
{
const double half = 5.00000000000000000000e-01; /* 0x3FE00000; 0x00000000 */
const double S1 = -1.66666666666666324348e-01; /* 0xBFC55555; 0x55555549 */
const double S2 = 8.33333333332248946124e-03; /* 0x3F811111; 0x1110F8A6 */
const double S3 = -1.98412698298579493134e-04; /* 0xBF2A01A0; 0x19C161D5 */
const double S4 = 2.75573137070700676789e-06; /* 0x3EC71DE3; 0x57B1FE7D */
const double S5 = -2.50507602534068634195e-08; /* 0xBE5AE5E6; 0x8A2B9CEB */
const double S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A; 0x5ACFD57C */
double z, r, v;
int ix;
ix = HighWord(x) & 0x7fffffff; /* high word of x */
if (ix < 0x3e400000) /* |x| < 2**-27 */
{ if ((int)x == 0) return x; } /* generate inexact */
z = x * x;
v = z * x;
r = S2 + z * (S3 + z * (S4 + z * (S5 + z * S6)));
if (iy == 0)
return x + v * (S1 + z * r);
else
return x - ((z * (half * y - v * r) - y) - v * S1);
}
#endregion Sin
#region Sinh
public static double Sinh(double x)
{
if (x < 0F)
x = -x;
if (x <= 22F)
{
double Ex_1 = Tanh(x / 2) * (Exp(x) + 1);
return ((Ex_1 + (Ex_1 / (Ex_1 - 1))) / 2);
}
else
{
return (Exp(x) / 2);
}
}
#endregion Sinh
#region Sqrt
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunSoft, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
public static double Sqrt(double x)
{
double z = 0;
const uint sign = 0x80000000;
uint r, t1, s1, ix1, q1;
int ix0, s0, q, m, t, i;
ix0 = HighWord(x); /* high word of x */
ix1 = (uint)LowWord(x); /* low word of x */
/* take care of Inf and NaN */
if ((ix0 & 0x7ff00000) == 0x7ff00000)
return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf sqrt(-inf)=sNaN */
/* take care of zero */
if (ix0 <= 0)
{
if (((ix0 & (~0x80000000)) | ix1) == 0)
return x;/* sqrt(+-0) = +-0 */
else if (ix0 < 0)
return (x - x) / (x - x); /* sqrt(-ve) = sNaN */
}
/* normalize x */
m = (ix0 >> 20);
if (m == 0)
{ /* subnormal x */
while (ix0 == 0)
{
m -= 21;
ix0 |= ((int)ix1 >> 11); ix1 <<= 21;
}
for (i = 0; (ix0 & 0x00100000) == 0; i++) ix0 <<= 1;
m -= i - 1;
ix0 |= ((int)ix1 >> (32 - i));
ix1 <<= i;
}
m -= 1023; /* unbias exponent */
ix0 = (ix0 & 0x000fffff) | 0x00100000;
if ((m & 1) % 2 != 0)
{ /* odd m, double x to make it even */
ix0 += ix0 + (int)((long)(ix1 & sign) >> 31);
ix1 += ix1;
}
m >>= 1; /* m = [m/2] */
/* generate sqrt(x) bit by bit */
ix0 += ix0 + (int)((long)(ix1 & sign) >> 31);
ix1 += ix1;
s1 = 0;
s0 = (int)s1;
q1 = (uint)s0;
q = (int)q1; /* [q,q1] = sqrt(x) */
r = 0x00200000; /* r = moving bit from right to left */
while (r != 0)
{
t = s0 + (int)r;
if (t <= ix0)
{
s0 = t + (int)r;
ix0 -= t;
q += (int)r;
}
ix0 += ix0 + ((int)(ix1 & sign) >> 31);
ix1 += ix1;
r >>= 1;
}
r = sign;
while (r != 0)
{
t1 = s1 + r;
t = s0;
if ((t < ix0) || ((t == ix0) && (t1 <= ix1)))
{
s1 = t1 + r;
if (((t1 & sign) == sign) && (s1 & sign) == 0) s0 += 1;
ix0 -= t;
if (ix1 < t1) ix0 -= 1;
ix1 -= t1;
q1 += r;
}
ix0 += ix0 + ((int)(ix1 & sign) >> 31);
ix1 += ix1;
r >>= 1;
}
/* use floating add to find out rounding direction */
if (((uint)ix0 | ix1) != 0)
{
z = 1 - 1.0e-300; /* trigger inexact flag */
if (z >= 1)
{
z = 1 + 1.0e-300;
if (q1 == 0xffffffff)
{
q1 = 0; q += 1;
}
else if (z > 1)
{
if (q1 == 0xfffffffe)
q += 1;
q1 += 2;
}
else
q1 += (q1 & 1);
}
}
ix0 = (q >> 1) + 0x3fe00000;
ix1 = q1 >> 1;
if ((q & 1) == 1) ix1 |= sign;
ix0 += (m << 20);
long value = BitConverter.DoubleToInt64Bits(x);
Byte[] valueBytes = BitConverter.GetBytes(value);
int offset = BitConverter.IsLittleEndian ? 4 : 0;
Byte[] toAddHigher = BitConverter.GetBytes(ix0);
Byte[] toAddLower = BitConverter.GetBytes(ix1);
for (int I = 0; I < 4; I++)
{
valueBytes[I + offset] = toAddHigher[I];
valueBytes[I] = toAddLower[I];
}
return BitConverter.ToDouble(valueBytes, 0);
}
#endregion Sqrt
#region Tan
public static double Tan(double x)
{
if (double.IsNegativeInfinity(x) || double.IsInfinity(x)) return double.NaN;
return Sin(x) / Cos(x);
}
#endregion Tan
#region Tanh
public static double Tanh(double x)
{
return (expm1(2F * x) / (expm1(2F * x) + 2F));
}
#endregion Tanh
#region Truncate
public static double Truncate(double x)
{
return ((x == 0) ? 0F : ((x > 0F) ? Floor(x) : Ceiling(x)));
}
#endregion Truncate
#region Internaly used functions
private static int __ieee754_rem_pio2(double x, double[] y)
{
int highOffset = BitConverter.IsLittleEndian ? 4 : 0;
int lowOffset = BitConverter.IsLittleEndian ? 4 : 0;
int[] two_over_pi = {
0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,
0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,
0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,
0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,
0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8,
0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF,
0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,
0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3,
0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,
0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B,
};
int[] npio2_hw = new int[]{
0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C,
0x4025FDBB, 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C,
0x40346B9C, 0x4035FDBB, 0x40378FDB, 0x403921FB, 0x403AB41B, 0x403C463A,
0x403DD85A, 0x403F6A7A, 0x40407E4C, 0x4041475C, 0x4042106C, 0x4042D97C,
0x4043A28C, 0x40446B9C, 0x404534AC, 0x4045FDBB, 0x4046C6CB, 0x40478FDB,
0x404858EB, 0x404921FB,
};
const double two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */
pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */
pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */
pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */
pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */
pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
double z = 0, w, t, r, fn;
double[] tx = new double[3];
int e0, i, j, nx, n, ix, hx;
hx = HighWord(x); /* high word of x */
ix = hx & 0x7fffffff;
if (ix <= 0x3fe921fb) /* |x| ~<= pi/4 , no need for reduction */
{ y[0] = x; y[1] = 0; return 0; }
if (ix < 0x4002d97c)
{ /* |x| < 3pi/4, special case with n=+-1 */
if (hx > 0)
{
z = x - pio2_1;
if (ix != 0x3ff921fb)
{ /* 33+53 bit pi is good enough */
y[0] = z - pio2_1t;
y[1] = (z - y[0]) - pio2_1t;
}
else
{ /* near pi/2, use 33+33+53 bit pi */
z -= pio2_2;
y[0] = z - pio2_2t;
y[1] = (z - y[0]) - pio2_2t;
}
return 1;
}
else
{ /* negative x */
z = x + pio2_1;
if (ix != 0x3ff921fb)
{ /* 33+53 bit pi is good enough */
y[0] = z + pio2_1t;
y[1] = (z - y[0]) + pio2_1t;
}
else
{ /* near pi/2, use 33+33+53 bit pi */
z += pio2_2;
y[0] = z + pio2_2t;
y[1] = (z - y[0]) + pio2_2t;
}
return -1;
}
}
if (ix <= 0x413921fb)
{ /* |x| ~<= 2^19*(pi/2), medium size */
t = Abs(x);
n = (int)(t * invpio2 + 0.5);
fn = n;
r = t - fn * pio2_1;
w = fn * pio2_1t; /* 1st round good to 85 bit */
if (n < 32 && ix != npio2_hw[n - 1])
{
y[0] = r - w; /* quick check no cancellation */
}
else
{
j = ix >> 20;
y[0] = r - w;
i = j - (((HighWord(y[0])) >> 20) & 0x7ff);
if (i > 16)
{ /* 2nd iteration needed, good to 118 */
t = r;
w = fn * pio2_2;
r = t - w;
w = fn * pio2_2t - ((t - r) - w);
y[0] = r - w;
i = j - (((HighWord(y[0])) >> 20) & 0x7ff);
if (i > 49)
{ /* 3rd iteration need, 151 bits acc */
t = r; /* will cover all possible cases */
w = fn * pio2_3;
r = t - w;
w = fn * pio2_3t - ((t - r) - w);
y[0] = r - w;
}
}
}
y[1] = (r - y[0]) - w;
if (hx < 0)
{
y[0] = -y[0];
y[1] = -y[1];
return -n;
}
else
return n;
}
/*
* all other (large) arguments
*/
if (ix >= 0x7ff00000)
{ /* x is inf or NaN */
y[0] = y[1] = x - x;
return 0;
}
/* set z = scalbn(|x|,ilogb(x)-23) */
//__LO(z) = __LO(x);
//e0 = (ix >> 20) - 1046; /* e0 = ilogb(z)-23; */
//__HI(z) = ix - (e0 << 20);
e0 = (ix >> 20) - 1046; /* e0 = ilogb(z)-23; */
long lz = BitConverter.DoubleToInt64Bits(z);
long lx = BitConverter.DoubleToInt64Bits(x);
long lv = BitConverter.DoubleToInt64Bits(ix - (e0 << 20));
Byte[] bz = BitConverter.GetBytes(lz);
Byte[] bx = BitConverter.GetBytes(lx);
Byte[] bv = BitConverter.GetBytes(lv);
for (int l = 0; l < 4; l++)
{
bz[l + lowOffset] = bx[l + lowOffset];
bz[l + highOffset] = bv[l + highOffset];
}
for (i = 0; i < 2; i++)
{
tx[i] = ((int)(z));
z = (z - tx[i]) * two24;
}
tx[2] = z;
nx = 3;
while (tx[nx - 1] == 0)
nx--; /* skip zero term */
n = __kernel_rem_pio2(tx, y, e0, nx, 2, two_over_pi);
if (hx < 0)
{
y[0] = -y[0];
y[1] = -y[1];
return -n;
}
return n;
}
private static int __kernel_rem_pio2(double[] x, double[] y, int e0, int nx, int prec, int[] ipio2)
{
int[] init_jk = { 2, 3, 4, 6 }; /* initial value for jk */
double[] PIo2 = {
1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */
7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */
5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */
3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */
1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */
1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */
2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */
2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */
};
double two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
twon24 = 5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */
int jz, jx, jv, jp, jk, carry, n, i, j, k, m, q0, ih;
int[] iq = new int[20];
double z, fw;
double[] f = new double[20];
double[] fq = new double[20];
double[] q = new double[20];
/* initialize jk*/
jk = init_jk[prec];
jp = jk;
/* determine jx,jv,q0, note that 3>q0 */
jx = nx - 1;
jv = (e0 - 3) / 24; if (jv < 0) jv = 0;
q0 = e0 - 24 * (jv + 1);
/* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
j = jv - jx; m = jx + jk;
for (i = 0; i <= m; i++, j++)
f[i] = (j < 0) ? 0 : ipio2[j];
/* compute q[0],q[1],...q[jk] */
for (i = 0; i <= jk; i++)
{
for (j = 0, fw = 0.0; j <= jx; j++)
fw += x[j] * f[jx + i - j];
q[i] = fw;
}
jz = jk;
recompute:
/* distill q[] into iq[] reversingly */
for (i = 0, j = jz, z = q[jz]; j > 0; i++, j--)
{
fw = ((int)(twon24 * z));
iq[i] = (int)(z - two24 * fw);
z = q[j - 1] + fw;
}
/* compute n */
z = Scalbn(z, q0); /* actual value of z */
z -= 8.0 * Floor(z * 0.125); /* trim off integer >= 8 */
n = (int)z;
z -= n;
ih = 0;
if (q0 > 0)
{ /* need iq[jz-1] to determine n */
i = (iq[jz - 1] >> (24 - q0)); n += i;
iq[jz - 1] -= i << (24 - q0);
ih = iq[jz - 1] >> (23 - q0);
}
else if (q0 == 0) ih = iq[jz - 1] >> 23;
else if (z >= 0.5) ih = 2;
if (ih > 0)
{ /* q > 0.5 */
n += 1; carry = 0;
for (i = 0; i < jz; i++)
{ /* compute 1-q */
j = iq[i];
if (carry == 0)
{
if (j != 0)
{
carry = 1; iq[i] = 0x1000000 - j;
}
}
else iq[i] = 0xffffff - j;
}
if (q0 > 0)
{ /* rare case: chance is 1 in 12 */
switch (q0)
{
case 1:
iq[jz - 1] &= 0x7fffff; break;
case 2:
iq[jz - 1] &= 0x3fffff; break;
}
}
if (ih == 2)
{
z = 1 - z;
if (carry != 0) z -= Scalbn(1, q0);
}
}
/* check if recomputation is needed */
if (z == 0)
{
j = 0;
for (i = jz - 1; i >= jk; i--) j |= iq[i];
if (j == 0)
{ /* need recomputation */
for (k = 1; iq[jk - k] == 0; k++) ; /* k = no. of terms needed */
for (i = jz + 1; i <= jz + k; i++)
{ /* add q[jz+1] to q[jz+k] */
f[jx + i] = ipio2[jv + i];
for (j = 0, fw = 0.0; j <= jx; j++) fw += x[j] * f[jx + i - j];
q[i] = fw;
}
jz += k;
goto recompute;
}
}
/* chop off zero terms */
if (z == 0.0)
{
jz -= 1; q0 -= 24;
while (iq[jz] == 0) { jz--; q0 -= 24; }
}
else
{ /* break z into 24-bit if necessary */
z = Scalbn(z, -q0);
if (z >= two24)
{
fw = ((int)(twon24 * z));
iq[jz] = (int)(z - two24 * fw);
jz += 1; q0 += 24;
iq[jz] = (int)fw;
}
else
iq[jz] = (int)z;
}
/* convert integer "bit" chunk to floating-point value */
fw = Scalbn(1, q0);
for (i = jz; i >= 0; i--)
{
q[i] = fw * iq[i];
fw *= twon24;
}
/* compute PIo2[0,...,jp]*q[jz,...,0] */
for (i = jz; i >= 0; i--)
{
for (fw = 0.0, k = 0; k <= jp && k <= jz - i; k++)
fw += PIo2[k] * q[i + k];
fq[jz - i] = fw;
}
/* compress fq[] into y[] */
switch (prec)
{
case 0:
fw = 0.0;
for (i = jz; i >= 0; i--)
fw += fq[i];
y[0] = (ih == 0) ? fw : -fw;
break;
case 1:
case 2:
fw = 0.0;
for (i = jz; i >= 0; i--)
fw += fq[i];
y[0] = (ih == 0) ? fw : -fw;
fw = fq[0] - fw;
for (i = 1; i <= jz; i++)
fw += fq[i];
y[1] = (ih == 0) ? fw : -fw;
break;
case 3: /* painful */
for (i = jz; i > 0; i--)
{
fw = fq[i - 1] + fq[i];
fq[i] += fq[i - 1] - fw;
fq[i - 1] = fw;
}
for (i = jz; i > 1; i--)
{
fw = fq[i - 1] + fq[i];
fq[i] += fq[i - 1] - fw;
fq[i - 1] = fw;
}
for (fw = 0.0, i = jz; i >= 2; i--)
fw += fq[i];
if (ih == 0)
{
y[0] = fq[0]; y[1] = fq[1];
y[2] = fw;
}
else
{
y[0] = -fq[0]; y[1] = -fq[1];
y[2] = -fw;
}
break;
}
return n & 7;
}
private static double Scalbn(double x, int n)
{
double two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
huge = 1.0e+300,
tiny = 1.0e-300;
int k, hx, lx;
hx = HighWord(x);
lx = LowWord(x);
k = (hx & 0x7ff00000) >> 20; /* extract exponent */
if (k == 0)
{ /* 0 or subnormal x */
if ((lx | (hx & 0x7fffffff)) == 0)
return x; /* +-0 */
x *= two54;
hx = HighWord(x);
k = ((hx & 0x7ff00000) >> 20) - 54;
if (n < -50000)
return tiny * x; /*underflow*/
}
if (k == 0x7ff)
return x + x; /* NaN or Inf */
k = k + n;
if (k > 0x7fe)
return huge * (((long)x >> 31) & 1) * huge;// copysign(huge, x); /* overflow */
if (k > 0) /* normal result */
{
//__HI(x) = (hx & 0x800fffff) | (k << 20);
Byte[] _bx = BitConverter.GetBytes(BitConverter.DoubleToInt64Bits(x));
Byte[] _bv = BitConverter.GetBytes(BitConverter.DoubleToInt64Bits((hx & 0x800) | (k << 20)));
for (int i = 0; i < 4; i++)
{
_bx[i + (BitConverter.IsLittleEndian ? 4 : 0)] = _bv[i];
}
return x;
}
if (k <= -54)
if (n > 50000) /* in case integer overflow in n+k */
return huge * (((long)x >> 31) & 1) * huge; //copysign(huge, x); /*overflow*/
else
return tiny * (((long)x >> 31) & 1) * tiny;// copysign(tiny, x); /*underflow*/
k += 54; /* subnormal result */
//__HI(x) = (hx & 0x800) | (k << 20);
Byte[] bx = BitConverter.GetBytes(BitConverter.DoubleToInt64Bits(x));
Byte[] bv = BitConverter.GetBytes(BitConverter.DoubleToInt64Bits((hx & 0x800) | (k << 20)));
for (int i = 0; i < 4; i++)
{
bx[i + (BitConverter.IsLittleEndian ? 4 : 0)] = bv[i];
}
return x * twom54;
}
#region expm1
private static double expm1(double x)
{
double u = Exp(x);
return ((u == 1.0F) ? x : ((u - 1.0F == -1.0F) ? -1.0F : ((u - 1.0F) * x / Log(u))));
}
#endregion expm1
#region _power
private static double _power(double x, int c)
{
if (c == 0)
return 1.0F;
int _c;
double ret = x;
if (c >= 0f)
{
for (_c = 1; _c < c; _c++)
ret *= ret;
}
else
{
for (_c = 1; _c < c; _c++)
ret /= ret;
}
return ret;
}
#endregion _power
#region atans
private static double atans(double x)
{
if (x < sq2m1)
{
return atanx(x);
}
else if (x > sq2p1)
{
return (pio2 - atanx(1.0F / x));
}
else
{
return (pio4 + atanx((x - 1.0F) / (x + 1.0F)));
}
}
#endregion atans
#region atanx
private static double atanx(double x)
{
double argsq, value;
/* get denormalized add in following if range arg**10 is much smaller
than q1, so check for that case
*/
if ((x > -.01) && (x < .01))
{
value = (atan_p0 / atan_q0);
}
else
{
argsq = x * x;
value = ((((atan_p4 * argsq + atan_p3) * argsq + atan_p2) * argsq + atan_p1) * argsq + atan_p0) / (((((argsq + atan_q4) * argsq + atan_q3) * argsq + atan_q2) * argsq + atan_q1) * argsq + atan_q0);
}
return value * x;
//if (-.01 < arg && arg < .01)
// value = p0 / q0;
//double ArgSquared = x * x;
//return
// (((((atan_p4 * ArgSquared + atan_p3) * ArgSquared + atan_p2) * ArgSquared + atan_p1) * ArgSquared + atan_p0)
// /
// (((((ArgSquared + atan_q4) * ArgSquared + atan_q3) * ArgSquared + atan_q2) * ArgSquared + atan_q1) * ArgSquared + atan_q0) * x);
}
#endregion atanx
#region Words
private static int HighWord(double x)
{
long value = BitConverter.DoubleToInt64Bits(x);
Byte[] valueBytes = BitConverter.GetBytes(value);
int offset = BitConverter.IsLittleEndian ? 4 : 0;
return BitConverter.ToInt32(valueBytes, offset);
}
private static int LowWord(double x) //Opposite of high word
{
long value = BitConverter.DoubleToInt64Bits(x);
Byte[] valueBytes = BitConverter.GetBytes(value);
return BitConverter.ToInt32(valueBytes, BitConverter.IsLittleEndian ? 0 : 4);
}
#endregion Words
#endregion Internaly used functions
}
}