mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-19 12:30:32 +00:00
493 lines
No EOL
14 KiB
C#
493 lines
No EOL
14 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using Cosmos.IL2CPU.Plugs;
|
|
using Cosmos.System;
|
|
|
|
namespace Cosmos.System.Plugs.System
|
|
{
|
|
[Plug(Target = typeof(global::System.Math))]
|
|
public class MathImpl
|
|
{
|
|
|
|
#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
|
|
|
|
public const double PI = 3.1415926535897931;
|
|
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
|
|
|
|
#region Acos
|
|
public static double Acos(double x)
|
|
{
|
|
if ((x > 1.0) || (x < -1.0))
|
|
throw new ArgumentOutOfRangeException("Domain error");
|
|
return (pio2 - Asin(x));
|
|
}
|
|
#endregion
|
|
|
|
#region Asin
|
|
public static double Asin(double x)
|
|
{
|
|
if (x > 1.0F)
|
|
{
|
|
throw new ArgumentOutOfRangeException("Domain error");
|
|
}
|
|
double sign = 1F, temp;
|
|
if (x < 0.0F)
|
|
{
|
|
x = -x;
|
|
sign = -1.0F;
|
|
}
|
|
temp = Sqrt(1.0F - (x * x));
|
|
temp = ((x > 0.7) ? (pio2 - Atan(temp / x)) : (Atan(x / temp)));
|
|
return (sign * temp);
|
|
}
|
|
#endregion
|
|
|
|
#region Atan
|
|
public static double Atan(double x)
|
|
{
|
|
return ((x > 0F) ? atans(x) : (-atans(-x)));
|
|
}
|
|
#endregion
|
|
|
|
#region Atan2
|
|
public static double Atan2(double y, double x)
|
|
{
|
|
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
|
|
|
|
#region Ceiling
|
|
public static double Ceiling(double a)
|
|
{
|
|
// should be using assembler for bigger values than int or long max
|
|
if (a == Double.NaN || a == Double.NegativeInfinity || a == Double.PositiveInfinity)
|
|
return a;
|
|
int i = (a - (int)a > 0) ? (int)(a + 1) : (int)a;
|
|
return i;
|
|
}
|
|
#endregion
|
|
|
|
#region Cos
|
|
public static double Cos(double x)
|
|
{
|
|
if (x < 0)
|
|
x = -x;
|
|
byte quadrand = 0;
|
|
if ((x > (PI / 2F)) && (x < (PI)))
|
|
{
|
|
quadrand = 1;
|
|
x = PI - x;
|
|
}
|
|
if ((x > (PI)) && (x < ((3F * PI) / 2)))
|
|
{
|
|
quadrand = 2;
|
|
x = PI - x;
|
|
}
|
|
if ((x > ((3F * PI) / 2)))
|
|
{
|
|
quadrand = 3;
|
|
x = (2F * PI) - x;
|
|
}
|
|
const double c1 = 0.99999999999925182;
|
|
const double c2 = -0.49999999997024012;
|
|
const double c3 = 0.041666666473384543;
|
|
const double c4 = -0.001388888418000423;
|
|
const double c5 = 0.0000248010406484558;
|
|
const double c6 = -0.0000002752469638432;
|
|
const double c7 = 0.0000000019907856854;
|
|
double x2 = x * x; ;
|
|
return (((quadrand == 0) || (quadrand == 3)) ? (c1 + x2 * (c2 + x2 * (c3 + x2 * (c4 + x2 * (c5 + x2 * (c6 + c7 * x2)))))) : (-(c1 + x2 * (c2 + x2 * (c3 + x2 * (c4 + x2 * (c5 + x2 * (c6 + c7 * x2))))))));
|
|
//Cos(x) = Sin(90degrees - radians)
|
|
//return Sin((Math.PI / 2) - a);
|
|
}
|
|
#endregion
|
|
|
|
#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
|
|
|
|
#region Exp
|
|
public static double Exp(double x)
|
|
{
|
|
double c;
|
|
int n = 1;
|
|
double ex = 1F;
|
|
double m = 1F;
|
|
while (x > 10.000F)
|
|
{
|
|
m *= 22026.4657948067;
|
|
x -= 10F;
|
|
}
|
|
while (x > 01.000F)
|
|
{
|
|
m *= E;
|
|
x -= 1F;
|
|
}
|
|
while (x > 00.100F)
|
|
{
|
|
m *= 1.10517091807565; ;
|
|
x -= 0.1F;
|
|
}
|
|
while (x > 00.010F)
|
|
{
|
|
m *= 1.01005016708417;
|
|
x -= 0.01F;
|
|
}
|
|
for (int y = 1; y <= 4; y++)
|
|
{
|
|
c = _power(x, y);
|
|
ex += c / (double)n;
|
|
n *= (y + 1);
|
|
}
|
|
return ex * m;
|
|
}
|
|
#endregion
|
|
|
|
#region Floor
|
|
public static double Floor(double a)
|
|
{
|
|
// should be using assembler for bigger values than int or long max
|
|
if (a == Double.NaN || a == Double.NegativeInfinity || a == Double.PositiveInfinity)
|
|
return a;
|
|
int i = (a - (int)a < 0) ? (int)(a - 1) : (int)a;
|
|
return i;
|
|
}
|
|
#endregion
|
|
|
|
#region Log (base e)
|
|
public static double Log(double x)
|
|
{
|
|
return Log(x, E);
|
|
}
|
|
#endregion
|
|
|
|
#region Log (base specified)
|
|
public static double Log(double x, double newBase)
|
|
{
|
|
if (x == 0.0F)
|
|
{
|
|
return double.NegativeInfinity;
|
|
}
|
|
if ((x < 1.0F) && (newBase < 1.0F))
|
|
{
|
|
throw new ArgumentOutOfRangeException("can't compute Log");
|
|
}
|
|
|
|
double partial = 0.5F;
|
|
double integer = 0F;
|
|
double fractional = 0.0F;
|
|
|
|
while (x < 1.0F)
|
|
{
|
|
integer -= 1F;
|
|
x *= newBase;
|
|
}
|
|
|
|
while (x >= newBase)
|
|
{
|
|
integer += 1F;
|
|
x /= newBase;
|
|
}
|
|
|
|
x *= x;
|
|
|
|
while (partial >= 2.22045e-016)
|
|
{
|
|
if (x >= newBase)
|
|
{
|
|
fractional += partial;
|
|
x = x / newBase;
|
|
}
|
|
partial *= 0.5F;
|
|
x *= x;
|
|
}
|
|
|
|
return (integer + fractional);
|
|
}
|
|
#endregion
|
|
|
|
#region Log10
|
|
public static double Log10(double x)
|
|
{
|
|
return Log(x, 10F);
|
|
}
|
|
#endregion
|
|
|
|
#region Pow
|
|
public static double Pow(double x, double y)
|
|
{
|
|
if (x <= 0.0F)
|
|
{
|
|
double temp = 0F;
|
|
long l;
|
|
if (x == 0.0F && y <= 0.0F)
|
|
throw new ArgumentException();
|
|
|
|
l = (long)Floor(y);
|
|
if (l != y)
|
|
temp = Exp(y * Log(-x));
|
|
if ((l % 2) == 1)
|
|
temp = -temp;
|
|
|
|
return (temp);
|
|
}
|
|
|
|
return (Exp(y * Log(x)));
|
|
//if (y == 0)
|
|
//{
|
|
// return 1;
|
|
//}
|
|
//else if (y == 1)
|
|
//{
|
|
// return x;
|
|
//}
|
|
//else
|
|
//{
|
|
// double xResult = x;
|
|
|
|
// for (int i = 2; i <= y; i++)
|
|
// {
|
|
// xResult = xResult * x;
|
|
// }
|
|
|
|
// return xResult;
|
|
//}
|
|
}
|
|
#endregion
|
|
|
|
#region Round
|
|
public static double Round(double d)
|
|
{
|
|
return ((Math.Floor(d) % 2 == 0) ? Math.Floor(d) : Math.Ceiling(d));
|
|
}
|
|
#endregion
|
|
|
|
#region Sin
|
|
public static double Sin(double x)
|
|
{
|
|
return Cos((PI / 2.0F) - x);
|
|
|
|
//// should be using assembler instruction
|
|
//bool signSwitch = false;
|
|
//double result = 0;
|
|
|
|
////TO radians
|
|
//double radians = a;// *(Math.PI / 180);
|
|
|
|
//if (radians > Math.PI)
|
|
//{
|
|
// radians = radians - Math.PI;
|
|
// signSwitch = true;
|
|
//}
|
|
//else if (a > Math.PI / 2)
|
|
//{
|
|
// radians = radians - Math.PI;
|
|
// signSwitch = true;
|
|
//}
|
|
|
|
////Temp function to increase precision make more factorial calculations
|
|
//result = (radians) - (Math.Pow(radians, 3) / Factorial(3));
|
|
//result += (Math.Pow(radians, 5) / Factorial(5)) - (Math.Pow(radians, 7) / Factorial(7)) + (Math.Pow(radians, 9) / Factorial(9));
|
|
|
|
///* USE WHEN Modulus Works
|
|
// * int sign = 0;
|
|
//for (int i = 3; i < 19; i += 2)
|
|
//{
|
|
// if (sign % 2 == 0)
|
|
// result += -Math.Pow(radians, i) / fact(i);
|
|
// else
|
|
// result += Math.Pow(radiansa, i) / fact(i);
|
|
// sign++;
|
|
//}*/
|
|
|
|
//if (signSwitch)
|
|
// return result * -1;
|
|
//else
|
|
// return result;
|
|
}
|
|
#endregion
|
|
|
|
#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
|
|
|
|
#region Sqrt
|
|
public static double Sqrt(double x)
|
|
{
|
|
double i = 0;
|
|
double x1 = 0.0F;
|
|
double x2 = 0.0F;
|
|
|
|
if (x == 0F)
|
|
return 0F;
|
|
|
|
while ((i * i) <= x)
|
|
{
|
|
i += 0.1F;
|
|
}
|
|
|
|
x1 = i;
|
|
// this originally used another variable here,
|
|
// but the use of i was done, thus it's faster
|
|
// to re-use the variable.
|
|
for (i = 0; i < 10; i++)
|
|
{
|
|
x2 = x;
|
|
x2 /= x1;
|
|
x2 += x1;
|
|
x2 /= 2;
|
|
x1 = x2;
|
|
}
|
|
return x2;
|
|
}
|
|
#endregion
|
|
|
|
#region Tan
|
|
public static double Tan(double x)
|
|
{
|
|
return (Sin(x) / Cos(x));
|
|
}
|
|
#endregion
|
|
|
|
#region Tanh
|
|
public static double Tanh(double x)
|
|
{
|
|
return (expm1(2F * x) / (expm1(2F * x) + 2F));
|
|
}
|
|
#endregion
|
|
|
|
#region Truncate
|
|
public static double Truncate(double x)
|
|
{
|
|
return ((x == 0) ? 0F : ((x > 0F) ? Floor(x) : Ceiling(x)));
|
|
}
|
|
#endregion
|
|
|
|
//#region Factorial (only used in Sin(), not plug )
|
|
//public static int Factorial(int n)
|
|
//{
|
|
// if (n == 0)
|
|
// return 1;
|
|
// else
|
|
// return n * Factorial(n - 1);
|
|
//}
|
|
//#endregion
|
|
|
|
#region Internaly used functions
|
|
|
|
#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
|
|
|
|
#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
|
|
|
|
#region atans
|
|
private static double atans(double x)
|
|
{
|
|
return ((x < sq2m1) ? atanx(x) : ((x > sq2p1) ? (pio2 - atanx(1.0F / x)) : (pio4 + atanx((x - 1.0F) / (x + 1.0F)))));
|
|
}
|
|
#endregion
|
|
|
|
#region atanx
|
|
private static double atanx(double x)
|
|
{
|
|
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
|
|
|
|
#endregion
|
|
|
|
|
|
}
|
|
} |