751 lines
25 KiB
C#
751 lines
25 KiB
C#
using Nerd_STF.Exceptions;
|
|
using Nerd_STF.Helpers;
|
|
using Nerd_STF.Mathematics.Equations;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Numerics;
|
|
|
|
namespace Nerd_STF.Mathematics
|
|
{
|
|
public static class MathE
|
|
{
|
|
public static int Abs(int value) => value < 0 ? -value : value;
|
|
public static double Abs(double value) => value < 0 ? -value : value;
|
|
#if CS11_OR_GREATER
|
|
public static T Abs<T>(T num) where T : INumber<T>
|
|
{
|
|
return num < T.Zero ? -num : num;
|
|
}
|
|
#endif
|
|
|
|
public static int Average(IEnumerable<int> values)
|
|
{
|
|
int sum = 0;
|
|
int count = 0;
|
|
foreach (int val in values)
|
|
{
|
|
sum += val;
|
|
count++;
|
|
}
|
|
return sum / count;
|
|
}
|
|
public static double Average(IEnumerable<double> values)
|
|
{
|
|
double sum = 0;
|
|
int count = 0;
|
|
foreach (double val in values)
|
|
{
|
|
sum += val;
|
|
count++;
|
|
}
|
|
return sum / count;
|
|
}
|
|
#if CS11_OR_GREATER
|
|
public static T Average<T>(IEnumerable<T> values) where T : INumber<T>
|
|
{
|
|
T sum = T.Zero;
|
|
int count = 0;
|
|
foreach (T val in values)
|
|
{
|
|
sum += val;
|
|
count++;
|
|
}
|
|
return sum / T.CreateChecked(count);
|
|
}
|
|
#endif
|
|
public static double Average(IEquation equ, double lowerBound, double upperBound, double epsilon = 1e-3)
|
|
{
|
|
double sum = 0;
|
|
double steps = Abs(upperBound - lowerBound) / epsilon;
|
|
for (double x = lowerBound; x <= upperBound; x += epsilon) sum += equ[x];
|
|
return sum / steps;
|
|
}
|
|
|
|
public static int Ceiling(double value)
|
|
{
|
|
if (value % 1 == 0 || value < 0) return (int)value;
|
|
else return (int)value + 1;
|
|
}
|
|
public static void Ceiling(ref double value)
|
|
{
|
|
if (value % 1 != 0)
|
|
{
|
|
if (value > 0) value += 1 - value % 1;
|
|
else value -= value % 1;
|
|
}
|
|
}
|
|
public static IEquation Ceiling(IEquation equ) =>
|
|
new Equation((double x) => Ceiling(equ.Get(x)));
|
|
|
|
public static double Clamp(double value, double min, double max)
|
|
{
|
|
if (min > max) throw new ClampOrderMismatchException(nameof(min), nameof(max));
|
|
if (value < min) value = min;
|
|
if (value > max) value = max;
|
|
return value;
|
|
}
|
|
public static int Clamp(int value, int min, int max)
|
|
{
|
|
if (min > max) throw new ClampOrderMismatchException(nameof(min), nameof(max));
|
|
if (value < min) value = min;
|
|
if (value > max) value = max;
|
|
return value;
|
|
}
|
|
public static void Clamp(ref double value, double min, double max)
|
|
{
|
|
if (min > max) throw new ClampOrderMismatchException(nameof(min), nameof(max));
|
|
if (value < min) value = min;
|
|
if (value > max) value = max;
|
|
}
|
|
public static void Clamp(ref int value, int min, int max)
|
|
{
|
|
if (min > max) throw new ClampOrderMismatchException(nameof(min), nameof(max));
|
|
if (value < min) value = min;
|
|
if (value > max) value = max;
|
|
}
|
|
public static IEquation Clamp(IEquation equ, double min, double max) =>
|
|
new Equation((double x) => Clamp(equ.Get(x), min, max));
|
|
public static IEquation Clamp(IEquation value, IEquation min, IEquation max) =>
|
|
new Equation((double x) => Clamp(value.Get(x), min.Get(x), max.Get(x)));
|
|
#if CS11_OR_GREATER
|
|
public static T Clamp<T>(T value, T min, T max)
|
|
where T : INumber<T>
|
|
{
|
|
if (min > max) throw new ClampOrderMismatchException(nameof(min), nameof(max));
|
|
if (value < min) value = min;
|
|
if (value > max) value = max;
|
|
return value;
|
|
}
|
|
public static void Clamp<T>(ref T value, T min, T max)
|
|
where T : INumber<T>
|
|
{
|
|
if (min > max) throw new ClampOrderMismatchException(nameof(min), nameof(max));
|
|
if (value < min) value = min;
|
|
if (value > max) value = max;
|
|
}
|
|
#endif
|
|
|
|
public static int Dot(IEnumerable<int> a, IEnumerable<int> b)
|
|
{
|
|
List<int> parts = new List<int>(a);
|
|
int index = 0;
|
|
foreach (int bPart in b)
|
|
{
|
|
if (index < parts.Count) parts[index] *= bPart;
|
|
else parts.Add(bPart);
|
|
index++;
|
|
}
|
|
return Sum(parts);
|
|
}
|
|
public static double Dot(IEnumerable<double> a, IEnumerable<double> b)
|
|
{
|
|
List<double> parts = new List<double>(a);
|
|
int index = 0;
|
|
foreach (double bPart in b)
|
|
{
|
|
if (index < parts.Count) parts[index] *= bPart;
|
|
else parts.Add(bPart);
|
|
index++;
|
|
}
|
|
return Sum(parts);
|
|
}
|
|
public static int Dot(IEnumerable<IEnumerable<int>> groups)
|
|
{
|
|
List<int> parts = new List<int>();
|
|
foreach (IEnumerable<int> group in groups)
|
|
{
|
|
int index = 0;
|
|
foreach (int gPart in group)
|
|
{
|
|
if (index < parts.Count) parts[index] *= gPart;
|
|
else parts.Add(gPart);
|
|
index++;
|
|
}
|
|
}
|
|
return Sum(parts);
|
|
}
|
|
public static double Dot(IEnumerable<IEnumerable<double>> groups)
|
|
{
|
|
List<double> parts = new List<double>();
|
|
foreach (IEnumerable<double> group in groups)
|
|
{
|
|
int index = 0;
|
|
foreach (double gPart in group)
|
|
{
|
|
if (index < parts.Count) parts[index] *= gPart;
|
|
else parts.Add(gPart);
|
|
index++;
|
|
}
|
|
}
|
|
return Sum(parts);
|
|
}
|
|
#if CS11_OR_GREATER
|
|
public static T Dot<T>(IEnumerable<T> a, IEnumerable<T> b) where T : INumber<T>
|
|
{
|
|
List<T> parts = new List<T>(a);
|
|
int index = 0;
|
|
foreach (T bPart in b)
|
|
{
|
|
if (index < parts.Count) parts[index] *= bPart;
|
|
else parts.Add(bPart);
|
|
index++;
|
|
}
|
|
return Sum(parts);
|
|
}
|
|
public static T Dot<T>(IEnumerable<IEnumerable<T>> groups)
|
|
where T : INumber<T>
|
|
{
|
|
List<T> parts = new List<T>();
|
|
foreach (IEnumerable<T> group in groups)
|
|
{
|
|
int index = 0;
|
|
foreach (T gPart in group)
|
|
{
|
|
if (index < parts.Count) parts[index] *= gPart;
|
|
else parts.Add(gPart);
|
|
index++;
|
|
}
|
|
}
|
|
return Sum(parts);
|
|
}
|
|
#endif
|
|
|
|
public static IEquation DynamicIntegral(IEquation equ, IEquation lower, IEquation upper) =>
|
|
new Equation((double x) => equ.Integrate(lower[x], upper[x]));
|
|
|
|
public static double EulersMethod(IEquation equ, double refX, double deltaX) =>
|
|
equ.Derive()[refX] * deltaX + equ[refX];
|
|
|
|
// TODO: Gamma function at some point.
|
|
public static BigInteger FactorialBig(int num)
|
|
{
|
|
if (num < 0) return 0;
|
|
BigInteger result = 1;
|
|
for (int i = 2; i <= num; i++) result *= i;
|
|
return result;
|
|
}
|
|
public static BigInteger FactorialBig(int fromInclusive, int toInclusive)
|
|
{
|
|
if (fromInclusive > toInclusive) throw new ClampOrderMismatchException();
|
|
BigInteger result = 1;
|
|
for (int i = fromInclusive; i <= toInclusive; i++) result *= i;
|
|
return result;
|
|
}
|
|
public static ulong Factorial(int num)
|
|
{
|
|
if (num < 0) return 0;
|
|
else if (num > 20) throw new ArgumentOutOfRangeException(nameof(num), "Resulting number is too big to fit in a ulong.");
|
|
|
|
ulong result = 1, ulNum = (ulong)num;
|
|
for (ulong i = 2; i <= ulNum; i++) result *= i;
|
|
return result;
|
|
}
|
|
public static ulong Factorial(int fromInclusive, int toInclusive)
|
|
{
|
|
if (fromInclusive > toInclusive) throw new ClampOrderMismatchException();
|
|
|
|
ulong result = 1, ulMin = (ulong)fromInclusive, ulMax = (ulong)toInclusive;
|
|
for (ulong i = ulMin; i <= ulMax; i++) result *= i;
|
|
return result;
|
|
}
|
|
#if CS11_OR_GREATER
|
|
public static T Factorial<T>(T num) where T : INumber<T>
|
|
{
|
|
if (num < T.Zero) return T.Zero;
|
|
T result = T.One;
|
|
for (T i = T.One; i <= num; i++) result *= i;
|
|
return result;
|
|
}
|
|
public static T Factorial<T>(T fromInclusive, T toInclusive) where T : INumber<T>
|
|
{
|
|
if (fromInclusive > toInclusive) throw new ClampOrderMismatchException();
|
|
T result = T.One;
|
|
for (T i = fromInclusive; i <= toInclusive; i++) result *= i;
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
public static int[] Factors(int num) => FactorsE(num).ToArray();
|
|
public static IEnumerable<int> FactorsE(int num)
|
|
{
|
|
for (int i = 1; i <= num; i++) if (num % i == 0) yield return i;
|
|
}
|
|
|
|
public static unsafe double FastExp2(int pow)
|
|
{
|
|
// 11-bit exponent, 52-bit mantissa.
|
|
ulong bits = (ulong)pow;
|
|
if (pow > 0) bits = ((bits - 1) & 0b01111111111 | 0b10000000000) << 52;
|
|
else bits = ((bits - 1) & 0b01111111111) << 52;
|
|
return *(double*)&bits;
|
|
}
|
|
public static unsafe float FastExp2f(int pow)
|
|
{
|
|
// 8-bit exponent, 23-bit mantissa
|
|
uint bits = (uint)pow;
|
|
if (pow > 0) bits = ((bits - 1) & 0b01111111 | 0b10000000) << 23;
|
|
else bits = ((bits - 1) & 0b01111111) << 23;
|
|
return *(float*)&bits;
|
|
}
|
|
|
|
public static int Floor(double value)
|
|
{
|
|
if (value % 1 == 0 || value > 0) return (int)value;
|
|
else return (int)value - 1;
|
|
}
|
|
public static void Floor(ref double value)
|
|
{
|
|
if (value % 1 != 0)
|
|
{
|
|
if (value > 0) value -= value % 1;
|
|
else value -= 1 + value % 1;
|
|
}
|
|
}
|
|
public static IEquation Floor(IEquation equ) =>
|
|
new Equation((double x) => Floor(equ.Get(x)));
|
|
|
|
public static int Gcf(int a, int b)
|
|
{
|
|
for (int i = Min(a, b); i >= 1; i--)
|
|
{
|
|
if (a % i == 0 &&
|
|
b % i == 0) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
public static int Gcf(int a, int b, int c)
|
|
{
|
|
for (int i = Min(a, b); i >= 1; i--)
|
|
{
|
|
if (a % i == 0 &&
|
|
b % i == 0 &&
|
|
c % i == 0) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
public static int Gcf(IEnumerable<int> nums)
|
|
{
|
|
for (int i = Min(nums); i >= 1; i--)
|
|
{
|
|
bool valid = true;
|
|
foreach (int check in nums)
|
|
{
|
|
if (check % i != 0)
|
|
{
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
if (valid) return i;
|
|
}
|
|
return -1; // Will only get here if there are negative numbers in the collection.
|
|
}
|
|
|
|
public static double InverseSqrt(double num) => 1 / Sqrt(num);
|
|
public static unsafe float InverseSqrtFast(float num)
|
|
{
|
|
// I think we all know this function. Code structure
|
|
// has changed (ported), but the idea is exactly the
|
|
// same.
|
|
|
|
int raw = *(int*)#
|
|
float half = num * 0.5f;
|
|
raw = 0x5F3759DF - (raw >> 1);
|
|
num = *(float*)&raw;
|
|
|
|
num *= 1.5f - (half * num * num); // Newton's method.
|
|
return num;
|
|
}
|
|
|
|
public static int Lcm(int a, int b) => a * b / Gcf(a, b);
|
|
public static int Lcm(int a, int b, int c) => a * b * c / Gcf(a, b, c);
|
|
public static int Lcm(IEnumerable<int> nums) => Product(nums) / Gcf(nums);
|
|
|
|
public static double Lerp(double a, double b, double t, bool clamp = true)
|
|
{
|
|
if (clamp) Clamp(ref t, 0, 1);
|
|
return a + t * (b - a);
|
|
}
|
|
public static int Lerp(int a, int b, double t, bool clamp = true)
|
|
{
|
|
if (clamp) Clamp(ref t, 0, 1);
|
|
return (int)(a + t * (b - a));
|
|
}
|
|
public static IEquation Lerp(IEquation a, IEquation b, double t, bool clamp = true) =>
|
|
new Equation((double x) => Lerp(a.Get(x), b.Get(x), t, clamp));
|
|
#if CS11_OR_GREATER
|
|
public static T Lerp<T>(T a, T b, T t, bool clamp = true)
|
|
where T : INumber<T>
|
|
{
|
|
if (clamp) Clamp(ref t, T.Zero, T.One);
|
|
return a + t * (b - a);
|
|
}
|
|
#endif
|
|
|
|
public static int Max(int a, int b) => a > b ? a : b;
|
|
public static double Max(double a, double b) => a > b ? a : b;
|
|
public static T Max<T>(T a, T b) where T : IComparable<T>
|
|
{
|
|
if (a.CompareTo(b) > 0) return a;
|
|
else return b;
|
|
}
|
|
public static int Max(IEnumerable<int> values)
|
|
{
|
|
bool any = false;
|
|
int best = 0;
|
|
foreach (int val in values)
|
|
{
|
|
if (!any)
|
|
{
|
|
any = true;
|
|
best = val;
|
|
}
|
|
else if (val > best) best = val;
|
|
}
|
|
return best;
|
|
}
|
|
public static double Max(IEnumerable<double> values)
|
|
{
|
|
bool any = false;
|
|
double best = 0;
|
|
foreach (double val in values)
|
|
{
|
|
if (!any)
|
|
{
|
|
any = true;
|
|
best = val;
|
|
}
|
|
else if (val > best) best = val;
|
|
}
|
|
return best;
|
|
}
|
|
public static T Max<T>(IEnumerable<T> values) where T : IComparable<T>
|
|
{
|
|
bool any = false;
|
|
T best = values.First();
|
|
foreach (T val in values)
|
|
{
|
|
if (!any)
|
|
{
|
|
any = true;
|
|
best = val;
|
|
}
|
|
else if (val.CompareTo(best) > 0) best = val;
|
|
}
|
|
return best;
|
|
}
|
|
|
|
public static int Min(int a, int b) => a < b ? a : b;
|
|
public static double Min(double a, double b) => a < b ? a : b;
|
|
public static T Min<T>(T a, T b) where T : IComparable<T>
|
|
{
|
|
if (a.CompareTo(b) < 0) return a;
|
|
else return b;
|
|
}
|
|
public static int Min(IEnumerable<int> values)
|
|
{
|
|
bool any = false;
|
|
int best = 0;
|
|
foreach (int val in values)
|
|
{
|
|
if (!any)
|
|
{
|
|
any = true;
|
|
best = val;
|
|
}
|
|
else if (val < best) best = val;
|
|
}
|
|
return best;
|
|
}
|
|
public static double Min(IEnumerable<double> values)
|
|
{
|
|
bool any = false;
|
|
double best = 0;
|
|
foreach (double val in values)
|
|
{
|
|
if (!any)
|
|
{
|
|
any = true;
|
|
best = val;
|
|
}
|
|
else if (val < best) best = val;
|
|
}
|
|
return best;
|
|
}
|
|
public static T Min<T>(IEnumerable<T> values) where T : IComparable<T>
|
|
{
|
|
bool any = false;
|
|
T best = values.First();
|
|
foreach (T val in values)
|
|
{
|
|
if (!any)
|
|
{
|
|
any = true;
|
|
best = val;
|
|
}
|
|
else if (val.CompareTo(best) < 0) best = val;
|
|
}
|
|
return best;
|
|
}
|
|
|
|
public static int ModAbs(int value, int mod)
|
|
{
|
|
while (value >= mod) value -= mod;
|
|
while (value < 0) value += mod;
|
|
return value;
|
|
}
|
|
public static double ModAbs(double value, double mod)
|
|
{
|
|
while (value >= mod) value -= mod;
|
|
while (value < 0) value += mod;
|
|
return value;
|
|
}
|
|
#if CS11_OR_GREATER
|
|
public static T ModAbs<T>(T value, T mod) where T : INumber<T>
|
|
{
|
|
while (value >= mod) value -= mod;
|
|
while (value < T.Zero) value += mod;
|
|
return value;
|
|
}
|
|
#endif
|
|
|
|
public static BigInteger NprBig(int n, int r) => FactorialBig(n - r + 1, n);
|
|
public static int Npr(int n, int r) => (int)Factorial(n - r + 1, n);
|
|
|
|
public static int Pow(int @base, int pow)
|
|
{
|
|
if (pow < 0) return 1 / Pow(@base, -pow);
|
|
int result = 1;
|
|
for (int i = 1; i <= pow; i++) result *= @base;
|
|
return result;
|
|
}
|
|
public static double Pow(double @base, int pow)
|
|
{
|
|
if (pow < 0) return 1 / Pow(@base, -pow);
|
|
double result = 1;
|
|
for (int i = 1; i <= pow; i++) result *= @base;
|
|
return result;
|
|
}
|
|
public static double Pow(double @base, double pow) =>
|
|
CordicHelper.PowAnyBase(@base, pow, 8);
|
|
|
|
public static int[] PrimeFactors(int num) => PrimeFactorsE(num).ToArray();
|
|
public static IEnumerable<int> PrimeFactorsE(int num)
|
|
{
|
|
int i = 2;
|
|
while (num > 1)
|
|
{
|
|
while (num % i == 0)
|
|
{
|
|
yield return i;
|
|
num /= i;
|
|
}
|
|
if (i > 2) i += 2;
|
|
else i++;
|
|
}
|
|
}
|
|
|
|
public static int Product(IEnumerable<int> values)
|
|
{
|
|
bool any = false;
|
|
int prod = 1;
|
|
foreach (int val in values)
|
|
{
|
|
any = true;
|
|
prod *= val;
|
|
}
|
|
return any ? prod : 0;
|
|
}
|
|
public static double Product(IEnumerable<double> values)
|
|
{
|
|
bool any = false;
|
|
double prod = 1;
|
|
foreach (double val in values)
|
|
{
|
|
any = true;
|
|
prod *= val;
|
|
}
|
|
return any ? prod : 0;
|
|
}
|
|
#if CS11_OR_GREATER
|
|
public static T Product<T>(IEnumerable<T> values)
|
|
where T : INumber<T>
|
|
{
|
|
bool any = false;
|
|
T prod = T.One;
|
|
foreach (T val in values)
|
|
{
|
|
any = true;
|
|
prod *= val;
|
|
}
|
|
return any ? prod : T.Zero;
|
|
}
|
|
#endif
|
|
|
|
public static int Round(double value)
|
|
{
|
|
if (value > 0)
|
|
{
|
|
if (value % 1 >= 0.5) return (int)value + 1;
|
|
else return (int)value;
|
|
}
|
|
else
|
|
{
|
|
if (-value % 1 >= 0.5) return (int)value - 1;
|
|
else return (int)value;
|
|
}
|
|
}
|
|
public static void Round(ref double value)
|
|
{
|
|
if (value > 0)
|
|
{
|
|
if (value % 1 >= 0.5) value += 1 - value % 1;
|
|
else value -= value % 1;
|
|
}
|
|
else
|
|
{
|
|
if (-value % 1 >= 0.5) value -= 1 + value % 1;
|
|
else value -= value % 1;
|
|
}
|
|
}
|
|
public static IEquation Round(IEquation equ) =>
|
|
new Equation((double x) => Round(equ.Get(x)));
|
|
|
|
#if CS11_OR_GREATER
|
|
public static int Sign<T>(T num) where T : INumber<T> =>
|
|
num > T.Zero ? 1 : num < T.Zero ? -1 : 0;
|
|
#endif
|
|
public static int Sign(double num) => num > 0 ? 1 : num < 0 ? -1 : 0;
|
|
public static int Sign(int num) => num > 0 ? 1 : num < 0 ? -1 : 0;
|
|
|
|
public static double Sin(double rad, int terms = 8)
|
|
{
|
|
bool flip = false;
|
|
if (rad < 0)
|
|
{
|
|
flip = true;
|
|
rad = -rad;
|
|
}
|
|
if (rad > Constants.Tau) rad %= Constants.Tau;
|
|
|
|
double trueX = rad - Constants.Pi;
|
|
|
|
// Taylor series. More accurate than the polynomial
|
|
// I used in Nerd_STF 2.0.
|
|
int sign = 1;
|
|
int fact = 1;
|
|
int twoN = 1;
|
|
double result = trueX, xPow = trueX;
|
|
for (int n = 1; n < terms; n++)
|
|
{
|
|
twoN += 2;
|
|
fact *= twoN * (twoN - 1);
|
|
sign = -sign;
|
|
xPow *= trueX * trueX;
|
|
result += xPow * sign / fact;
|
|
}
|
|
|
|
return flip ? result : -result;
|
|
}
|
|
public static IEquation Sin(IEquation inputRad, int terms = 8) =>
|
|
new Equation((double x) => Sin(inputRad[x], terms));
|
|
public static double Cos(double rad, int terms = 8) =>
|
|
Sin(rad + Constants.HalfPi, terms);
|
|
public static IEquation Cos(IEquation inputRad, int terms = 8) =>
|
|
new Equation((double x) => Cos(inputRad[x], terms));
|
|
public static double Tan(double rad, int terms = 8) =>
|
|
Sin(rad + Constants.HalfPi, terms) / Sin(rad, terms);
|
|
public static IEquation Tan(IEquation inputRad, int terms = 8) =>
|
|
new Equation((double x) => Tan(inputRad[x], terms));
|
|
public static double Csc(double rad, int terms = 8) =>
|
|
1 / Sin(rad, terms);
|
|
public static IEquation Csc(IEquation inputRad, int terms = 8) =>
|
|
new Equation((double x) => Csc(inputRad[x], terms));
|
|
public static double Sec(double rad, int terms = 8) =>
|
|
1 / Sin(rad + Constants.HalfPi, terms);
|
|
public static IEquation Sec(IEquation inputRad, int terms = 8) =>
|
|
new Equation((double x) => Sec(inputRad[x], terms));
|
|
public static double Cot(double rad, int terms = 8) =>
|
|
Sin(rad, terms) / Sin(rad + Constants.HalfPi, terms);
|
|
public static IEquation Cot(IEquation inputRad, int terms = 8) =>
|
|
new Equation((double x) => Cot(inputRad[x], terms));
|
|
|
|
public static double Sqrt(double num) => 1 / InverseSqrtFast((float)num); // !!TODO!!: Bring back Newton's
|
|
public static IEquation Sqrt(IEquation equ) =>
|
|
new Equation((double x) => Sqrt(equ.Get(x)));
|
|
|
|
public static double Stdev(IEnumerable<double> nums) => Sqrt(Variance(nums));
|
|
|
|
public static int Sum(IEnumerable<int> nums)
|
|
{
|
|
int sum = 0;
|
|
foreach (int num in nums) sum += num;
|
|
return sum;
|
|
}
|
|
public static double Sum(IEnumerable<double> nums)
|
|
{
|
|
double sum = 0;
|
|
foreach (double num in nums) sum += num;
|
|
return sum;
|
|
}
|
|
#if CS11_OR_GREATER
|
|
public static T Sum<T>(IEnumerable<T> nums) where T : INumber<T>
|
|
{
|
|
T sum = T.Zero;
|
|
foreach (T num in nums) sum += num;
|
|
return sum;
|
|
}
|
|
#endif
|
|
|
|
public static Linear TangentLine(IEquation equ, double x)
|
|
{
|
|
double slope = equ.Derive()[x];
|
|
return new Linear(slope, equ[x] - slope * x);
|
|
}
|
|
|
|
public static Polynomial TaylorSeries(IEquation equ, double x, int terms)
|
|
{
|
|
IEquation current = equ;
|
|
double[] coeffs = new double[terms];
|
|
int fact = 1;
|
|
for (int i = 0; i < terms; i++)
|
|
{
|
|
coeffs[i] = current.Get(x) / fact;
|
|
current = current.Derive();
|
|
fact *= i + 1;
|
|
}
|
|
return new Polynomial(false, coeffs);
|
|
}
|
|
|
|
public static double Variance(IEnumerable<double> nums)
|
|
{
|
|
double mean = Average(nums), sum = 0;
|
|
int count = 0;
|
|
foreach (double num in nums)
|
|
{
|
|
double dist = num - mean;
|
|
sum += dist * dist;
|
|
count++;
|
|
}
|
|
return sum / (count - 1);
|
|
}
|
|
|
|
public static double ZScore(double val, IEnumerable<double> nums)
|
|
{
|
|
double mean = Average(nums), sum = 0;
|
|
int count = 0;
|
|
foreach (double num in nums)
|
|
{
|
|
double dist = num - mean;
|
|
sum += dist * dist;
|
|
count++;
|
|
}
|
|
double stdev = Sqrt(sum / count - 1);
|
|
return (val - mean) / stdev;
|
|
}
|
|
public static double ZScore(double val, double mean, double stdev) =>
|
|
(val - mean) / stdev;
|
|
}
|
|
}
|