Releasing Nerd_STF version 2.4.0. #88
1300
Changelog.md
1300
Changelog.md
File diff suppressed because it is too large
Load Diff
BIN
Extras/Banner.png
Normal file
BIN
Extras/Banner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 836 KiB |
BIN
Extras/Logo Square High Res.png
Normal file
BIN
Extras/Logo Square High Res.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 316 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 24 KiB |
18
Nerd_STF/Exceptions/BadMethodException.cs
Normal file
18
Nerd_STF/Exceptions/BadMethodException.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
namespace Nerd_STF.Exceptions;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class BadMethodException : Nerd_STFException
|
||||||
|
{
|
||||||
|
public MethodInfo? MethodInfo;
|
||||||
|
|
||||||
|
public BadMethodException() : base("The method or delegate provided is invalid for this operation.") { }
|
||||||
|
public BadMethodException(string message) : base(message) { }
|
||||||
|
public BadMethodException(Exception inner) : base("The method or delegate provided is invalid for this operation.", inner) { }
|
||||||
|
public BadMethodException(MethodInfo method) : this() => MethodInfo = method;
|
||||||
|
public BadMethodException(MethodInfo method, Exception inner) : this(inner) => MethodInfo = method;
|
||||||
|
public BadMethodException(string message, Exception inner) : base(message, inner) { }
|
||||||
|
public BadMethodException(string message, MethodInfo method) : this(message) => MethodInfo = method;
|
||||||
|
public BadMethodException(string message, MethodInfo method, Exception inner) : this(message, inner) => MethodInfo = method;
|
||||||
|
|
||||||
|
protected BadMethodException(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
||||||
|
}
|
||||||
@ -2,18 +2,7 @@
|
|||||||
|
|
||||||
public static class ConversionExtension
|
public static class ConversionExtension
|
||||||
{
|
{
|
||||||
[Obsolete("This extension turns out to already exist as a constructor in the " +
|
|
||||||
"System.Collections.Generic.Dictionary<TKey, TValue> type. This will be removed in v2.4.0")]
|
|
||||||
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>
|
|
||||||
(this IEnumerable<KeyValuePair<TKey, TValue>> pairs)
|
|
||||||
where TKey : notnull
|
|
||||||
{
|
|
||||||
Dictionary<TKey, TValue> res = new();
|
|
||||||
foreach (KeyValuePair<TKey, TValue> pair in pairs) res.Add(pair.Key, pair.Value);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Fill<T> ToFill<T>(this T[] arr) => i => arr[i];
|
public static Fill<T> ToFill<T>(this T[] arr) => i => arr[i];
|
||||||
public static Fill<T> ToFill<T>(this T[,] arr, Int2? size) => arr.Flatten(size).ToFill();
|
public static Fill<T> ToFill<T>(this T[,] arr, Int2? size) => arr.Flatten(size).ToFill();
|
||||||
public static Fill2D<T> ToFill2D<T>(this T[,] arr) => (x, y) => arr[x, y];
|
public static Fill2d<T> ToFill2D<T>(this T[,] arr) => (x, y) => arr[x, y];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,299 @@
|
|||||||
|
|
||||||
public static class EquationExtension
|
public static class EquationExtension
|
||||||
{
|
{
|
||||||
|
private static readonly List<Type> ValidNumberTypes = new()
|
||||||
|
{
|
||||||
|
typeof(byte),
|
||||||
|
typeof(sbyte),
|
||||||
|
typeof(short),
|
||||||
|
typeof(ushort),
|
||||||
|
typeof(int),
|
||||||
|
typeof(uint),
|
||||||
|
typeof(long),
|
||||||
|
typeof(ulong),
|
||||||
|
typeof(float),
|
||||||
|
typeof(double),
|
||||||
|
typeof(decimal)
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Equation Absolute(this Equation equ) => x => Mathf.Absolute(equ(x));
|
||||||
|
public static Equation AbsoluteMod(this Equation equ, float mod) => x => Mathf.AbsoluteMod(equ(x), mod);
|
||||||
|
|
||||||
|
public static Equation ArcCos(this Equation equ) => x => Mathf.ArcCos(equ(x)).Radians;
|
||||||
|
public static Equation ArcCot(this Equation equ) => x => Mathf.ArcCot(equ(x)).Radians;
|
||||||
|
public static Equation ArcCsc(this Equation equ) => x => Mathf.ArcCsc(equ(x)).Radians;
|
||||||
|
public static Equation ArcSec(this Equation equ) => x => Mathf.ArcSec(equ(x)).Radians;
|
||||||
|
public static Equation ArcSin(this Equation equ) => x => Mathf.ArcSin(equ(x)).Radians;
|
||||||
|
public static Equation ArcTan(this Equation equ) => x => Mathf.ArcTan(equ(x)).Radians;
|
||||||
|
|
||||||
|
public static Equation ArcCosh(this Equation equ) => x => Mathf.ArcCosh(equ(x));
|
||||||
|
public static Equation ArcCoth(this Equation equ) => x => Mathf.ArcCoth(equ(x));
|
||||||
|
public static Equation ArcCsch(this Equation equ) => x => Mathf.ArcCsch(equ(x));
|
||||||
|
public static Equation ArcSech(this Equation equ) => x => Mathf.ArcSech(equ(x));
|
||||||
|
public static Equation ArcSinh(this Equation equ) => x => Mathf.ArcSinh(equ(x));
|
||||||
|
public static Equation ArcTanh(this Equation equ) => x => Mathf.ArcTanh(equ(x));
|
||||||
|
|
||||||
|
public static float Average(this Equation equ, float min, float max, float step = Calculus.DefaultStep) =>
|
||||||
|
Mathf.Average(equ, min, max, step);
|
||||||
|
public static Equation Average(this Equation equ, Equation min, Equation max, float step = Calculus.DefaultStep) =>
|
||||||
|
x => Mathf.Average(equ, min(x), max(x), step);
|
||||||
|
|
||||||
|
public static Equation Binomial(this Equation equ, int total, float successRate) =>
|
||||||
|
x => Mathf.Binomial((int)equ(x), total, successRate);
|
||||||
|
public static Equation Binomial(this Equation equ, Equation total, Equation successRate) =>
|
||||||
|
x => Mathf.Binomial((int)equ(x), (int)total(x), successRate(x));
|
||||||
|
|
||||||
|
public static Equation Cbrt(this Equation equ) => x => Mathf.Cbrt(equ(x));
|
||||||
|
|
||||||
|
public static Equation Ceiling(this Equation equ) => x => Mathf.Ceiling(equ(x));
|
||||||
|
|
||||||
|
public static Equation Clamp(this Equation equ, float min, float max) => x => Mathf.Clamp(equ(x), min, max);
|
||||||
|
public static Equation Clamp(this Equation equ, Equation min, Equation max) =>
|
||||||
|
x => Mathf.Clamp(equ(x), min(x), max(x));
|
||||||
|
|
||||||
|
public static Equation Combinations(this Equation equ, int size) =>
|
||||||
|
x => Mathf.Combinations(size, (int)equ(x));
|
||||||
|
public static Equation Combinations(this Equation equ, Equation size) =>
|
||||||
|
x => Mathf.Combinations((int)size(x), (int)equ(x));
|
||||||
|
|
||||||
|
public static Equation Cos(this Equation equ) => x => Mathf.Cos(equ(x));
|
||||||
|
public static Equation Cot(this Equation equ) => x => Mathf.Cot(equ(x));
|
||||||
|
public static Equation Csc(this Equation equ) => x => Mathf.Csc(equ(x));
|
||||||
|
|
||||||
|
public static Equation Cosh(this Equation equ) => x => Mathf.Cosh(equ(x));
|
||||||
|
public static Equation Coth(this Equation equ) => x => Mathf.Coth(equ(x));
|
||||||
|
public static Equation Csch(this Equation equ) => x => Mathf.Csch(equ(x));
|
||||||
|
|
||||||
|
public static Equation Divide(this Equation equ, params float[] dividends) =>
|
||||||
|
x => Mathf.Divide(equ(x), dividends);
|
||||||
|
public static Equation Divide(this Equation equ, params Equation[] dividends) => delegate (float x)
|
||||||
|
{
|
||||||
|
float[] dividendsAtValue = new float[dividends.Length];
|
||||||
|
for (int i = 0; i < dividends.Length; i++) dividendsAtValue[i] = dividends[i](x);
|
||||||
|
return Mathf.Divide(equ(x), dividendsAtValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Equation Factorial(this Equation equ) => x => Mathf.Factorial((int)equ(x));
|
||||||
|
|
||||||
|
public static Equation Floor(this Equation equ) => x => Mathf.Floor(equ(x));
|
||||||
|
|
||||||
|
public static Equation GetDerivative(this Equation equ, float step = Calculus.DefaultStep) =>
|
||||||
|
Calculus.GetDerivative(equ, step);
|
||||||
|
public static float GetDerivativeAtPoint(this Equation equ, float x, float step = Calculus.DefaultStep) =>
|
||||||
|
Calculus.GetDerivativeAtPoint(equ, x, step);
|
||||||
|
|
||||||
|
public static float GetIntegral(this Equation equ, float lowerBound, float upperBound,
|
||||||
|
float step = Calculus.DefaultStep) => Calculus.GetIntegral(equ, lowerBound, upperBound, step);
|
||||||
|
|
||||||
|
public static Equation GetDynamicIntegral(this Equation equ, Equation lowerBound,
|
||||||
|
Equation upperBound, float step = Calculus.DefaultStep) => Calculus.GetDynamicIntegral(equ, lowerBound, upperBound, step);
|
||||||
|
|
||||||
|
public static Equation GetTaylorSeries(this Equation equ, float referenceX, int iterations = 4, float step = 0.01f) =>
|
||||||
|
Calculus.GetTaylorSeries(equ, referenceX, iterations, step);
|
||||||
|
|
||||||
|
public static Dictionary<float, float> GetValues(this Equation equ, float min, float max,
|
||||||
|
float step = Calculus.DefaultStep) => Mathf.GetValues(equ, min, max, step);
|
||||||
|
|
||||||
|
public static float GradientDescent(this Equation equ, float initial, float rate, int iterations = 1000,
|
||||||
|
float step = Calculus.DefaultStep) => Calculus.GradientDescent(equ, initial, rate, iterations, step);
|
||||||
|
|
||||||
|
public static Equation InverseSqrt(this Equation equ) => x => Mathf.InverseSqrt(equ(x));
|
||||||
|
|
||||||
|
public static Equation Log(this Equation equ, float @base) => x => Mathf.Log(@base, equ(x));
|
||||||
|
|
||||||
|
public static float Max(this Equation equ, float min, float max, float step = Calculus.DefaultStep) =>
|
||||||
|
Mathf.Max(equ, min, max, step);
|
||||||
|
public static float Min(this Equation equ, float min, float max, float step = Calculus.DefaultStep) =>
|
||||||
|
Mathf.Min(equ, min, max, step);
|
||||||
|
|
||||||
|
public static Equation Permutations(this Equation equ, int size) =>
|
||||||
|
x => Mathf.Permutations(size, (int)equ(x));
|
||||||
|
public static Equation Permutations(this Equation equ, Equation size) =>
|
||||||
|
x => Mathf.Permutations((int)size(x), (int)equ(x));
|
||||||
|
|
||||||
|
public static Equation Power(this Equation equ, float pow) => x => Mathf.Power(equ(x), pow);
|
||||||
|
public static Equation Power(this Equation equ, Equation pow) => x => Mathf.Power(equ(x), pow(x));
|
||||||
|
|
||||||
|
public static Equation Product(this Equation equ, params float[] vals) => delegate (float x)
|
||||||
|
{
|
||||||
|
float[] valsAtValue = new float[vals.Length + 1];
|
||||||
|
valsAtValue[0] = equ(x);
|
||||||
|
for (int i = 0; i < vals.Length; i++) valsAtValue[i + 1] = vals[i];
|
||||||
|
return Mathf.Product(valsAtValue);
|
||||||
|
};
|
||||||
|
public static Equation Product(this Equation equ, params Equation[] vals) => delegate (float x)
|
||||||
|
{
|
||||||
|
float[] valsAtValue = new float[vals.Length + 1];
|
||||||
|
valsAtValue[0] = equ(x);
|
||||||
|
for (int i = 0; i < vals.Length; i++) valsAtValue[i + 1] = vals[i](x);
|
||||||
|
return Mathf.Product(valsAtValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Equation Root(this Equation equ, float index) => x => Mathf.Root(equ(x), index);
|
||||||
|
public static Equation Root(this Equation equ, Equation index) => x => Mathf.Root(equ(x), index(x));
|
||||||
|
|
||||||
|
public static Equation Round(this Equation equ) => x => Mathf.Round(equ(x));
|
||||||
|
|
||||||
|
public static Equation Sec(this Equation equ) => x => Mathf.Sec(equ(x));
|
||||||
|
public static Equation Sin(this Equation equ) => x => Mathf.Sin(equ(x));
|
||||||
|
|
||||||
|
public static Equation Sech(this Equation equ) => x => Mathf.Sech(equ(x));
|
||||||
|
public static Equation Sinh(this Equation equ) => x => Mathf.Sinh(equ(x));
|
||||||
|
|
||||||
|
public static float SolveBisection(this Equation equ, float initialA, float initialB, float tolerance = 1e-5f,
|
||||||
|
int maxIterations = 1000) =>
|
||||||
|
Mathf.SolveBisection(equ, initialA, initialB, tolerance, maxIterations);
|
||||||
|
public static float SolveEquation(this Equation equ, float initial, float tolerance = 1e-5f,
|
||||||
|
float step = Calculus.DefaultStep, int maxIterations = 1000) =>
|
||||||
|
Mathf.SolveEquation(equ, initial, tolerance, step, maxIterations);
|
||||||
|
public static float SolveNewton(this Equation equ, float initial, float tolerance = 1e-5f,
|
||||||
|
float step = Calculus.DefaultStep, int maxIterations = 1000) =>
|
||||||
|
Mathf.SolveNewton(equ, initial, tolerance, step, maxIterations);
|
||||||
|
|
||||||
|
public static Equation Sqrt(this Equation equ) => x => Mathf.Sqrt(equ(x));
|
||||||
|
|
||||||
|
public static Equation Subtract(this Equation equ, params float[] vals) =>
|
||||||
|
x => Mathf.Subtract(equ(x), vals);
|
||||||
|
public static Equation Subtract(this Equation equ, params Equation[] vals) => delegate (float x)
|
||||||
|
{
|
||||||
|
float[] valsAtValue = new float[vals.Length];
|
||||||
|
for (int i = 0; i < vals.Length; i++) valsAtValue[i] = vals[i](x);
|
||||||
|
return Mathf.Subtract(equ(x), valsAtValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Equation Sum(this Equation equ, params float[] vals) => delegate (float x)
|
||||||
|
{
|
||||||
|
float[] valsAtValue = new float[vals.Length + 1];
|
||||||
|
valsAtValue[0] = equ(x);
|
||||||
|
for (int i = 0; i < vals.Length; i++) valsAtValue[i + 1] = vals[i];
|
||||||
|
return Mathf.Sum(valsAtValue);
|
||||||
|
};
|
||||||
|
public static Equation Sum(this Equation equ, params Equation[] vals) => delegate (float x)
|
||||||
|
{
|
||||||
|
float[] valsAtValue = new float[vals.Length + 1];
|
||||||
|
valsAtValue[0] = equ(x);
|
||||||
|
for (int i = 0; i < vals.Length; i++) valsAtValue[i + 1] = vals[i](x);
|
||||||
|
return Mathf.Sum(valsAtValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Equation Tan(this Equation equ) => x => Mathf.Tan(equ(x));
|
||||||
|
|
||||||
|
public static Equation Tanh(this Equation equ) => x => Mathf.Tanh(equ(x));
|
||||||
|
|
||||||
|
public static Equation ZScore(this Equation equ, params float[] vals) => x => Mathf.ZScore(equ(x), vals);
|
||||||
|
public static Equation ZScore(this Equation equ, params Equation[] vals) => delegate (float x)
|
||||||
|
{
|
||||||
|
float[] valsAtValue = new float[vals.Length];
|
||||||
|
for (int i = 0; i < vals.Length; i++) valsAtValue[i] = vals[i](x);
|
||||||
|
return Mathf.ZScore(equ(x), valsAtValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Equation ZScore(this Equation equ, float mean, float stdev) =>
|
||||||
|
x => Mathf.ZScore(equ(x), mean, stdev);
|
||||||
|
public static Equation ZScore(this Equation equ, Equation mean, Equation stdev) =>
|
||||||
|
x => Mathf.ZScore(equ(x), mean(x), stdev(x));
|
||||||
|
|
||||||
|
public static Equation InvokeMethod(this Equation equ, MethodInfo method, params object?[]? args)
|
||||||
|
{
|
||||||
|
// Determine if this method is a valid method. This exception will be thrown if this method
|
||||||
|
// shouldn't be invoked this way. Might be able to be handled a bit better, but it works.
|
||||||
|
Exception throwIfBad = new BadMethodException("This method cannot be invoked in the context of an " +
|
||||||
|
nameof(Equation), method);
|
||||||
|
|
||||||
|
// Basic method property check.
|
||||||
|
if (method.IsAbstract || method.IsConstructor || method.IsGenericMethod || !method.IsPublic)
|
||||||
|
throw throwIfBad;
|
||||||
|
|
||||||
|
// Check if a valid number of arguments is provided and the first one takes a number.
|
||||||
|
ParameterInfo[] paramTypes = method.GetParameters();
|
||||||
|
int requiredParams = 0;
|
||||||
|
while (requiredParams < paramTypes.Length && !paramTypes[requiredParams].IsOptional) requiredParams++;
|
||||||
|
|
||||||
|
args ??= Array.Empty<object>();
|
||||||
|
if (args.Length + 1 < requiredParams || args.Length > paramTypes.Length) throw throwIfBad;
|
||||||
|
|
||||||
|
if (paramTypes.Length < 1) throw throwIfBad;
|
||||||
|
|
||||||
|
if (!ValidNumberTypes.Contains(paramTypes[0].ParameterType)) throw throwIfBad;
|
||||||
|
|
||||||
|
// Check if the return type is also a number.
|
||||||
|
if (!ValidNumberTypes.Contains(method.ReturnType)) throw throwIfBad;
|
||||||
|
|
||||||
|
// This is a good method. Generate the arguments required using the equation and invoke it.
|
||||||
|
// The first item in this list will be the float value of the equation.
|
||||||
|
List<object?> invokeArgs = new() { 0 };
|
||||||
|
invokeArgs.AddRange(args);
|
||||||
|
|
||||||
|
return delegate (float x)
|
||||||
|
{
|
||||||
|
// Invoke the method (with some casting of course).
|
||||||
|
invokeArgs[0] = Convert.ChangeType(equ(x), method.ReturnType);
|
||||||
|
object? result = method.Invoke(null, invokeArgs.ToArray());
|
||||||
|
|
||||||
|
if (result is null) throw new UndefinedException($"Invoked method \"{method.Name}\" returned null " +
|
||||||
|
"for this input.");
|
||||||
|
|
||||||
|
return (float)Convert.ChangeType(result, typeof(float));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static Equation InvokeMathMethod(this Equation equ, string name, params object?[]? args)
|
||||||
|
{
|
||||||
|
// Check a couple math classes to see if the method is found. If at least one is found,
|
||||||
|
// compare the parameters and return type to what is expected. If more than one perfect
|
||||||
|
// match exists, the first one will be selected.
|
||||||
|
|
||||||
|
args ??= Array.Empty<object>();
|
||||||
|
Type[] toCheck = { typeof(Mathf), typeof(Math) }; // This is the order methods should be searched in.
|
||||||
|
|
||||||
|
foreach (Type t in toCheck)
|
||||||
|
{
|
||||||
|
// Basic property and return checks.
|
||||||
|
List<MethodInfo> possibleMethods = (from m in t.GetMethods()
|
||||||
|
let basicCheck = !m.IsAbstract && !m.IsConstructor &&
|
||||||
|
!m.IsGenericMethod && m.IsPublic
|
||||||
|
let nameCheck = m.Name == name
|
||||||
|
let returnCheck = ValidNumberTypes.Contains(m.ReturnType)
|
||||||
|
where basicCheck && nameCheck && returnCheck
|
||||||
|
select m).ToList();
|
||||||
|
|
||||||
|
if (possibleMethods.Count < 1) continue;
|
||||||
|
|
||||||
|
foreach (MethodInfo m in possibleMethods)
|
||||||
|
{
|
||||||
|
// Check if a valid number of arguments is provided and the first one takes a number.
|
||||||
|
ParameterInfo[] paramTypes = m.GetParameters();
|
||||||
|
int requiredParams = 0;
|
||||||
|
while (requiredParams < paramTypes.Length && !paramTypes[requiredParams].IsOptional) requiredParams++;
|
||||||
|
|
||||||
|
args ??= Array.Empty<object>();
|
||||||
|
if (args.Length + 1 < requiredParams || args.Length > paramTypes.Length) continue;
|
||||||
|
|
||||||
|
if (paramTypes.Length < 1) continue;
|
||||||
|
|
||||||
|
if (!ValidNumberTypes.Contains(paramTypes[0].ParameterType)) continue;
|
||||||
|
|
||||||
|
// This is a good method. Generate the arguments required using the equation and invoke it.
|
||||||
|
// The first item in this list will be the float value of the equation.
|
||||||
|
List<object?> invokeArgs = new() { 0 };
|
||||||
|
invokeArgs.AddRange(args);
|
||||||
|
|
||||||
|
return delegate (float x)
|
||||||
|
{
|
||||||
|
// Invoke the method (with some casting of course).
|
||||||
|
invokeArgs[0] = Convert.ChangeType(equ(x), m.ReturnType);
|
||||||
|
object? result = m.Invoke(null, invokeArgs.ToArray());
|
||||||
|
|
||||||
|
if (result is null) throw new UndefinedException($"Invoked method \"{m.Name}\" returned " +
|
||||||
|
"null for this input.");
|
||||||
|
|
||||||
|
return (float)Convert.ChangeType(result, typeof(float));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new BadMethodException("No method that fits this criteria found in the math types.");
|
||||||
|
}
|
||||||
|
|
||||||
public static Equation Scale(this Equation equ, float value, ScaleType type = ScaleType.Both) => type switch
|
public static Equation Scale(this Equation equ, float value, ScaleType type = ScaleType.Both) => type switch
|
||||||
{
|
{
|
||||||
ScaleType.X => x => equ(x / value),
|
ScaleType.X => x => equ(x / value),
|
||||||
|
|||||||
101
Nerd_STF/Extensions/StringExtension.cs
Normal file
101
Nerd_STF/Extensions/StringExtension.cs
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
namespace Nerd_STF.Extensions;
|
||||||
|
|
||||||
|
public static class StringExtension
|
||||||
|
{
|
||||||
|
public static string? GetSection(this string str, string prefix, bool includeFix = true, int startIndex = 0,
|
||||||
|
int? endIndex = null)
|
||||||
|
{
|
||||||
|
endIndex ??= str.Length;
|
||||||
|
|
||||||
|
int start = str.IndexOf(prefix, startIndex);
|
||||||
|
if (start == -1 || start > endIndex.Value) return null;
|
||||||
|
|
||||||
|
int end = str.IndexOf(prefix, start + prefix.Length);
|
||||||
|
if (end == -1) end = str.Length;
|
||||||
|
else if (end > endIndex.Value) end = endIndex.Value;
|
||||||
|
|
||||||
|
if (includeFix)
|
||||||
|
{
|
||||||
|
start += prefix.Length;
|
||||||
|
if (start > end) return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str[start..end];
|
||||||
|
}
|
||||||
|
public static string? GetSection(this string str, string prefix, string suffix, bool includeFix = true,
|
||||||
|
int startIndex = 0, int? endIndex = null)
|
||||||
|
{
|
||||||
|
endIndex ??= str.Length;
|
||||||
|
|
||||||
|
int start = str.IndexOf(prefix, startIndex);
|
||||||
|
if (start == -1 || start > endIndex.Value) return null;
|
||||||
|
|
||||||
|
int end = str.IndexOf(suffix, start + prefix.Length);
|
||||||
|
if (end == -1) return null;
|
||||||
|
else if (end > endIndex.Value) end = endIndex.Value;
|
||||||
|
|
||||||
|
if (includeFix) start += prefix.Length;
|
||||||
|
else end += suffix.Length;
|
||||||
|
|
||||||
|
if (start > end) return null;
|
||||||
|
|
||||||
|
return str[start..end];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string[] GetSections(this string str, string prefix, bool includeFix = true, int startIndex = 0,
|
||||||
|
int? endIndex = null)
|
||||||
|
{
|
||||||
|
endIndex ??= str.Length;
|
||||||
|
|
||||||
|
List<string> sections = new();
|
||||||
|
for (int i = startIndex; i < endIndex && i < str.Length; )
|
||||||
|
{
|
||||||
|
int start = str.IndexOf(prefix, startIndex);
|
||||||
|
if (start == -1 || start > endIndex.Value) break;
|
||||||
|
|
||||||
|
int end = str.IndexOf(prefix, start + prefix.Length);
|
||||||
|
if (end == -1) end = str.Length;
|
||||||
|
else if (end > endIndex.Value) end = endIndex.Value;
|
||||||
|
|
||||||
|
if (includeFix)
|
||||||
|
{
|
||||||
|
start += prefix.Length;
|
||||||
|
if (start > end) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sections.Add(str[start..end]);
|
||||||
|
i = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sections.ToArray();
|
||||||
|
}
|
||||||
|
public static string[] GetSections(this string str, string prefix, string suffix, bool includeFix = true, int startIndex = 0,
|
||||||
|
int? endIndex = null)
|
||||||
|
{
|
||||||
|
endIndex ??= str.Length;
|
||||||
|
|
||||||
|
List<string> sections = new();
|
||||||
|
for (int i = startIndex; i < endIndex && i < str.Length; )
|
||||||
|
{
|
||||||
|
endIndex ??= str.Length;
|
||||||
|
|
||||||
|
int start = str.IndexOf(prefix, i);
|
||||||
|
if (start == -1 || start > endIndex.Value) break;
|
||||||
|
|
||||||
|
int end = str.IndexOf(suffix, start + prefix.Length);
|
||||||
|
if (end == -1) break;
|
||||||
|
else if (end > endIndex.Value) end = endIndex.Value;
|
||||||
|
|
||||||
|
if (includeFix) start += prefix.Length;
|
||||||
|
else end += suffix.Length;
|
||||||
|
|
||||||
|
if (start > end) break;
|
||||||
|
|
||||||
|
i = end;
|
||||||
|
|
||||||
|
sections.Add(str[start..end]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sections.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,3 @@
|
|||||||
namespace Nerd_STF;
|
namespace Nerd_STF;
|
||||||
|
|
||||||
public delegate T Fill2D<T>(int indexX, int indexY);
|
public delegate T Fill2d<T>(int indexX, int indexY);
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
namespace Nerd_STF;
|
|
||||||
|
|
||||||
[Obsolete("This delegate is kind of useless and will be removed in Nerd_STF v2.4.0.")]
|
|
||||||
public delegate void Foreach(object item);
|
|
||||||
[Obsolete("This delegate is kind of useless and will be removed in Nerd_STF v2.4.0.")]
|
|
||||||
public delegate void Foreach<T>(T item);
|
|
||||||
@ -29,7 +29,7 @@ public class Image : ICloneable, IEnumerable<IColor>, IEquatable<Image>
|
|||||||
Size = new(width, height);
|
Size = new(width, height);
|
||||||
for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) Pixels[x, y] = fill(y * width + x);
|
for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) Pixels[x, y] = fill(y * width + x);
|
||||||
}
|
}
|
||||||
public Image(int width, int height, Fill2D<IColor> fill)
|
public Image(int width, int height, Fill2d<IColor> fill)
|
||||||
{
|
{
|
||||||
Pixels = new IColor[width, height];
|
Pixels = new IColor[width, height];
|
||||||
Size = new(width, height);
|
Size = new(width, height);
|
||||||
@ -39,7 +39,7 @@ public class Image : ICloneable, IEnumerable<IColor>, IEquatable<Image>
|
|||||||
public Image(Int2 size, IColor[] cols) : this(size.x, size.y, cols) { }
|
public Image(Int2 size, IColor[] cols) : this(size.x, size.y, cols) { }
|
||||||
public Image(Int2 size, IColor[,] cols) : this(size.x, size.y, cols) { }
|
public Image(Int2 size, IColor[,] cols) : this(size.x, size.y, cols) { }
|
||||||
public Image(Int2 size, Fill<IColor> fill) : this(size.x, size.y, fill) { }
|
public Image(Int2 size, Fill<IColor> fill) : this(size.x, size.y, fill) { }
|
||||||
public Image(Int2 size, Fill2D<IColor> fill) : this(size.x, size.y, fill) { }
|
public Image(Int2 size, Fill2d<IColor> fill) : this(size.x, size.y, fill) { }
|
||||||
|
|
||||||
public IColor this[int indexX, int indexY]
|
public IColor this[int indexX, int indexY]
|
||||||
{
|
{
|
||||||
|
|||||||
317
Nerd_STF/Helpers/CordicHelper.cs
Normal file
317
Nerd_STF/Helpers/CordicHelper.cs
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
namespace Nerd_STF.Helpers;
|
||||||
|
|
||||||
|
// TODO: Make this internal
|
||||||
|
|
||||||
|
// Putting this in here for future reference:
|
||||||
|
// CORDIC is basically just splitting up an
|
||||||
|
// operation into more smaller operations.
|
||||||
|
// For example, turning sin(5rad) into
|
||||||
|
// sin(4rad + 1rad), which can be turned into
|
||||||
|
// the formula cos(4rad)cos(1rad) - sin(4rad)sin(1rad),
|
||||||
|
// to which we know the values of each part.
|
||||||
|
// Then we just do this iteratively on a bunch
|
||||||
|
// of powers of 2.
|
||||||
|
public static class CordicHelper
|
||||||
|
{
|
||||||
|
private static readonly float[] p_cosTable =
|
||||||
|
{
|
||||||
|
0.540302305868f, // cos(2^0)
|
||||||
|
0.87758256189f, // cos(2^-1)
|
||||||
|
0.968912421711f, // cos(2^-2)
|
||||||
|
0.992197667229f, // cos(2^-3)
|
||||||
|
0.9980475107f, // cos(2^-4)
|
||||||
|
0.999511758485f, // cos(2^-5)
|
||||||
|
0.999877932171f, // cos(2^-6)
|
||||||
|
0.999969482577f, // cos(2^-7)
|
||||||
|
0.999992370615f, // cos(2^-8)
|
||||||
|
0.999998092652f, // cos(2^-9)
|
||||||
|
0.999999523163f, // cos(2^-10)
|
||||||
|
0.999999880791f, // cos(2^-11)
|
||||||
|
0.999999970198f, // cos(2^-12)
|
||||||
|
0.999999992549f, // cos(2^-13)
|
||||||
|
0.999999998137f, // cos(2^-14)
|
||||||
|
0.999999999534f // cos(2^-15)
|
||||||
|
};
|
||||||
|
private static readonly float[] p_sinTable =
|
||||||
|
{
|
||||||
|
0.841470984808f, // sin(2^0)
|
||||||
|
0.479425538604f, // sin(2^-1)
|
||||||
|
0.247403959255f, // sin(2^-2)
|
||||||
|
0.124674733385f, // sin(2^-3)
|
||||||
|
0.0624593178424f, // sin(2^-4)
|
||||||
|
0.0312449139853f, // sin(2^-5)
|
||||||
|
0.0156243642249f, // sin(2^-6)
|
||||||
|
0.00781242052738f, // sin(2^-7)
|
||||||
|
0.0039062400659f, // sin(2^-8)
|
||||||
|
0.00195312375824f, // sin(2^-9)
|
||||||
|
0.00097656234478f, // sin(2^-10)
|
||||||
|
0.000488281230597f, // sin(2^-11)
|
||||||
|
0.000244140622575f, // sin(2^-12)
|
||||||
|
0.000122070312197f, // sin(2^-13)
|
||||||
|
0.0000610351562121f, // sin(2^-14)
|
||||||
|
0.0000305175781203f // sin(2^-15)
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly float[] p_coshTable =
|
||||||
|
{
|
||||||
|
1.54308063482f, // cosh(2^0)
|
||||||
|
1.12762596521f, // cosh(2^-1)
|
||||||
|
1.03141309988f, // cosh(2^-2)
|
||||||
|
1.00782267783f, // cosh(2^-3)
|
||||||
|
1.00195376087f, // cosh(2^-4)
|
||||||
|
1.00048832099f, // cosh(2^-5)
|
||||||
|
1.0001220728f, // cosh(2^-6)
|
||||||
|
1.00003051773f, // cosh(2^-7)
|
||||||
|
1.0000076294f, // cosh(2^-8)
|
||||||
|
1.00000190735f, // cosh(2^-9)
|
||||||
|
1.00000047684f, // cosh(2^-10)
|
||||||
|
1.00000011921f, // cosh(2^-11)
|
||||||
|
1.0000000298f, // cosh(2^-12)
|
||||||
|
1.00000000745f, // cosh(2^-13)
|
||||||
|
1.00000000186f, // cosh(2^-14)
|
||||||
|
1.00000000047f, // cosh(2^-15)
|
||||||
|
};
|
||||||
|
private static readonly float[] p_sinhTable =
|
||||||
|
{
|
||||||
|
1.17520119364f, // sinh(2^0)
|
||||||
|
0.521095305494f, // sinh(2^-1)
|
||||||
|
0.252612316808f, // sinh(2^-2)
|
||||||
|
0.125325775241f, // sinh(2^-3)
|
||||||
|
0.0625406980522f, // sinh(2^-4)
|
||||||
|
0.0312550865114f, // sinh(2^-5)
|
||||||
|
0.0156256357906f, // sinh(2^-6)
|
||||||
|
0.0078125794731f, // sinh(2^-7)
|
||||||
|
0.00390625993412f, // sinh(2^-8)
|
||||||
|
0.00195312624176f, // sinh(2^-9)
|
||||||
|
0.00097656265522f, // sinh(2^-10)
|
||||||
|
0.000488281269403f, // sinh(2^-11)
|
||||||
|
0.000244140627425f, // sinh(2^-12)
|
||||||
|
0.000122070312803f, // sinh(2^-13)
|
||||||
|
0.0000610351562879f, // sinh(2^-14)
|
||||||
|
0.0000305175781297f, // sinh(2^-15)
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly Dictionary<(float bas, int depth), float[]> p_expTables;
|
||||||
|
|
||||||
|
static CordicHelper()
|
||||||
|
{
|
||||||
|
p_expTables = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This was originally intended to replace the Mathf.Cos
|
||||||
|
// and Mathf.Sin functions, but it ended up being considerably
|
||||||
|
// slower. In the future if it gets optimized, I might then
|
||||||
|
// choose to replace it.
|
||||||
|
// REMEMBER: When implementing, remember to use Mathf.AbsoluteMod,
|
||||||
|
// because that's what I was intending when I wrote this.
|
||||||
|
public static (float sin, float cos) CalculateTrig(float x, int iterations)
|
||||||
|
{
|
||||||
|
float approximateX = 0,
|
||||||
|
approximateCos = 1,
|
||||||
|
approximateSin = 0;
|
||||||
|
|
||||||
|
// Iterate continuously until it gets better.
|
||||||
|
for (int i = 0; i < iterations; i++)
|
||||||
|
{
|
||||||
|
// We need to find the biggest step that'll move us
|
||||||
|
// closer to the real X (without overshooting).
|
||||||
|
float diffX = x - approximateX;
|
||||||
|
|
||||||
|
// This is assuming that cosTable and sinTable
|
||||||
|
// have the same length.
|
||||||
|
for (int j = 0; j < p_cosTable.Length; j++)
|
||||||
|
{
|
||||||
|
// The amount the difference will shrink.
|
||||||
|
float incX = FastGenExp2((sbyte)-j);
|
||||||
|
|
||||||
|
if (diffX >= incX)
|
||||||
|
{
|
||||||
|
// Because here we go big to small, the first one that triggers
|
||||||
|
// this if statement should also be the biggest one that can.
|
||||||
|
|
||||||
|
// Get the sin and cos values for this power of two.
|
||||||
|
float valCos = p_cosTable[j],
|
||||||
|
valSin = p_sinTable[j];
|
||||||
|
|
||||||
|
// Do the products.
|
||||||
|
float newCos = approximateCos * valCos - approximateSin * valSin,
|
||||||
|
newSin = approximateCos * valSin + approximateSin * valCos;
|
||||||
|
|
||||||
|
// Apply differences
|
||||||
|
approximateX += incX;
|
||||||
|
approximateCos = newCos;
|
||||||
|
approximateSin = newSin;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sin and cos should be pretty accurate by now,
|
||||||
|
// so we can return them.
|
||||||
|
return (approximateSin, approximateCos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static (float sinh, float cosh) CalculateHyperTrig(float x, int iterations)
|
||||||
|
{
|
||||||
|
float approximateX = 0,
|
||||||
|
approximateCosh = 1,
|
||||||
|
approximateSinh = 0;
|
||||||
|
|
||||||
|
// Iterate continuously until it gets better.
|
||||||
|
for (int i = 0; i < iterations; i++)
|
||||||
|
{
|
||||||
|
// We need to find the biggest step that'll move us
|
||||||
|
// closer to the real X (without overshooting).
|
||||||
|
float diffX = x - approximateX;
|
||||||
|
|
||||||
|
// This is assuming that cosTable and sinTable
|
||||||
|
// have the same length.
|
||||||
|
for (int j = 0; j < p_coshTable.Length; j++)
|
||||||
|
{
|
||||||
|
// The amount the difference will shrink.
|
||||||
|
float incX = FastGenExp2((sbyte)-j);
|
||||||
|
|
||||||
|
if (diffX >= incX)
|
||||||
|
{
|
||||||
|
// Because here we go big to small, the first one that triggers
|
||||||
|
// this if statement should also be the biggest one that can.
|
||||||
|
|
||||||
|
// Get the sin and cos values for this power of two.
|
||||||
|
float valCosh = p_coshTable[j],
|
||||||
|
valSinh = p_sinhTable[j];
|
||||||
|
|
||||||
|
// Do the products.
|
||||||
|
float newCosh = approximateCosh * valCosh + approximateSinh * valSinh,
|
||||||
|
newSinh = approximateCosh * valSinh + approximateSinh * valCosh;
|
||||||
|
|
||||||
|
// Apply differences
|
||||||
|
approximateX += incX;
|
||||||
|
approximateCosh = newCosh;
|
||||||
|
approximateSinh = newSinh;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sin and cos should be pretty accurate by now,
|
||||||
|
// so we can return them.
|
||||||
|
return (approximateSinh, approximateCosh);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float ExpAnyBase(float bas, float pow, int tableDepth, int iterations)
|
||||||
|
{
|
||||||
|
// We need to auto-generate a table of values for this number the user enters.
|
||||||
|
float[] table;
|
||||||
|
if (p_expTables.ContainsKey((bas, tableDepth)))
|
||||||
|
{
|
||||||
|
// Table was already generated, so we can reuse it.
|
||||||
|
table = p_expTables[(bas, tableDepth)];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Calculate a table for the CORDIC system by
|
||||||
|
// applying sequential square roots.
|
||||||
|
table = new float[tableDepth];
|
||||||
|
table[0] = bas;
|
||||||
|
for (int i = 1; i < tableDepth; i++) table[i] = Mathf.Sqrt(table[i - 1]);
|
||||||
|
p_expTables.Add((bas, tableDepth), table);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we can perform the CORDIC method.
|
||||||
|
float approximateX = 0, approximateVal = 1;
|
||||||
|
|
||||||
|
// Iterate continuously until it gets better.
|
||||||
|
for (int i = 0; i < iterations; i++)
|
||||||
|
{
|
||||||
|
// We need to find the biggest step that'll move us
|
||||||
|
// closer to the real X (without overshooting).
|
||||||
|
float diffX = pow - approximateX;
|
||||||
|
|
||||||
|
for (int j = 0; j < tableDepth; j++)
|
||||||
|
{
|
||||||
|
// The amount the difference will shrink.
|
||||||
|
float incX = FastGenExp2((sbyte)-j);
|
||||||
|
|
||||||
|
if (diffX >= incX)
|
||||||
|
{
|
||||||
|
// Because here we go big to small, the first one that triggers
|
||||||
|
// this if statement should also be the biggest one that can.
|
||||||
|
|
||||||
|
// Get the power value for this power of two.
|
||||||
|
float val = table[j];
|
||||||
|
|
||||||
|
// Apply our value.
|
||||||
|
approximateX += incX;
|
||||||
|
approximateVal *= val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value should be pretty accurate by now,
|
||||||
|
// so we can return it.
|
||||||
|
return approximateVal;
|
||||||
|
}
|
||||||
|
public static float LogAnyBase(float bas, float val, int tableDepth, int iterations)
|
||||||
|
{
|
||||||
|
// We need to auto-generate a table of values for this number the user enters.
|
||||||
|
// However, we can use the already existing exponent tables and just swap the
|
||||||
|
// indexes and the values.
|
||||||
|
float[] table;
|
||||||
|
if (p_expTables.ContainsKey((bas, tableDepth)))
|
||||||
|
{
|
||||||
|
// Table was already generated, so we can reuse it.
|
||||||
|
table = p_expTables[(bas, tableDepth)];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Calculate a table for the CORDIC system by
|
||||||
|
// applying sequential square roots.
|
||||||
|
table = new float[tableDepth];
|
||||||
|
table[0] = bas;
|
||||||
|
for (int i = 1; i < tableDepth; i++) table[i] = Mathf.Sqrt(table[i - 1]);
|
||||||
|
p_expTables.Add((bas, tableDepth), table);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we can perform the CORDIC method.
|
||||||
|
float approximateX = 0, approximateVal = 1;
|
||||||
|
|
||||||
|
// Iterate continuously until it gets better.
|
||||||
|
for (int i = 0; i < iterations; i++)
|
||||||
|
{
|
||||||
|
float diffY = val / approximateVal;
|
||||||
|
|
||||||
|
for (int j = 0; j < table.Length; j++)
|
||||||
|
{
|
||||||
|
// The amount the difference will shrink.
|
||||||
|
float incX = FastGenExp2((sbyte)-j);
|
||||||
|
float newVal = table[j];
|
||||||
|
|
||||||
|
if (diffY >= newVal)
|
||||||
|
{
|
||||||
|
// Because here we go big to small, the first one that triggers
|
||||||
|
// this if statement should also be the biggest one that can.
|
||||||
|
|
||||||
|
// Apply our value.
|
||||||
|
approximateX += incX;
|
||||||
|
approximateVal *= newVal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value should be pretty accurate by now,
|
||||||
|
// so we can return it.
|
||||||
|
return approximateX;
|
||||||
|
}
|
||||||
|
|
||||||
|
// An extremely fast way to generate 2 to
|
||||||
|
// the power of p. I say "generate" because I'm
|
||||||
|
// just messing with the mantissa's data and
|
||||||
|
// not doing any real math.
|
||||||
|
private static float FastGenExp2(sbyte p)
|
||||||
|
{
|
||||||
|
int data = (((p - 1) ^ 0b10000000) << 23) & ~(1 << 31);
|
||||||
|
return UnsafeHelper.SwapType<int, float>(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
91
Nerd_STF/Helpers/MathfHelper.cs
Normal file
91
Nerd_STF/Helpers/MathfHelper.cs
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
namespace Nerd_STF.Helpers;
|
||||||
|
|
||||||
|
internal static class MathfHelper
|
||||||
|
{
|
||||||
|
public static (int[] group, long max)[] MillerRabinWitnessNumbers =
|
||||||
|
{
|
||||||
|
(new int[] { 2, 3 }, 1_373_653),
|
||||||
|
(new int[] { 31, 73 }, 9_080_191),
|
||||||
|
(new int[] { 2, 3, 5 }, 25_326_001),
|
||||||
|
(new int[] { 2, 13, 23, 1_662_803 }, 1_122_004_669_633),
|
||||||
|
(new int[] { 2, 3, 5, 7, 11 }, 2_152_302_898_747),
|
||||||
|
(new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37 }, long.MaxValue) // The real maximum is 318_665_857_834_031_151_167_461
|
||||||
|
};
|
||||||
|
|
||||||
|
public static bool IsPrimeClassic(long num)
|
||||||
|
{
|
||||||
|
for (long i = 2; i <= num / 2; i++) if (num % i == 0) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x49204655434B494E47204C4F5645204E554D42525048494C45
|
||||||
|
// For some reason (I think the witnesses are slightly off), 12 numbers under 100,000
|
||||||
|
// are misrepresented as prime. I guess one of the witnesses becomes a liar for them.
|
||||||
|
// Mostly works though.
|
||||||
|
//
|
||||||
|
// TODO: In 2.10, the Mathf.PowerMod(int, int, int) method needs to be reworked to
|
||||||
|
// have a better O(n).
|
||||||
|
public static bool IsPrimeMillerRabin(long num)
|
||||||
|
{
|
||||||
|
// Negatives are composite, zero and one are composite, two and three are prime.
|
||||||
|
if (num <= 3) return num > 1;
|
||||||
|
|
||||||
|
long unchanged = num;
|
||||||
|
|
||||||
|
// Find the number's proper witness group.
|
||||||
|
int[]? witnessGroup = null;
|
||||||
|
for (int i = 0; i < MillerRabinWitnessNumbers.Length; i++)
|
||||||
|
{
|
||||||
|
if (num <= MillerRabinWitnessNumbers[i].max)
|
||||||
|
{
|
||||||
|
witnessGroup = MillerRabinWitnessNumbers[i].group;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (witnessGroup is null) throw new MathException($"The number {num} is out of range of the available witness " +
|
||||||
|
$"numbers. Use the {nameof(PrimeCheckMethod.Classic)} method instead."); // This should never happen.
|
||||||
|
|
||||||
|
// Prep the number for court.
|
||||||
|
num -= 1; // For clarity.
|
||||||
|
|
||||||
|
// Seperate out powers of two.
|
||||||
|
int m = 0;
|
||||||
|
while (num % 2 == 0)
|
||||||
|
{
|
||||||
|
m++;
|
||||||
|
num /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
long d = num; // The rest.
|
||||||
|
|
||||||
|
// Our number is rewritten as 2^m * d + 1
|
||||||
|
|
||||||
|
foreach (int a in witnessGroup)
|
||||||
|
{
|
||||||
|
// Calculate a^d = 1 mod n
|
||||||
|
// If true, the number *may* be prime (test all star numbers to be sure)
|
||||||
|
// If false, the number is *definitely* composite.
|
||||||
|
|
||||||
|
bool thinks = false;
|
||||||
|
for (int m2 = 0; m2 < m; m2++)
|
||||||
|
{
|
||||||
|
// Add any amount of multiples of two as given, but not as many as the original breakdown.
|
||||||
|
|
||||||
|
int additional = 1;
|
||||||
|
for (int m3 = 0; m3 < m2; m3++) additional *= 2;
|
||||||
|
|
||||||
|
long result = Mathf.PowerMod(a, additional * d, unchanged);
|
||||||
|
if (Mathf.AbsoluteMod(result + 1, unchanged) == 0 || Mathf.AbsoluteMod(result - 1, unchanged) == 0)
|
||||||
|
{
|
||||||
|
thinks = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!thinks) return false; // Definitely not prime.
|
||||||
|
else continue; // For clarity. A claim that the number is prime is not trustworthy until we've checked all witnesses.
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; // Probably prime.
|
||||||
|
}
|
||||||
|
}
|
||||||
48
Nerd_STF/Helpers/RationalHelper.cs
Normal file
48
Nerd_STF/Helpers/RationalHelper.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
namespace Nerd_STF.Helpers;
|
||||||
|
|
||||||
|
internal static class RationalHelper
|
||||||
|
{
|
||||||
|
public static Rational SimplifyAuto(float value)
|
||||||
|
{
|
||||||
|
string valueStr = value.ToString();
|
||||||
|
int pointIndex = valueStr.IndexOf(".");
|
||||||
|
if (pointIndex < 0) return new((int)value, 1);
|
||||||
|
|
||||||
|
int raise = valueStr.Substring(pointIndex + 1).Length;
|
||||||
|
int den = Mathf.Power(10, raise);
|
||||||
|
|
||||||
|
return new((int)(value * den), den);
|
||||||
|
}
|
||||||
|
public static Rational SimplifyFarey(float value, float tolerance, int maxIters)
|
||||||
|
{
|
||||||
|
float remainder = value % 1;
|
||||||
|
if (remainder == 0) return new((int)value, 1);
|
||||||
|
|
||||||
|
int additional = (int)(value - remainder);
|
||||||
|
|
||||||
|
Rational min = Rational.Zero, max = Rational.One;
|
||||||
|
Rational result;
|
||||||
|
float resultValue;
|
||||||
|
|
||||||
|
int iters = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
result = new(min.numerator + max.numerator, min.denominator + max.denominator, false);
|
||||||
|
resultValue = result.GetValue();
|
||||||
|
|
||||||
|
if (remainder == resultValue) break;
|
||||||
|
else if (remainder > resultValue) min = result;
|
||||||
|
else if (remainder < resultValue) max = result;
|
||||||
|
|
||||||
|
iters++;
|
||||||
|
if (maxIters != -1 && iters > maxIters) break;
|
||||||
|
}
|
||||||
|
while (Mathf.Absolute(resultValue - value) > tolerance);
|
||||||
|
|
||||||
|
if (additional != 0)
|
||||||
|
result = new(result.numerator + additional * result.denominator, result.denominator);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
Nerd_STF/Helpers/UnsafeHelper.cs
Normal file
13
Nerd_STF/Helpers/UnsafeHelper.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Nerd_STF.Helpers;
|
||||||
|
|
||||||
|
// These are all the unsafe functions I couldn't make safe. I don't want too much
|
||||||
|
// unsafe code, so this is where I put all of it that I require.
|
||||||
|
internal static unsafe class UnsafeHelper
|
||||||
|
{
|
||||||
|
// Forcefully change the type of an object
|
||||||
|
// without changing the data of the object.
|
||||||
|
public static NT SwapType<CT, NT>(CT obj)
|
||||||
|
where CT : unmanaged
|
||||||
|
where NT : unmanaged
|
||||||
|
=> *(NT*)&obj;
|
||||||
|
}
|
||||||
@ -1,6 +0,0 @@
|
|||||||
namespace Nerd_STF;
|
|
||||||
|
|
||||||
public interface IEncapsulator<T, TE> : IContains<TE> where T : IEquatable<T> where TE : IEquatable<TE>
|
|
||||||
{
|
|
||||||
public T Encapsulate(TE val);
|
|
||||||
}
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
namespace Nerd_STF;
|
namespace Nerd_STF;
|
||||||
|
|
||||||
public interface IGroup2D<T> : IGroup<T>
|
public interface IGroup2d<T> : IGroup<T>
|
||||||
{
|
{
|
||||||
public T[,] ToArray2D();
|
public T[,] ToArray2D();
|
||||||
public Fill2D<T> ToFill2D();
|
public Fill2d<T> ToFill2D();
|
||||||
}
|
}
|
||||||
|
|||||||
6
Nerd_STF/Mathematics/Abstract/IEncapsulate.cs
Normal file
6
Nerd_STF/Mathematics/Abstract/IEncapsulate.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace Nerd_STF.Mathematics.Abstract;
|
||||||
|
|
||||||
|
public interface IEncapsulate<T, TE> : IContains<TE> where T : IEquatable<T> where TE : IEquatable<TE>
|
||||||
|
{
|
||||||
|
public T Encapsulate(TE val);
|
||||||
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
namespace Nerd_STF.Mathematics.Abstract;
|
namespace Nerd_STF.Mathematics.Abstract;
|
||||||
|
|
||||||
public interface IMatrix<T> : IAbsolute<T>, ICeiling<T>, IClamp<T>, IDivide<T>,
|
public interface IMatrix<T> : IAbsolute<T>, ICeiling<T>, IClamp<T>, IDivide<T>,
|
||||||
IEquatable<T>, IFloor<T>, IGroup2D<float>, ILerp<T, float>, IProduct<T>, IRound<T>,
|
IEquatable<T>, IFloor<T>, IGroup2d<float>, ILerp<T, float>, IProduct<T>, IRound<T>,
|
||||||
ISubtract<T>, ISum<T>
|
ISubtract<T>, ISum<T>
|
||||||
where T : IMatrix<T>
|
where T : IMatrix<T>
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
namespace Nerd_STF.Mathematics.Abstract;
|
namespace Nerd_STF.Mathematics.Abstract;
|
||||||
|
|
||||||
public interface IPresets1D<T> where T : IPresets1D<T>
|
public interface IPresets1d<T> where T : IPresets1d<T>
|
||||||
{
|
{
|
||||||
public static abstract T One { get; }
|
public static abstract T One { get; }
|
||||||
public static abstract T Zero { get; }
|
public static abstract T Zero { get; }
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
namespace Nerd_STF.Mathematics.Abstract;
|
namespace Nerd_STF.Mathematics.Abstract;
|
||||||
|
|
||||||
public interface IPresets2D<T> : IPresets1D<T> where T : IPresets2D<T>
|
public interface IPresets2d<T> : IPresets1d<T> where T : IPresets2d<T>
|
||||||
{
|
{
|
||||||
public static abstract T Down { get; }
|
public static abstract T Down { get; }
|
||||||
public static abstract T Left { get; }
|
public static abstract T Left { get; }
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
namespace Nerd_STF.Mathematics.Abstract;
|
namespace Nerd_STF.Mathematics.Abstract;
|
||||||
|
|
||||||
public interface IPresets3D<T> : IPresets2D<T> where T : IPresets3D<T>
|
public interface IPresets3d<T> : IPresets2d<T> where T : IPresets3d<T>
|
||||||
{
|
{
|
||||||
public static abstract T Back { get; }
|
public static abstract T Back { get; }
|
||||||
public static abstract T Forward { get; }
|
public static abstract T Forward { get; }
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
namespace Nerd_STF.Mathematics.Abstract;
|
namespace Nerd_STF.Mathematics.Abstract;
|
||||||
|
|
||||||
public interface IPresets4D<T> : IPresets2D<T>, IPresets3D<T> where T : IPresets4D<T>
|
public interface IPresets4d<T> : IPresets2d<T>, IPresets3d<T> where T : IPresets4d<T>
|
||||||
{
|
{
|
||||||
public static abstract T HighW { get; }
|
public static abstract T HighW { get; }
|
||||||
public static abstract T LowW { get; }
|
public static abstract T LowW { get; }
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Nerd_STF.Mathematics.Abstract;
|
namespace Nerd_STF.Mathematics.Abstract;
|
||||||
|
|
||||||
public interface IShape2D<TNumber> where TNumber : INumber<TNumber>
|
public interface IShape2d<TNumber> where TNumber : INumber<TNumber>
|
||||||
{
|
{
|
||||||
public TNumber Area { get; }
|
public TNumber Area { get; }
|
||||||
public TNumber Perimeter { get; }
|
public TNumber Perimeter { get; }
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Nerd_STF.Mathematics.Abstract;
|
namespace Nerd_STF.Mathematics.Abstract;
|
||||||
|
|
||||||
public interface IShape3D<TNumber> where TNumber : INumber<TNumber>
|
public interface IShape3d<TNumber> where TNumber : INumber<TNumber>
|
||||||
{
|
{
|
||||||
public TNumber SurfaceArea { get; }
|
public TNumber SurfaceArea { get; }
|
||||||
public TNumber Volume { get; }
|
public TNumber Volume { get; }
|
||||||
|
|||||||
@ -20,7 +20,7 @@ public class Matrix : IMatrix<Matrix, Matrix>
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
public static Matrix One(Int2 size) => new(size, 1);
|
public static Matrix One(Int2 size) => new(size, 1);
|
||||||
public static Matrix SignGrid(Int2 size) => new(size, Equations.SgnFill);
|
public static Matrix SignGrid(Int2 size) => new(size, Fills.SignFill);
|
||||||
public static Matrix Zero(Int2 size) => new(size);
|
public static Matrix Zero(Int2 size) => new(size);
|
||||||
|
|
||||||
public bool HasMinors => Size.x > 1 && Size.y > 1;
|
public bool HasMinors => Size.x > 1 && Size.y > 1;
|
||||||
@ -85,13 +85,13 @@ public class Matrix : IMatrix<Matrix, Matrix>
|
|||||||
array = new float[size.x, size.y];
|
array = new float[size.x, size.y];
|
||||||
for (int r = 0; r < size.x; r++) for (int c = 0; c < size.y; c++) array[r, c] = vals[r, c];
|
for (int r = 0; r < size.x; r++) for (int c = 0; c < size.y; c++) array[r, c] = vals[r, c];
|
||||||
}
|
}
|
||||||
public Matrix(Int2 size, Fill2D<float> vals)
|
public Matrix(Int2 size, Fill2d<float> vals)
|
||||||
{
|
{
|
||||||
Size = size;
|
Size = size;
|
||||||
array = new float[size.x, size.y];
|
array = new float[size.x, size.y];
|
||||||
for (int r = 0; r < size.x; r++) for (int c = 0; c < size.y; c++) array[r, c] = vals(r, c);
|
for (int r = 0; r < size.x; r++) for (int c = 0; c < size.y; c++) array[r, c] = vals(r, c);
|
||||||
}
|
}
|
||||||
public Matrix(Int2 size, Fill2D<int> vals)
|
public Matrix(Int2 size, Fill2d<int> vals)
|
||||||
{
|
{
|
||||||
Size = size;
|
Size = size;
|
||||||
array = new float[size.x, size.y];
|
array = new float[size.x, size.y];
|
||||||
@ -188,7 +188,7 @@ public class Matrix : IMatrix<Matrix, Matrix>
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Apply(Modifier2D modifier)
|
public void Apply(Modifier2d modifier)
|
||||||
{
|
{
|
||||||
for (int r = 0; r < Size.x; r++) for (int c = 0; c < Size.y; c++)
|
for (int r = 0; r < Size.x; r++) for (int c = 0; c < Size.y; c++)
|
||||||
array[r, c] = modifier(new(r, c), array[r, c]);
|
array[r, c] = modifier(new(r, c), array[r, c]);
|
||||||
@ -310,7 +310,7 @@ public class Matrix : IMatrix<Matrix, Matrix>
|
|||||||
public float[] ToArray() => array.Flatten(new(Size.y, Size.x));
|
public float[] ToArray() => array.Flatten(new(Size.y, Size.x));
|
||||||
public float[,] ToArray2D() => array;
|
public float[,] ToArray2D() => array;
|
||||||
public Fill<float> ToFill() => ToFillExtension.ToFill(this);
|
public Fill<float> ToFill() => ToFillExtension.ToFill(this);
|
||||||
public Fill2D<float> ToFill2D()
|
public Fill2d<float> ToFill2D()
|
||||||
{
|
{
|
||||||
Matrix @this = this;
|
Matrix @this = this;
|
||||||
return (x, y) => @this[x, y];
|
return (x, y) => @this[x, y];
|
||||||
|
|||||||
@ -68,8 +68,8 @@ public record class Matrix2x2 : IStaticMatrix<Matrix2x2>
|
|||||||
public Matrix2x2(Fill<int> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
public Matrix2x2(Fill<int> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
||||||
public Matrix2x2(float[,] nums) : this(nums[0, 0], nums[0, 1], nums[1, 0], nums[1, 1]) { }
|
public Matrix2x2(float[,] nums) : this(nums[0, 0], nums[0, 1], nums[1, 0], nums[1, 1]) { }
|
||||||
public Matrix2x2(int[,] nums) : this(nums[0, 0], nums[0, 1], nums[1, 0], nums[1, 1]) { }
|
public Matrix2x2(int[,] nums) : this(nums[0, 0], nums[0, 1], nums[1, 0], nums[1, 1]) { }
|
||||||
public Matrix2x2(Fill2D<float> fill) : this(fill(0, 0), fill(0, 1), fill(1, 0), fill(1, 1)) { }
|
public Matrix2x2(Fill2d<float> fill) : this(fill(0, 0), fill(0, 1), fill(1, 0), fill(1, 1)) { }
|
||||||
public Matrix2x2(Fill2D<int> fill) : this(fill(0, 0), fill(0, 1), fill(1, 0), fill(1, 1)) { }
|
public Matrix2x2(Fill2d<int> fill) : this(fill(0, 0), fill(0, 1), fill(1, 0), fill(1, 1)) { }
|
||||||
public Matrix2x2(Float2 r1, Float2 r2) : this(r1.x, r1.y, r2.x, r2.y) { }
|
public Matrix2x2(Float2 r1, Float2 r2) : this(r1.x, r1.y, r2.x, r2.y) { }
|
||||||
public Matrix2x2(Fill<Float2> fill) : this(fill(0), fill(1)) { }
|
public Matrix2x2(Fill<Float2> fill) : this(fill(0), fill(1)) { }
|
||||||
public Matrix2x2(Fill<Int2> fill) : this((IEnumerable<int>)fill(0), fill(1)) { }
|
public Matrix2x2(Fill<Int2> fill) : this((IEnumerable<int>)fill(0), fill(1)) { }
|
||||||
@ -265,7 +265,7 @@ public record class Matrix2x2 : IStaticMatrix<Matrix2x2>
|
|||||||
{ r2c1, r2c2 }
|
{ r2c1, r2c2 }
|
||||||
};
|
};
|
||||||
public Fill<float> ToFill() => ToFillExtension.ToFill(this);
|
public Fill<float> ToFill() => ToFillExtension.ToFill(this);
|
||||||
public Fill2D<float> ToFill2D()
|
public Fill2d<float> ToFill2D()
|
||||||
{
|
{
|
||||||
Matrix2x2 @this = this;
|
Matrix2x2 @this = this;
|
||||||
return (x, y) => @this[x, y];
|
return (x, y) => @this[x, y];
|
||||||
|
|||||||
@ -106,9 +106,9 @@ public record class Matrix3x3 : IStaticMatrix<Matrix3x3>
|
|||||||
nums[1, 0], nums[1, 1], nums[1, 2], nums[2, 0], nums[2, 1], nums[2, 2]) { }
|
nums[1, 0], nums[1, 1], nums[1, 2], nums[2, 0], nums[2, 1], nums[2, 2]) { }
|
||||||
public Matrix3x3(int[,] nums) : this(nums[0, 0], nums[0, 1], nums[0, 2],
|
public Matrix3x3(int[,] nums) : this(nums[0, 0], nums[0, 1], nums[0, 2],
|
||||||
nums[1, 0], nums[1, 1], nums[1, 2], nums[2, 0], nums[2, 1], nums[2, 2]) { }
|
nums[1, 0], nums[1, 1], nums[1, 2], nums[2, 0], nums[2, 1], nums[2, 2]) { }
|
||||||
public Matrix3x3(Fill2D<float> fill) : this(fill(0, 0), fill(0, 1), fill(0, 2),
|
public Matrix3x3(Fill2d<float> fill) : this(fill(0, 0), fill(0, 1), fill(0, 2),
|
||||||
fill(1, 0), fill(1, 1), fill(1, 2), fill(2, 0), fill(2, 1), fill(2, 2)) { }
|
fill(1, 0), fill(1, 1), fill(1, 2), fill(2, 0), fill(2, 1), fill(2, 2)) { }
|
||||||
public Matrix3x3(Fill2D<int> fill) : this(fill(0, 0), fill(0, 1), fill(0, 2),
|
public Matrix3x3(Fill2d<int> fill) : this(fill(0, 0), fill(0, 1), fill(0, 2),
|
||||||
fill(1, 0), fill(1, 1), fill(1, 2), fill(2, 0), fill(2, 1), fill(2, 2)) { }
|
fill(1, 0), fill(1, 1), fill(1, 2), fill(2, 0), fill(2, 1), fill(2, 2)) { }
|
||||||
public Matrix3x3(Float3 r1, Float3 r2, Float3 r3) : this(r1.x, r1.y, r1.z, r2.x, r2.y, r2.z, r3.x, r3.y, r3.z) { }
|
public Matrix3x3(Float3 r1, Float3 r2, Float3 r3) : this(r1.x, r1.y, r1.z, r2.x, r2.y, r2.z, r3.x, r3.y, r3.z) { }
|
||||||
public Matrix3x3(Fill<Float3> fill) : this(fill(0), fill(1), fill(2)) { }
|
public Matrix3x3(Fill<Float3> fill) : this(fill(0), fill(1), fill(2)) { }
|
||||||
@ -371,7 +371,7 @@ public record class Matrix3x3 : IStaticMatrix<Matrix3x3>
|
|||||||
{ r3c1, r3c2, r3c3 }
|
{ r3c1, r3c2, r3c3 }
|
||||||
};
|
};
|
||||||
public Fill<float> ToFill() => ToFillExtension.ToFill(this);
|
public Fill<float> ToFill() => ToFillExtension.ToFill(this);
|
||||||
public Fill2D<float> ToFill2D()
|
public Fill2d<float> ToFill2D()
|
||||||
{
|
{
|
||||||
Matrix3x3 @this = this;
|
Matrix3x3 @this = this;
|
||||||
return (x, y) => @this[x, y];
|
return (x, y) => @this[x, y];
|
||||||
|
|||||||
@ -146,10 +146,10 @@ public record class Matrix4x4 : IStaticMatrix<Matrix4x4>
|
|||||||
public Matrix4x4(int[,] nums) : this(nums[0, 0], nums[0, 1], nums[0, 2], nums[0, 3], nums[1, 0],
|
public Matrix4x4(int[,] nums) : this(nums[0, 0], nums[0, 1], nums[0, 2], nums[0, 3], nums[1, 0],
|
||||||
nums[1, 1], nums[1, 2], nums[1, 3], nums[2, 0], nums[2, 1], nums[2, 2], nums[2, 3], nums[3, 0],
|
nums[1, 1], nums[1, 2], nums[1, 3], nums[2, 0], nums[2, 1], nums[2, 2], nums[2, 3], nums[3, 0],
|
||||||
nums[3, 1], nums[3, 2], nums[3, 3]) { }
|
nums[3, 1], nums[3, 2], nums[3, 3]) { }
|
||||||
public Matrix4x4(Fill2D<float> fill) : this(fill(0, 0), fill(0, 1), fill(0, 2), fill(0, 3), fill(1, 0),
|
public Matrix4x4(Fill2d<float> fill) : this(fill(0, 0), fill(0, 1), fill(0, 2), fill(0, 3), fill(1, 0),
|
||||||
fill(1, 1), fill(1, 2), fill(1, 3), fill(2, 0), fill(2, 1), fill(2, 2), fill(2, 3), fill(3, 0),
|
fill(1, 1), fill(1, 2), fill(1, 3), fill(2, 0), fill(2, 1), fill(2, 2), fill(2, 3), fill(3, 0),
|
||||||
fill(3, 1), fill(3, 2), fill(3, 3)) { }
|
fill(3, 1), fill(3, 2), fill(3, 3)) { }
|
||||||
public Matrix4x4(Fill2D<int> fill) : this(fill(0, 0), fill(0, 1), fill(0, 2), fill(0, 3), fill(1, 0),
|
public Matrix4x4(Fill2d<int> fill) : this(fill(0, 0), fill(0, 1), fill(0, 2), fill(0, 3), fill(1, 0),
|
||||||
fill(1, 1), fill(1, 2), fill(1, 3), fill(2, 0), fill(2, 1), fill(2, 2), fill(2, 3), fill(3, 0),
|
fill(1, 1), fill(1, 2), fill(1, 3), fill(2, 0), fill(2, 1), fill(2, 2), fill(2, 3), fill(3, 0),
|
||||||
fill(3, 1), fill(3, 2), fill(3, 3)) { }
|
fill(3, 1), fill(3, 2), fill(3, 3)) { }
|
||||||
public Matrix4x4(Float4 r1, Float4 r2, Float4 r3, Float4 r4) : this(r1.x, r1.y, r1.z,
|
public Matrix4x4(Float4 r1, Float4 r2, Float4 r3, Float4 r4) : this(r1.x, r1.y, r1.z,
|
||||||
@ -502,7 +502,7 @@ public record class Matrix4x4 : IStaticMatrix<Matrix4x4>
|
|||||||
{ r4c1, r4c2, r4c3, r4c4 }
|
{ r4c1, r4c2, r4c3, r4c4 }
|
||||||
};
|
};
|
||||||
public Fill<float> ToFill() => ToFillExtension.ToFill(this);
|
public Fill<float> ToFill() => ToFillExtension.ToFill(this);
|
||||||
public Fill2D<float> ToFill2D()
|
public Fill2d<float> ToFill2D()
|
||||||
{
|
{
|
||||||
Matrix4x4 @this = this;
|
Matrix4x4 @this = this;
|
||||||
return (x, y) => @this[x, y];
|
return (x, y) => @this[x, y];
|
||||||
|
|||||||
@ -4,7 +4,7 @@ public record struct Vector2d : IAbsolute<Vector2d>, IAverage<Vector2d>,
|
|||||||
IClampMagnitude<Vector2d, float>, IComparable<Vector2d>, ICross<Vector2d, Vector3d>,
|
IClampMagnitude<Vector2d, float>, IComparable<Vector2d>, ICross<Vector2d, Vector3d>,
|
||||||
IDot<Vector2d, float>, IEquatable<Vector2d>, IFromTuple<Vector2d, (Angle angle, float mag)>,
|
IDot<Vector2d, float>, IEquatable<Vector2d>, IFromTuple<Vector2d, (Angle angle, float mag)>,
|
||||||
ILerp<Vector2d, float>, IMax<Vector2d>, IMagnitude<float>, IMedian<Vector2d>, IMin<Vector2d>,
|
ILerp<Vector2d, float>, IMax<Vector2d>, IMagnitude<float>, IMedian<Vector2d>, IMin<Vector2d>,
|
||||||
IPresets2D<Vector2d>, ISplittable<Vector2d, (Angle[] rots, float[] mags)>, ISubtract<Vector2d>,
|
IPresets2d<Vector2d>, ISplittable<Vector2d, (Angle[] rots, float[] mags)>, ISubtract<Vector2d>,
|
||||||
ISum<Vector2d>
|
ISum<Vector2d>
|
||||||
{
|
{
|
||||||
public static Vector2d Down => new(Angle.Down);
|
public static Vector2d Down => new(Angle.Down);
|
||||||
|
|||||||
@ -4,7 +4,7 @@ public record struct Vector3d : IAbsolute<Vector3d>, IAverage<Vector3d>, IClampM
|
|||||||
IComparable<Vector3d>, ICross<Vector3d>, IDot<Vector3d, float>, IEquatable<Vector3d>,
|
IComparable<Vector3d>, ICross<Vector3d>, IDot<Vector3d, float>, IEquatable<Vector3d>,
|
||||||
IFromTuple<Vector3d, (Angle yaw, Angle pitch, float mag)>, IIndexAll<Angle>, IIndexRangeAll<Angle>,
|
IFromTuple<Vector3d, (Angle yaw, Angle pitch, float mag)>, IIndexAll<Angle>, IIndexRangeAll<Angle>,
|
||||||
ILerp<Vector3d, float>, IMagnitude<float>, IMax<Vector3d>, IMedian<Vector3d>, IMin<Vector3d>,
|
ILerp<Vector3d, float>, IMagnitude<float>, IMax<Vector3d>, IMedian<Vector3d>, IMin<Vector3d>,
|
||||||
IPresets3D<Vector3d>, ISubtract<Vector3d>, ISum<Vector3d>
|
IPresets3d<Vector3d>, ISubtract<Vector3d>, ISum<Vector3d>
|
||||||
{
|
{
|
||||||
public static Vector3d Back => new(Angle.Zero, Angle.Up);
|
public static Vector3d Back => new(Angle.Zero, Angle.Up);
|
||||||
public static Vector3d Down => new(Angle.Down, Angle.Zero);
|
public static Vector3d Down => new(Angle.Down, Angle.Zero);
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
public struct Angle : IAbsolute<Angle>, IAverage<Angle>, IClamp<Angle>, ICloneable,
|
public struct Angle : IAbsolute<Angle>, IAverage<Angle>, IClamp<Angle>, ICloneable,
|
||||||
IComparable<Angle>, IEquatable<Angle>, ILerp<Angle, float>, IMax<Angle>, IMedian<Angle>,
|
IComparable<Angle>, IEquatable<Angle>, ILerp<Angle, float>, IMax<Angle>, IMedian<Angle>,
|
||||||
IMin<Angle>, IPresets2D<Angle>
|
IMin<Angle>, IPresets2d<Angle>
|
||||||
{
|
{
|
||||||
public static Angle Down => new(270);
|
public static Angle Down => new(270);
|
||||||
public static Angle Left => new(180);
|
public static Angle Left => new(180);
|
||||||
|
|||||||
@ -7,7 +7,7 @@ public static class Calculus
|
|||||||
public static Equation GetDerivative(Equation equ, float step = DefaultStep) =>
|
public static Equation GetDerivative(Equation equ, float step = DefaultStep) =>
|
||||||
x => GetDerivativeAtPoint(equ, x, step);
|
x => GetDerivativeAtPoint(equ, x, step);
|
||||||
public static float GetDerivativeAtPoint(Equation equ, float x, float step = DefaultStep) =>
|
public static float GetDerivativeAtPoint(Equation equ, float x, float step = DefaultStep) =>
|
||||||
(equ(x + DefaultStep) - equ(x)) / step;
|
(equ(x + step) - equ(x)) / step;
|
||||||
|
|
||||||
public static float GetIntegral(Equation equ, float lowerBound, float upperBound, float step = DefaultStep)
|
public static float GetIntegral(Equation equ, float lowerBound, float upperBound, float step = DefaultStep)
|
||||||
{
|
{
|
||||||
@ -19,14 +19,38 @@ public static class Calculus
|
|||||||
public static Equation GetDynamicIntegral(Equation equ, Equation lowerBound, Equation upperBound,
|
public static Equation GetDynamicIntegral(Equation equ, Equation lowerBound, Equation upperBound,
|
||||||
float step = DefaultStep) => x => GetIntegral(equ, lowerBound(x), upperBound(x), step);
|
float step = DefaultStep) => x => GetIntegral(equ, lowerBound(x), upperBound(x), step);
|
||||||
|
|
||||||
|
public static Equation GetTaylorSeries(Equation equ, float referenceX, int iterations = 4, float step = 0.01f)
|
||||||
|
{
|
||||||
|
Equation activeDerivative = equ;
|
||||||
|
float[] coefficients = new float[iterations];
|
||||||
|
int fact = 1;
|
||||||
|
for (int i = 0; i < iterations; i++)
|
||||||
|
{
|
||||||
|
coefficients[i] = activeDerivative(referenceX) / fact;
|
||||||
|
activeDerivative = GetDerivative(activeDerivative, step);
|
||||||
|
fact *= i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return delegate (float x)
|
||||||
|
{
|
||||||
|
float xVal = 1, result = 0;
|
||||||
|
for (int i = 0; i < coefficients.Length; i++)
|
||||||
|
{
|
||||||
|
result += coefficients[i] * xVal;
|
||||||
|
xVal *= x;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Unfortunately, I cannot test this function, as I have literally no idea how it works and
|
// Unfortunately, I cannot test this function, as I have literally no idea how it works and
|
||||||
// I can't find any tools online (and couldn't make my own) to compare my results.
|
// I can't find any tools online (and couldn't make my own) to compare my results.
|
||||||
// Something to know, though I didn't feel like it deserved its own [Obsolete] attribute.
|
// Something to know, though I didn't feel like it deserved its own [Obsolete] attribute.
|
||||||
public static float GradientDescent(Equation equ, float initial, float rate, float stepCount = 1000,
|
public static float GradientDescent(Equation equ, float initial, float rate, int iterations = 1000,
|
||||||
float step = DefaultStep)
|
float step = DefaultStep)
|
||||||
{
|
{
|
||||||
float val = initial;
|
float val = initial;
|
||||||
for (int i = 0; i < stepCount; i++) val -= GetDerivativeAtPoint(equ, val, step) * rate;
|
for (int i = 0; i < iterations; i++) val -= GetDerivativeAtPoint(equ, val, step) * rate;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
Nerd_STF/Mathematics/Equation2d.cs
Normal file
3
Nerd_STF/Mathematics/Equation2d.cs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
namespace Nerd_STF.Mathematics;
|
||||||
|
|
||||||
|
public delegate Complex Equation2d(Complex input);
|
||||||
@ -5,7 +5,7 @@ public record struct Float2 : IAbsolute<Float2>, IAverage<Float2>, ICeiling<Floa
|
|||||||
ICross<Float2, Float3>, IDivide<Float2>, IDot<Float2, float>, IEquatable<Float2>,
|
ICross<Float2, Float3>, IDivide<Float2>, IDot<Float2, float>, IEquatable<Float2>,
|
||||||
IFloor<Float2, Int2>, IFromTuple<Float2, (float x, float y)>, IGroup<float>,
|
IFloor<Float2, Int2>, IFromTuple<Float2, (float x, float y)>, IGroup<float>,
|
||||||
ILerp<Float2, float>, IMathOperators<Float2>, IMax<Float2>, IMedian<Float2>, IMin<Float2>,
|
ILerp<Float2, float>, IMathOperators<Float2>, IMax<Float2>, IMedian<Float2>, IMin<Float2>,
|
||||||
IIndexAll<float>, IIndexRangeAll<float>, IPresets2D<Float2>, IProduct<Float2>, IRound<Float2, Int2>,
|
IIndexAll<float>, IIndexRangeAll<float>, IPresets2d<Float2>, IProduct<Float2>, IRound<Float2, Int2>,
|
||||||
ISplittable<Float2, (float[] Xs, float[] Ys)>, ISubtract<Float2>, ISum<Float2>
|
ISplittable<Float2, (float[] Xs, float[] Ys)>, ISubtract<Float2>, ISum<Float2>
|
||||||
{
|
{
|
||||||
public static Float2 Down => new(0, -1);
|
public static Float2 Down => new(0, -1);
|
||||||
@ -162,8 +162,6 @@ public record struct Float2 : IAbsolute<Float2>, IAverage<Float2>, ICeiling<Floa
|
|||||||
return (Xs, Ys);
|
return (Xs, Ys);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("This method is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public int CompareTo(Float2 other) => Magnitude.CompareTo(other.Magnitude);
|
public int CompareTo(Float2 other) => Magnitude.CompareTo(other.Magnitude);
|
||||||
public bool Equals(Float2 other) => x == other.x && y == other.y;
|
public bool Equals(Float2 other) => x == other.x && y == other.y;
|
||||||
public override int GetHashCode() => base.GetHashCode();
|
public override int GetHashCode() => base.GetHashCode();
|
||||||
@ -204,18 +202,6 @@ public record struct Float2 : IAbsolute<Float2>, IAverage<Float2>, ICeiling<Floa
|
|||||||
public static Float2 operator /(Float2 a, Float2 b) => new(a.x / b.x, a.y / b.y);
|
public static Float2 operator /(Float2 a, Float2 b) => new(a.x / b.x, a.y / b.y);
|
||||||
public static Float2 operator /(Float2 a, float b) => new(a.x / b, a.y / b);
|
public static Float2 operator /(Float2 a, float b) => new(a.x / b, a.y / b);
|
||||||
public static Float2 operator /(Float2 a, Matrix b) => (Float2)((Matrix)a / b);
|
public static Float2 operator /(Float2 a, Matrix b) => (Float2)((Matrix)a / b);
|
||||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator >(Float2 a, Float2 b) => a.CompareTo(b) > 0;
|
|
||||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator <(Float2 a, Float2 b) => a.CompareTo(b) < 0;
|
|
||||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
|
||||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator >=(Float2 a, Float2 b) => a == b || a > b;
|
|
||||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
|
||||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator <=(Float2 a, Float2 b) => a == b || a < b;
|
|
||||||
|
|
||||||
public static implicit operator Float2(Complex val) => new(val.u, val.i);
|
public static implicit operator Float2(Complex val) => new(val.u, val.i);
|
||||||
public static explicit operator Float2(Quaternion val) => new(val.u, val.i);
|
public static explicit operator Float2(Quaternion val) => new(val.u, val.i);
|
||||||
|
|||||||
@ -7,7 +7,7 @@ public record struct Float3 : IAbsolute<Float3>, IAverage<Float3>,
|
|||||||
ICross<Float3>, IDivide<Float3>, IDot<Float3, float>, IEquatable<Float3>,
|
ICross<Float3>, IDivide<Float3>, IDot<Float3, float>, IEquatable<Float3>,
|
||||||
IFloor<Float3, Int3>, IFromTuple<Float3, (float x, float y, float z)>, IGroup<float>,
|
IFloor<Float3, Int3>, IFromTuple<Float3, (float x, float y, float z)>, IGroup<float>,
|
||||||
IIndexAll<float>, IIndexRangeAll<float>, ILerp<Float3, float>, IMathOperators<Float3>, IMax<Float3>,
|
IIndexAll<float>, IIndexRangeAll<float>, ILerp<Float3, float>, IMathOperators<Float3>, IMax<Float3>,
|
||||||
IMedian<Float3>, IMin<Float3>, IPresets3D<Float3>, IProduct<Float3>, IRound<Float3, Int3>,
|
IMedian<Float3>, IMin<Float3>, IPresets3d<Float3>, IProduct<Float3>, IRound<Float3, Int3>,
|
||||||
ISplittable<Float3, (float[] Xs, float[] Ys, float[] Zs)>, ISubtract<Float3>, ISum<Float3>
|
ISplittable<Float3, (float[] Xs, float[] Ys, float[] Zs)>, ISubtract<Float3>, ISum<Float3>
|
||||||
{
|
{
|
||||||
public static Float3 Back => new(0, 0, -1);
|
public static Float3 Back => new(0, 0, -1);
|
||||||
@ -186,8 +186,6 @@ public record struct Float3 : IAbsolute<Float3>, IAverage<Float3>,
|
|||||||
return (Xs, Ys, Zs);
|
return (Xs, Ys, Zs);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("This method is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public int CompareTo(Float3 other) => Magnitude.CompareTo(other.Magnitude);
|
public int CompareTo(Float3 other) => Magnitude.CompareTo(other.Magnitude);
|
||||||
public bool Equals(Float3 other) => x == other.x && y == other.y && z == other.z;
|
public bool Equals(Float3 other) => x == other.x && y == other.y && z == other.z;
|
||||||
public override int GetHashCode() => base.GetHashCode();
|
public override int GetHashCode() => base.GetHashCode();
|
||||||
@ -238,18 +236,6 @@ public record struct Float3 : IAbsolute<Float3>, IAverage<Float3>,
|
|||||||
public static Float3 operator /(Float3 a, Float3 b) => new(a.x / b.x, a.y / b.y, a.z / b.z);
|
public static Float3 operator /(Float3 a, Float3 b) => new(a.x / b.x, a.y / b.y, a.z / b.z);
|
||||||
public static Float3 operator /(Float3 a, float b) => new(a.x / b, a.y / b, a.z / b);
|
public static Float3 operator /(Float3 a, float b) => new(a.x / b, a.y / b, a.z / b);
|
||||||
public static Float3 operator /(Float3 a, Matrix b) => (Float3)((Matrix)a / b);
|
public static Float3 operator /(Float3 a, Matrix b) => (Float3)((Matrix)a / b);
|
||||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator >(Float3 a, Float3 b) => a.CompareTo(b) > 0;
|
|
||||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator <(Float3 a, Float3 b) => a.CompareTo(b) < 0;
|
|
||||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
|
||||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator >=(Float3 a, Float3 b) => a == b || a > b;
|
|
||||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
|
||||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator <=(Float3 a, Float3 b) => a == b || a < b;
|
|
||||||
|
|
||||||
public static implicit operator Float3(Complex val) => new(val.u, val.i, 0);
|
public static implicit operator Float3(Complex val) => new(val.u, val.i, 0);
|
||||||
public static explicit operator Float3(Quaternion val) => new(val.u, val.i, val.j);
|
public static explicit operator Float3(Quaternion val) => new(val.u, val.i, val.j);
|
||||||
|
|||||||
@ -5,22 +5,16 @@ public record struct Float4 : IAbsolute<Float4>,
|
|||||||
IComparable<Float4>, IDivide<Float4>, IDot<Float4, float>, IEquatable<Float4>,
|
IComparable<Float4>, IDivide<Float4>, IDot<Float4, float>, IEquatable<Float4>,
|
||||||
IFloor<Float4, Int4>, IFromTuple<Float4, (float x, float y, float z, float w)>,
|
IFloor<Float4, Int4>, IFromTuple<Float4, (float x, float y, float z, float w)>,
|
||||||
IGroup<float>, IIndexAll<float>, IIndexRangeAll<float>, ILerp<Float4, float>, IMathOperators<Float4>,
|
IGroup<float>, IIndexAll<float>, IIndexRangeAll<float>, ILerp<Float4, float>, IMathOperators<Float4>,
|
||||||
IMax<Float4>, IMedian<Float4>, IMin<Float4>, IPresets4D<Float4>, IProduct<Float4>, IRound<Float4, Int4>,
|
IMax<Float4>, IMedian<Float4>, IMin<Float4>, IPresets4d<Float4>, IProduct<Float4>, IRound<Float4, Int4>,
|
||||||
ISplittable<Float4, (float[] Xs, float[] Ys, float[] Zs, float[] Ws)>, ISubtract<Float4>,
|
ISplittable<Float4, (float[] Xs, float[] Ys, float[] Zs, float[] Ws)>, ISubtract<Float4>,
|
||||||
ISum<Float4>
|
ISum<Float4>
|
||||||
{
|
{
|
||||||
public static Float4 Back => new(0, 0, -1, 0);
|
public static Float4 Back => new(0, 0, -1, 0);
|
||||||
public static Float4 Down => new(0, -1, 0, 0);
|
public static Float4 Down => new(0, -1, 0, 0);
|
||||||
[Obsolete("Field has been replaced by " + nameof(HighW) + ", because it has a better name. " +
|
|
||||||
"This field will be removed in v2.4.0.", false)]
|
|
||||||
public static Float4 Far => new(0, 0, 0, 1);
|
|
||||||
public static Float4 Forward => new(0, 0, 1, 0);
|
public static Float4 Forward => new(0, 0, 1, 0);
|
||||||
public static Float4 HighW => new(0, 0, 0, 1);
|
public static Float4 HighW => new(0, 0, 0, 1);
|
||||||
public static Float4 Left => new(-1, 0, 0, 0);
|
public static Float4 Left => new(-1, 0, 0, 0);
|
||||||
public static Float4 LowW => new(0, 0, 0, -1);
|
public static Float4 LowW => new(0, 0, 0, -1);
|
||||||
[Obsolete("Field has been replaced by " + nameof(LowW) + ", because it has a better name. " +
|
|
||||||
"This field will be removed in v2.4.0.", false)]
|
|
||||||
public static Float4 Near => new(0, 0, 0, -1);
|
|
||||||
public static Float4 Right => new(1, 0, 0, 0);
|
public static Float4 Right => new(1, 0, 0, 0);
|
||||||
public static Float4 Up => new(0, 1, 0, 0);
|
public static Float4 Up => new(0, 1, 0, 0);
|
||||||
|
|
||||||
@ -207,8 +201,6 @@ public record struct Float4 : IAbsolute<Float4>,
|
|||||||
return (Xs, Ys, Zs, Ws);
|
return (Xs, Ys, Zs, Ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("This method is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public int CompareTo(Float4 other) => Magnitude.CompareTo(other.Magnitude);
|
public int CompareTo(Float4 other) => Magnitude.CompareTo(other.Magnitude);
|
||||||
public bool Equals(Float4 other) => x == other.x && y == other.y && z == other.z && w == other.w;
|
public bool Equals(Float4 other) => x == other.x && y == other.y && z == other.z && w == other.w;
|
||||||
public override int GetHashCode() => base.GetHashCode();
|
public override int GetHashCode() => base.GetHashCode();
|
||||||
@ -252,18 +244,6 @@ public record struct Float4 : IAbsolute<Float4>,
|
|||||||
public static Float4 operator /(Float4 a, Float4 b) => new(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);
|
public static Float4 operator /(Float4 a, Float4 b) => new(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);
|
||||||
public static Float4 operator /(Float4 a, float b) => new(a.x / b, a.y / b, a.z / b, a.w / b);
|
public static Float4 operator /(Float4 a, float b) => new(a.x / b, a.y / b, a.z / b, a.w / b);
|
||||||
public static Float4 operator /(Float4 a, Matrix b) => (Float4)((Matrix)a / b);
|
public static Float4 operator /(Float4 a, Matrix b) => (Float4)((Matrix)a / b);
|
||||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator >(Float4 a, Float4 b) => a.CompareTo(b) > 0;
|
|
||||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator <(Float4 a, Float4 b) => a.CompareTo(b) < 0;
|
|
||||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
|
||||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator >=(Float4 a, Float4 b) => a == b || a > b;
|
|
||||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
|
||||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator <=(Float4 a, Float4 b) => a == b || a < b;
|
|
||||||
|
|
||||||
public static implicit operator Float4(Complex val) => new(val.u, val.i, 0, 0);
|
public static implicit operator Float4(Complex val) => new(val.u, val.i, 0, 0);
|
||||||
public static implicit operator Float4(Quaternion val) => new(val.u, val.i, val.j, val.k);
|
public static implicit operator Float4(Quaternion val) => new(val.u, val.i, val.j, val.k);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
namespace Nerd_STF.Mathematics.Geometry;
|
namespace Nerd_STF.Mathematics.Geometry;
|
||||||
|
|
||||||
public record class Box2D : IAbsolute<Box2D>, IAverage<Box2D>, ICeiling<Box2D>, IClamp<Box2D>, IContains<Vert>,
|
public record class Box2D : IAbsolute<Box2D>, IAverage<Box2D>, ICeiling<Box2D>, IClamp<Box2D>, IContains<Vert>,
|
||||||
IEquatable<Box2D>, IFloor<Box2D>, ILerp<Box2D, float>, IMedian<Box2D>, IRound<Box2D>, IShape2D<float>,
|
IEquatable<Box2D>, IFloor<Box2D>, ILerp<Box2D, float>, IMedian<Box2D>, IRound<Box2D>, IShape2d<float>,
|
||||||
ISplittable<Box2D, (Vert[] centers, Float2[] sizes)>
|
ISplittable<Box2D, (Vert[] centers, Float2[] sizes)>
|
||||||
{
|
{
|
||||||
public static Box2D Unit => new(Vert.Zero, Float2.One);
|
public static Box2D Unit => new(Vert.Zero, Float2.One);
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
public record class Box3D : IAbsolute<Box3D>, IAverage<Box3D>, ICeiling<Box3D>, IClamp<Box3D>,
|
public record class Box3D : IAbsolute<Box3D>, IAverage<Box3D>, ICeiling<Box3D>, IClamp<Box3D>,
|
||||||
IContains<Vert>, IEquatable<Box3D>, IFloor<Box3D>, ILerp<Box3D, float>, IMedian<Box3D>,
|
IContains<Vert>, IEquatable<Box3D>, IFloor<Box3D>, ILerp<Box3D, float>, IMedian<Box3D>,
|
||||||
IRound<Box3D>, IShape3D<float>, ISplittable<Box3D, (Vert[] centers, Float3[] sizes)>
|
IRound<Box3D>, IShape3d<float>, ISplittable<Box3D, (Vert[] centers, Float3[] sizes)>
|
||||||
{
|
{
|
||||||
public static Box3D Unit => new(Vert.Zero, Float3.One);
|
public static Box3D Unit => new(Vert.Zero, Float3.One);
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ namespace Nerd_STF.Mathematics.Geometry;
|
|||||||
|
|
||||||
public record class Line : IAbsolute<Line>, IAverage<Line>, ICeiling<Line>, IClamp<Line>, IClosestTo<Vert>,
|
public record class Line : IAbsolute<Line>, IAverage<Line>, ICeiling<Line>, IClamp<Line>, IClosestTo<Vert>,
|
||||||
IComparable<Line>, IContains<Vert>, IEquatable<Line>, IFloor<Line>, IFromTuple<Line, (Vert start, Vert end)>,
|
IComparable<Line>, IContains<Vert>, IEquatable<Line>, IFloor<Line>, IFromTuple<Line, (Vert start, Vert end)>,
|
||||||
IGroup<Vert>, IIndexAll<Vert>, IIndexRangeAll<Vert>, ILerp<Line, float>, IMedian<Line>, IPresets3D<Line>,
|
IGroup<Vert>, IIndexAll<Vert>, IIndexRangeAll<Vert>, ILerp<Line, float>, IMedian<Line>, IPresets3d<Line>,
|
||||||
IRound<Line>, ISplittable<Line, (Vert[] starts, Vert[] ends)>, ISubdivide<Line[]>
|
IRound<Line>, ISplittable<Line, (Vert[] starts, Vert[] ends)>, ISubdivide<Line[]>
|
||||||
{
|
{
|
||||||
public static Line Back => new(Vert.Zero, Vert.Back);
|
public static Line Back => new(Vert.Zero, Vert.Back);
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
public record class Quadrilateral : IAbsolute<Quadrilateral>, IAverage<Quadrilateral>, ICeiling<Quadrilateral>,
|
public record class Quadrilateral : IAbsolute<Quadrilateral>, IAverage<Quadrilateral>, ICeiling<Quadrilateral>,
|
||||||
IClamp<Quadrilateral>, IEquatable<Quadrilateral>, IFloor<Quadrilateral>,
|
IClamp<Quadrilateral>, IEquatable<Quadrilateral>, IFloor<Quadrilateral>,
|
||||||
IFromTuple<Quadrilateral, (Vert a, Vert b, Vert c, Vert d)>, IGroup<Vert>, IIndexAll<Vert>, IIndexRangeAll<Vert>,
|
IFromTuple<Quadrilateral, (Vert a, Vert b, Vert c, Vert d)>, IGroup<Vert>, IIndexAll<Vert>, IIndexRangeAll<Vert>,
|
||||||
ILerp<Quadrilateral, float>, IRound<Quadrilateral>, IShape2D<float>, ITriangulate
|
ILerp<Quadrilateral, float>, IRound<Quadrilateral>, IShape2d<float>, ITriangulate
|
||||||
{
|
{
|
||||||
public Vert A
|
public Vert A
|
||||||
{
|
{
|
||||||
|
|||||||
@ -4,7 +4,7 @@ namespace Nerd_STF.Mathematics.Geometry;
|
|||||||
|
|
||||||
public record class Triangle : IAbsolute<Triangle>, IAverage<Triangle>, ICeiling<Triangle>, IClamp<Triangle>,
|
public record class Triangle : IAbsolute<Triangle>, IAverage<Triangle>, ICeiling<Triangle>, IClamp<Triangle>,
|
||||||
IEquatable<Triangle>, IFloor<Triangle>, IFromTuple<Triangle, (Vert a, Vert b, Vert c)>, IGroup<Vert>,
|
IEquatable<Triangle>, IFloor<Triangle>, IFromTuple<Triangle, (Vert a, Vert b, Vert c)>, IGroup<Vert>,
|
||||||
IIndexAll<Vert>, IIndexRangeAll<Vert>, ILerp<Triangle, float>, IRound<Triangle>, IShape2D<float>
|
IIndexAll<Vert>, IIndexRangeAll<Vert>, ILerp<Triangle, float>, IRound<Triangle>, IShape2d<float>
|
||||||
{
|
{
|
||||||
public Vert A
|
public Vert A
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
public record struct Int2 : IAbsolute<Int2>, IAverage<Int2>, IClamp<Int2>, IClampMagnitude<Int2, int>,
|
public record struct Int2 : IAbsolute<Int2>, IAverage<Int2>, IClamp<Int2>, IClampMagnitude<Int2, int>,
|
||||||
IComparable<Int2>, ICross<Int2, Int3>, IDivide<Int2>, IDot<Int2, int>, IEquatable<Int2>,
|
IComparable<Int2>, ICross<Int2, Int3>, IDivide<Int2>, IDot<Int2, int>, IEquatable<Int2>,
|
||||||
IFromTuple<Int2, (int x, int y)>, IGroup<int>, IIndexAll<int>, IIndexRangeAll<int>, ILerp<Int2, float>,
|
IFromTuple<Int2, (int x, int y)>, IGroup<int>, IIndexAll<int>, IIndexRangeAll<int>, ILerp<Int2, float>,
|
||||||
IMathOperators<Int2>, IMax<Int2>, IMedian<Int2>, IMin<Int2>, IPresets2D<Int2>, IProduct<Int2>,
|
IMathOperators<Int2>, IMax<Int2>, IMedian<Int2>, IMin<Int2>, IPresets2d<Int2>, IProduct<Int2>,
|
||||||
ISplittable<Int2, (int[] Xs, int[] Ys)>, ISubtract<Int2>, ISum<Int2>
|
ISplittable<Int2, (int[] Xs, int[] Ys)>, ISubtract<Int2>, ISum<Int2>
|
||||||
{
|
{
|
||||||
public static Int2 Down => new(0, -1);
|
public static Int2 Down => new(0, -1);
|
||||||
@ -154,8 +154,6 @@ public record struct Int2 : IAbsolute<Int2>, IAverage<Int2>, IClamp<Int2>, IClam
|
|||||||
return (Xs, Ys);
|
return (Xs, Ys);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("This method is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public int CompareTo(Int2 other) => Magnitude.CompareTo(other.Magnitude);
|
public int CompareTo(Int2 other) => Magnitude.CompareTo(other.Magnitude);
|
||||||
public bool Equals(Int2 other) => x == other.x && y == other.y;
|
public bool Equals(Int2 other) => x == other.x && y == other.y;
|
||||||
public override int GetHashCode() => base.GetHashCode();
|
public override int GetHashCode() => base.GetHashCode();
|
||||||
@ -198,18 +196,6 @@ public record struct Int2 : IAbsolute<Int2>, IAverage<Int2>, IClamp<Int2>, IClam
|
|||||||
public static Int2 operator &(Int2 a, Int2 b) => new(a.x & b.x, a.y & b.y);
|
public static Int2 operator &(Int2 a, Int2 b) => new(a.x & b.x, a.y & b.y);
|
||||||
public static Int2 operator |(Int2 a, Int2 b) => new(a.x | b.x, a.y | b.y);
|
public static Int2 operator |(Int2 a, Int2 b) => new(a.x | b.x, a.y | b.y);
|
||||||
public static Int2 operator ^(Int2 a, Int2 b) => new(a.x ^ b.x, a.y ^ b.y);
|
public static Int2 operator ^(Int2 a, Int2 b) => new(a.x ^ b.x, a.y ^ b.y);
|
||||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator >(Int2 a, Int2 b) => a.CompareTo(b) > 0;
|
|
||||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator <(Int2 a, Int2 b) => a.CompareTo(b) < 0;
|
|
||||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
|
||||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator >=(Int2 a, Int2 b) => a == b || a > b;
|
|
||||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
|
||||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator <=(Int2 a, Int2 b) => a == b || a < b;
|
|
||||||
|
|
||||||
public static explicit operator Int2(Complex val) => new((int)val.u, (int)val.i);
|
public static explicit operator Int2(Complex val) => new((int)val.u, (int)val.i);
|
||||||
public static explicit operator Int2(Quaternion val) => new((int)val.u, (int)val.i);
|
public static explicit operator Int2(Quaternion val) => new((int)val.u, (int)val.i);
|
||||||
|
|||||||
@ -5,7 +5,7 @@ namespace Nerd_STF.Mathematics;
|
|||||||
public record struct Int3 : IAbsolute<Int3>, IAverage<Int3>, IClamp<Int3>, IClampMagnitude<Int3, int>,
|
public record struct Int3 : IAbsolute<Int3>, IAverage<Int3>, IClamp<Int3>, IClampMagnitude<Int3, int>,
|
||||||
IComparable<Int3>, ICross<Int3>, IDivide<Int3>, IDot<Int3, int>, IEquatable<Int3>,
|
IComparable<Int3>, ICross<Int3>, IDivide<Int3>, IDot<Int3, int>, IEquatable<Int3>,
|
||||||
IFromTuple<Int3, (int x, int y, int z)>, IGroup<int>, IIndexAll<int>, IIndexRangeAll<int>, ILerp<Int3, float>,
|
IFromTuple<Int3, (int x, int y, int z)>, IGroup<int>, IIndexAll<int>, IIndexRangeAll<int>, ILerp<Int3, float>,
|
||||||
IMathOperators<Int3>, IMax<Int3>, IMedian<Int3>, IMin<Int3>, IPresets3D<Int3>, IProduct<Int3>,
|
IMathOperators<Int3>, IMax<Int3>, IMedian<Int3>, IMin<Int3>, IPresets3d<Int3>, IProduct<Int3>,
|
||||||
ISplittable<Int3, (int[] Xs, int[] Ys, int[] Zs)>, ISubtract<Int3>, ISum<Int3>
|
ISplittable<Int3, (int[] Xs, int[] Ys, int[] Zs)>, ISubtract<Int3>, ISum<Int3>
|
||||||
{
|
{
|
||||||
public static Int3 Back => new(0, 0, -1);
|
public static Int3 Back => new(0, 0, -1);
|
||||||
@ -177,8 +177,6 @@ public record struct Int3 : IAbsolute<Int3>, IAverage<Int3>, IClamp<Int3>, IClam
|
|||||||
return (Xs, Ys, Zs);
|
return (Xs, Ys, Zs);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("This method is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public int CompareTo(Int3 other) => Magnitude.CompareTo(other.Magnitude);
|
public int CompareTo(Int3 other) => Magnitude.CompareTo(other.Magnitude);
|
||||||
public bool Equals(Int3 other) => x == other.x && y == other.y && z == other.z;
|
public bool Equals(Int3 other) => x == other.x && y == other.y && z == other.z;
|
||||||
public override int GetHashCode() => base.GetHashCode();
|
public override int GetHashCode() => base.GetHashCode();
|
||||||
@ -224,18 +222,6 @@ public record struct Int3 : IAbsolute<Int3>, IAverage<Int3>, IClamp<Int3>, IClam
|
|||||||
public static Int3 operator &(Int3 a, Int3 b) => new(a.x & b.x, a.y & b.y, a.z & b.z);
|
public static Int3 operator &(Int3 a, Int3 b) => new(a.x & b.x, a.y & b.y, a.z & b.z);
|
||||||
public static Int3 operator |(Int3 a, Int3 b) => new(a.x | b.x, a.y | b.y, a.z | b.z);
|
public static Int3 operator |(Int3 a, Int3 b) => new(a.x | b.x, a.y | b.y, a.z | b.z);
|
||||||
public static Int3 operator ^(Int3 a, Int3 b) => new(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z);
|
public static Int3 operator ^(Int3 a, Int3 b) => new(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z);
|
||||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator >(Int3 a, Int3 b) => a.CompareTo(b) > 0;
|
|
||||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator <(Int3 a, Int3 b) => a.CompareTo(b) < 0;
|
|
||||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
|
||||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator >=(Int3 a, Int3 b) => a == b || a > b;
|
|
||||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
|
||||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator <=(Int3 a, Int3 b) => a == b || a < b;
|
|
||||||
|
|
||||||
public static explicit operator Int3(Complex val) => new((int)val.u, (int)val.i, 0);
|
public static explicit operator Int3(Complex val) => new((int)val.u, (int)val.i, 0);
|
||||||
public static explicit operator Int3(Quaternion val) => new((int)val.u, (int)val.i, (int)val.j);
|
public static explicit operator Int3(Quaternion val) => new((int)val.u, (int)val.i, (int)val.j);
|
||||||
|
|||||||
@ -3,17 +3,11 @@
|
|||||||
public record struct Int4 : IAbsolute<Int4>, IAverage<Int4>, IClamp<Int4>, IClampMagnitude<Int4, int>,
|
public record struct Int4 : IAbsolute<Int4>, IAverage<Int4>, IClamp<Int4>, IClampMagnitude<Int4, int>,
|
||||||
IComparable<Int4>, IDivide<Int4>, IDot<Int4, int>, IEquatable<Int4>,
|
IComparable<Int4>, IDivide<Int4>, IDot<Int4, int>, IEquatable<Int4>,
|
||||||
IFromTuple<Int4, (int x, int y, int z, int w)>, IGroup<int>, IIndexAll<int>, IIndexRangeAll<int>,
|
IFromTuple<Int4, (int x, int y, int z, int w)>, IGroup<int>, IIndexAll<int>, IIndexRangeAll<int>,
|
||||||
ILerp<Int4, float>, IMathOperators<Int4>, IMax<Int4>, IMedian<Int4>, IMin<Int4>, IPresets4D<Int4>,
|
ILerp<Int4, float>, IMathOperators<Int4>, IMax<Int4>, IMedian<Int4>, IMin<Int4>, IPresets4d<Int4>,
|
||||||
IProduct<Int4>, ISplittable<Int4, (int[] Xs, int[] Ys, int[] Zs, int[] Ws)>, ISubtract<Int4>, ISum<Int4>
|
IProduct<Int4>, ISplittable<Int4, (int[] Xs, int[] Ys, int[] Zs, int[] Ws)>, ISubtract<Int4>, ISum<Int4>
|
||||||
{
|
{
|
||||||
public static Int4 Back => new(0, 0, -1, 0);
|
public static Int4 Back => new(0, 0, -1, 0);
|
||||||
[Obsolete("Field has been replaced by " + nameof(HighW) + ", because it has a better name. " +
|
|
||||||
"This field will be removed in v2.4.0.", false)]
|
|
||||||
public static Int4 Deep => new(0, 0, 0, -1);
|
|
||||||
public static Int4 Down => new(0, -1, 0, 0);
|
public static Int4 Down => new(0, -1, 0, 0);
|
||||||
[Obsolete("Field has been replaced by " + nameof(HighW) + ", because it has a better name. " +
|
|
||||||
"This field will be removed in v2.4.0.", false)]
|
|
||||||
public static Int4 Far => new(0, 0, 0, 1);
|
|
||||||
public static Int4 Forward => new(0, 0, 1, 0);
|
public static Int4 Forward => new(0, 0, 1, 0);
|
||||||
public static Int4 HighW => new(0, 0, 0, 1);
|
public static Int4 HighW => new(0, 0, 0, 1);
|
||||||
public static Int4 Left => new(-1, 0, 0, 0);
|
public static Int4 Left => new(-1, 0, 0, 0);
|
||||||
@ -196,8 +190,6 @@ public record struct Int4 : IAbsolute<Int4>, IAverage<Int4>, IClamp<Int4>, IClam
|
|||||||
return (Xs, Ys, Zs, Ws);
|
return (Xs, Ys, Zs, Ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("This method is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public int CompareTo(Int4 other) => Magnitude.CompareTo(other.Magnitude);
|
public int CompareTo(Int4 other) => Magnitude.CompareTo(other.Magnitude);
|
||||||
public bool Equals(Int4 other) => x == other.x && y == other.y && z == other.z && w == other.w;
|
public bool Equals(Int4 other) => x == other.x && y == other.y && z == other.z && w == other.w;
|
||||||
public override int GetHashCode() => base.GetHashCode();
|
public override int GetHashCode() => base.GetHashCode();
|
||||||
@ -244,18 +236,6 @@ public record struct Int4 : IAbsolute<Int4>, IAverage<Int4>, IClamp<Int4>, IClam
|
|||||||
public static Int4 operator &(Int4 a, Int4 b) => new(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w);
|
public static Int4 operator &(Int4 a, Int4 b) => new(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w);
|
||||||
public static Int4 operator |(Int4 a, Int4 b) => new(a.x | b.x, a.y | b.y, a.z | b.z, a.w | b.w);
|
public static Int4 operator |(Int4 a, Int4 b) => new(a.x | b.x, a.y | b.y, a.z | b.z, a.w | b.w);
|
||||||
public static Int4 operator ^(Int4 a, Int4 b) => new(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w);
|
public static Int4 operator ^(Int4 a, Int4 b) => new(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w);
|
||||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator >(Int4 a, Int4 b) => a.CompareTo(b) > 0;
|
|
||||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator <(Int4 a, Int4 b) => a.CompareTo(b) < 0;
|
|
||||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
|
||||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator >=(Int4 a, Int4 b) => a == b || a > b;
|
|
||||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
|
||||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator <=(Int4 a, Int4 b) => a == b || a < b;
|
|
||||||
|
|
||||||
public static explicit operator Int4(Complex val) => new((int)val.u, (int)val.i, 0, 0);
|
public static explicit operator Int4(Complex val) => new((int)val.u, (int)val.i, 0, 0);
|
||||||
public static explicit operator Int4(Quaternion val) => new((int)val.u, (int)val.i, (int)val.j, (int)val.k);
|
public static explicit operator Int4(Quaternion val) => new((int)val.u, (int)val.i, (int)val.j, (int)val.k);
|
||||||
|
|||||||
@ -19,19 +19,28 @@ public static class Mathf
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Angle ArcCos(float value) => ArcSin(-value) + Angle.Quarter;
|
public static Angle ArcCos(float value) => ArcSin(-value) + Angle.Quarter;
|
||||||
|
|
||||||
public static Angle ArcCot(float value) => ArcCos(value / Sqrt(1 + value * value));
|
public static Angle ArcCot(float value) => ArcCos(value / Sqrt(1 + value * value));
|
||||||
|
|
||||||
public static Angle ArcCsc(float value) => ArcSin(1 / value);
|
public static Angle ArcCsc(float value) => ArcSin(1 / value);
|
||||||
|
|
||||||
public static Angle ArcSec(float value) => ArcCos(1 / value);
|
public static Angle ArcSec(float value) => ArcCos(1 / value);
|
||||||
|
public static Angle ArcSin(float value)
|
||||||
// Maybe one day I'll have a polynomial for this, but the RMSE for an order 10 polynomial is only 0.00876.
|
{
|
||||||
public static Angle ArcSin(float value) => new((float)Math.Asin(value), Angle.Type.Radians);
|
if (value > 1 || value < -1) throw new ArgumentOutOfRangeException(nameof(value));
|
||||||
|
return (SolveNewton(x => Sin(x) - value, 0), Angle.Type.Degrees);
|
||||||
|
}
|
||||||
public static Angle ArcTan(float value) => ArcSin(value / Sqrt(1 + value * value));
|
public static Angle ArcTan(float value) => ArcSin(value / Sqrt(1 + value * value));
|
||||||
public static Angle ArcTan2(float a, float b) => ArcTan(a / b);
|
public static Angle ArcTan2(float a, float b) => ArcTan(a / b);
|
||||||
|
|
||||||
|
// I would've much rather used CORDIC for these inverses,
|
||||||
|
// but I can't think of an intuitive way to do it, so I'll
|
||||||
|
// hold off for now.
|
||||||
|
public static float ArcCosh(float value) => Log(Constants.E, value + Sqrt(value * value - 1));
|
||||||
|
public static float ArcCoth(float value) => Log(Constants.E, (1 + value) / (value - 1)) / 2;
|
||||||
|
public static float ArcCsch(float value) => Log(Constants.E, (1 + Sqrt(1 + value * value)) / value);
|
||||||
|
public static float ArcSech(float value) => Log(Constants.E, (1 + Sqrt(1 - value * value)) / value);
|
||||||
|
public static float ArcSinh(float value) => Log(Constants.E, value + Sqrt(value * value + 1));
|
||||||
|
public static float ArcTanh(float value) => Log(Constants.E, (1 + value) / (1 - value)) / 2;
|
||||||
|
public static float ArcTanh2(float a, float b) => ArcTanh(a / b);
|
||||||
|
|
||||||
public static float Average(Equation equ, float min, float max, float step = Calculus.DefaultStep)
|
public static float Average(Equation equ, float min, float max, float step = Calculus.DefaultStep)
|
||||||
{
|
{
|
||||||
List<float> vals = new();
|
List<float> vals = new();
|
||||||
@ -44,6 +53,8 @@ public static class Mathf
|
|||||||
public static float Binomial(int n, int total, float successRate) =>
|
public static float Binomial(int n, int total, float successRate) =>
|
||||||
Combinations(total, n) * Power(successRate, n) * Power(1 - successRate, total - n);
|
Combinations(total, n) * Power(successRate, n) * Power(1 - successRate, total - n);
|
||||||
|
|
||||||
|
public static float Cbrt(float value) => SolveNewton(x => x * x * x - value, 1);
|
||||||
|
|
||||||
public static int Ceiling(float val)
|
public static int Ceiling(float val)
|
||||||
{
|
{
|
||||||
float mod = val % 1;
|
float mod = val % 1;
|
||||||
@ -67,12 +78,23 @@ public static class Mathf
|
|||||||
public static float Cos(Angle angle) => Cos(angle.Radians);
|
public static float Cos(Angle angle) => Cos(angle.Radians);
|
||||||
public static float Cos(float radians) => Sin(radians + Constants.HalfPi);
|
public static float Cos(float radians) => Sin(radians + Constants.HalfPi);
|
||||||
|
|
||||||
|
public static float Cosh(float value)
|
||||||
|
{
|
||||||
|
if (value == 0) return 1;
|
||||||
|
else if (value < 0) return Cosh(-value);
|
||||||
|
else return CordicHelper.CalculateHyperTrig(value, 16).cosh;
|
||||||
|
}
|
||||||
|
|
||||||
public static float Cot(Angle angle) => Cot(angle.Radians);
|
public static float Cot(Angle angle) => Cot(angle.Radians);
|
||||||
public static float Cot(float radians) => Cos(radians) / Sin(radians);
|
public static float Cot(float radians) => Cos(radians) / Sin(radians);
|
||||||
|
|
||||||
|
public static float Coth(float value) => 1 / Tanh(value);
|
||||||
|
|
||||||
public static float Csc(Angle angle) => Csc(angle.Radians);
|
public static float Csc(Angle angle) => Csc(angle.Radians);
|
||||||
public static float Csc(float radians) => 1 / Sin(radians);
|
public static float Csc(float radians) => 1 / Sin(radians);
|
||||||
|
|
||||||
|
public static float Csch(float value) => 1 / Sinh(value);
|
||||||
|
|
||||||
public static float Divide(float val, params float[] dividends) => val / Product(dividends);
|
public static float Divide(float val, params float[] dividends) => val / Product(dividends);
|
||||||
public static int Divide(int val, params int[] dividends) => val / Product(dividends);
|
public static int Divide(int val, params int[] dividends) => val / Product(dividends);
|
||||||
|
|
||||||
@ -135,6 +157,14 @@ public static class Mathf
|
|||||||
|
|
||||||
public static float InverseSqrt(float val) => 1 / Sqrt(val);
|
public static float InverseSqrt(float val) => 1 / Sqrt(val);
|
||||||
|
|
||||||
|
public static bool IsPrime(int num, PrimeCheckMethod method = PrimeCheckMethod.Classic) =>
|
||||||
|
method switch
|
||||||
|
{
|
||||||
|
PrimeCheckMethod.Classic => MathfHelper.IsPrimeClassic(num),
|
||||||
|
PrimeCheckMethod.MillerRabin => MathfHelper.IsPrimeMillerRabin(num),
|
||||||
|
_ => throw new ArgumentException("Unknown prime check method.", nameof(method))
|
||||||
|
};
|
||||||
|
|
||||||
public static int LeastCommonMultiple(params int[] vals) => Product(vals) / GreatestCommonFactor(vals);
|
public static int LeastCommonMultiple(params int[] vals) => Product(vals) / GreatestCommonFactor(vals);
|
||||||
|
|
||||||
public static float Lerp(float a, float b, float t, bool clamp = true)
|
public static float Lerp(float a, float b, float t, bool clamp = true)
|
||||||
@ -144,6 +174,19 @@ public static class Mathf
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
public static int Lerp(int a, int b, float t, bool clamp = true) => (int)Lerp((float)a, b, t, clamp);
|
public static int Lerp(int a, int b, float t, bool clamp = true) => (int)Lerp((float)a, b, t, clamp);
|
||||||
|
public static Equation Lerp(float a, float b, Equation t, bool clamp = true) =>
|
||||||
|
x => Lerp(a, b, t(x), clamp);
|
||||||
|
public static Equation Lerp(Equation a, Equation b, float t, bool clamp = true) =>
|
||||||
|
x => Lerp(a(x), b(x), t, clamp);
|
||||||
|
public static Equation Lerp(Equation a, Equation b, Equation t, bool clamp = true) =>
|
||||||
|
x => Lerp(a(x), b(x), t(x), clamp);
|
||||||
|
|
||||||
|
public static float Log(float @base, float val)
|
||||||
|
{
|
||||||
|
if (val <= 0) throw new ArgumentOutOfRangeException(nameof(val));
|
||||||
|
else if (val < 1) return -Log(@base, 1 / val);
|
||||||
|
else return CordicHelper.LogAnyBase(@base, val, 16, 16);
|
||||||
|
}
|
||||||
|
|
||||||
public static Equation MakeEquation(Dictionary<float, float> vals) => delegate (float x)
|
public static Equation MakeEquation(Dictionary<float, float> vals) => delegate (float x)
|
||||||
{
|
{
|
||||||
@ -280,6 +323,20 @@ public static class Mathf
|
|||||||
// nPr (n = total, r = size)
|
// nPr (n = total, r = size)
|
||||||
public static int Permutations(int total, int size) => Factorial(total) / Factorial(total - size);
|
public static int Permutations(int total, int size) => Factorial(total) / Factorial(total - size);
|
||||||
|
|
||||||
|
public static int[] PrimeFactors(int num)
|
||||||
|
{
|
||||||
|
List<int> factors = new();
|
||||||
|
for (int i = 2; i <= num; i++)
|
||||||
|
{
|
||||||
|
while (num % i == 0)
|
||||||
|
{
|
||||||
|
factors.Add(i);
|
||||||
|
num /= i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return factors.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
public static float Product(params float[] vals)
|
public static float Product(params float[] vals)
|
||||||
{
|
{
|
||||||
if (vals.Length < 1) return 0;
|
if (vals.Length < 1) return 0;
|
||||||
@ -301,7 +358,12 @@ public static class Mathf
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float Power(float num, float pow) => (float)Math.Pow(num, pow);
|
public static float Power(float num, float pow)
|
||||||
|
{
|
||||||
|
if (pow == 0) return 1;
|
||||||
|
else if (pow < 0) return 1 / Power(num, -pow);
|
||||||
|
else return CordicHelper.ExpAnyBase(num, pow, 16, 16);
|
||||||
|
}
|
||||||
public static float Power(float num, int pow)
|
public static float Power(float num, int pow)
|
||||||
{
|
{
|
||||||
if (pow <= 0) return 0;
|
if (pow <= 0) return 0;
|
||||||
@ -329,6 +391,14 @@ public static class Mathf
|
|||||||
for (int i = 0; i < pow; i++) val = val * num % mod;
|
for (int i = 0; i < pow; i++) val = val * num % mod;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
public static long PowerMod(long num, long pow, long mod)
|
||||||
|
{
|
||||||
|
if (pow == 1) return num;
|
||||||
|
if (pow < 1) return 0;
|
||||||
|
long val = 1;
|
||||||
|
for (long i = 0; i < pow; i++) val = val * num % mod;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
public static float Root(float value, float index) => (float)Math.Exp(Math.Log(value) / index);
|
public static float Root(float value, float index) => (float)Math.Exp(Math.Log(value) / index);
|
||||||
|
|
||||||
@ -339,6 +409,18 @@ public static class Mathf
|
|||||||
public static float Sec(Angle angle) => Sec(angle.Radians);
|
public static float Sec(Angle angle) => Sec(angle.Radians);
|
||||||
public static float Sec(float radians) => 1 / Cos(radians);
|
public static float Sec(float radians) => 1 / Cos(radians);
|
||||||
|
|
||||||
|
public static float Sech(float value) => 1 / Cosh(value);
|
||||||
|
|
||||||
|
public static T[] SharedItems<T>(params T[][] arrays) where T : IEquatable<T>
|
||||||
|
{
|
||||||
|
if (arrays.Length < 1) return Array.Empty<T>();
|
||||||
|
|
||||||
|
IEnumerable<T> results = arrays[0];
|
||||||
|
foreach (T[] array in arrays) results = results.Where(x => array.Any(y => y.Equals(x)));
|
||||||
|
|
||||||
|
return UniqueItems(results.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
public static float Sin(Angle angle) => Sin(angle.Radians);
|
public static float Sin(Angle angle) => Sin(angle.Radians);
|
||||||
public static float Sin(float radians)
|
public static float Sin(float radians)
|
||||||
{
|
{
|
||||||
@ -361,7 +443,77 @@ public static class Mathf
|
|||||||
+ (j * x * x * x * x * x * x * x * x * x);
|
+ (j * x * x * x * x * x * x * x * x * x);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float Sqrt(float value) => Root(value, 2);
|
public static float Sinh(float value)
|
||||||
|
{
|
||||||
|
if (value == 0) return 0;
|
||||||
|
else if (value < 0) return -Sinh(-value);
|
||||||
|
else return CordicHelper.CalculateHyperTrig(value, 16).sinh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float SolveBisection(Equation equ, float initialA, float initialB, float tolerance = 1e-5f,
|
||||||
|
int maxIterations = 1000)
|
||||||
|
{
|
||||||
|
if (equ(initialA) == 0) return initialA;
|
||||||
|
else if (equ(initialB) == 0) return initialB;
|
||||||
|
|
||||||
|
float guessA = initialA, guessB = initialB, guessMid;
|
||||||
|
|
||||||
|
if (Math.Sign(equ(guessA)) == Math.Sign(equ(guessB)))
|
||||||
|
{
|
||||||
|
// Guess doesn't contain a zero (or isn't continuous). Return NaN.
|
||||||
|
return float.NaN;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iterations = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
guessMid = (guessA + guessB) / 2;
|
||||||
|
float valMid = equ(guessMid);
|
||||||
|
|
||||||
|
if (valMid == 0) return guessMid;
|
||||||
|
|
||||||
|
if (Math.Sign(equ(guessA)) != Math.Sign(valMid)) guessB = guessMid;
|
||||||
|
else guessA = guessMid;
|
||||||
|
|
||||||
|
iterations++;
|
||||||
|
if (iterations > maxIterations)
|
||||||
|
{
|
||||||
|
// Result isn't good enough. Return NaN.
|
||||||
|
return float.NaN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while ((guessB - guessA) > tolerance);
|
||||||
|
|
||||||
|
return guessMid;
|
||||||
|
}
|
||||||
|
public static float SolveEquation(Equation equ, float initial, float tolerance = 1e-5f,
|
||||||
|
float step = Calculus.DefaultStep, int maxIterations = 1000) =>
|
||||||
|
SolveNewton(equ, initial, tolerance, step, maxIterations);
|
||||||
|
public static float SolveNewton(Equation equ, float initial, float tolerance = 1e-5f,
|
||||||
|
float step = Calculus.DefaultStep, int maxIterations = 1000)
|
||||||
|
{
|
||||||
|
if (equ(initial) == 0) return initial;
|
||||||
|
|
||||||
|
float lastResult = initial, result;
|
||||||
|
int iterations = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
result = lastResult - (equ(lastResult) / Calculus.GetDerivativeAtPoint(equ, lastResult, step));
|
||||||
|
lastResult = result;
|
||||||
|
|
||||||
|
iterations++;
|
||||||
|
if (iterations > maxIterations)
|
||||||
|
{
|
||||||
|
// Result isn't good enough. Return NaN.
|
||||||
|
return float.NaN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (Absolute(equ(result)) > tolerance);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float Sqrt(float value) => SolveNewton(x => x * x - value, 1);
|
||||||
|
|
||||||
public static float Subtract(float num, params float[] vals) => num - Sum(vals);
|
public static float Subtract(float num, params float[] vals) => num - Sum(vals);
|
||||||
public static int Subtract(int num, params int[] vals) => num - Sum(vals);
|
public static int Subtract(int num, params int[] vals) => num - Sum(vals);
|
||||||
@ -391,6 +543,19 @@ public static class Mathf
|
|||||||
public static float Tan(Angle angle) => Tan(angle.Radians);
|
public static float Tan(Angle angle) => Tan(angle.Radians);
|
||||||
public static float Tan(float radians) => Sin(radians) / Cos(radians);
|
public static float Tan(float radians) => Sin(radians) / Cos(radians);
|
||||||
|
|
||||||
|
public static float Tanh(float value)
|
||||||
|
{
|
||||||
|
float cosh, sinh;
|
||||||
|
if (value < 0)
|
||||||
|
{
|
||||||
|
(cosh, sinh) = CordicHelper.CalculateHyperTrig(-value, 16);
|
||||||
|
sinh = -sinh;
|
||||||
|
}
|
||||||
|
else (cosh, sinh) = CordicHelper.CalculateHyperTrig(value, 16);
|
||||||
|
|
||||||
|
return cosh / sinh;
|
||||||
|
}
|
||||||
|
|
||||||
public static T[] UniqueItems<T>(params T[] vals) where T : IEquatable<T>
|
public static T[] UniqueItems<T>(params T[] vals) where T : IEquatable<T>
|
||||||
{
|
{
|
||||||
List<T> unique = new();
|
List<T> unique = new();
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
public record struct Complex(float u, float i) : IAbsolute<Complex>, IAverage<Complex>, ICeiling<Complex>,
|
public record struct Complex(float u, float i) : IAbsolute<Complex>, IAverage<Complex>, ICeiling<Complex>,
|
||||||
IClampMagnitude<Complex, float>, IComparable<Complex>, IDivide<Complex>, IDot<Complex, float>,
|
IClampMagnitude<Complex, float>, IComparable<Complex>, IDivide<Complex>, IDot<Complex, float>,
|
||||||
IEquatable<Complex>, IFloor<Complex>, IGroup<float>, IIndexAll<float>, IIndexRangeAll<float>,
|
IEquatable<Complex>, IFloor<Complex>, IGroup<float>, IIndexAll<float>, IIndexRangeAll<float>,
|
||||||
ILerp<Complex, float>, IMax<Complex>, IMedian<Complex>, IMin<Complex>, IPresets2D<Complex>, IProduct<Complex>,
|
ILerp<Complex, float>, IMax<Complex>, IMedian<Complex>, IMin<Complex>, IPresets2d<Complex>, IProduct<Complex>,
|
||||||
IRound<Complex>, ISplittable<Complex, (float[] Us, float[] Is)>, ISum<Complex>
|
IRound<Complex>, ISplittable<Complex, (float[] Us, float[] Is)>, ISum<Complex>
|
||||||
{
|
{
|
||||||
public static Complex Down => new(0, -1);
|
public static Complex Down => new(0, -1);
|
||||||
@ -190,18 +190,6 @@ public record struct Complex(float u, float i) : IAbsolute<Complex>, IAverage<Co
|
|||||||
public static Complex operator /(Complex a, float b) => new(a.u / b, a.i / b);
|
public static Complex operator /(Complex a, float b) => new(a.u / b, a.i / b);
|
||||||
public static Complex operator /(Complex a, Matrix b) => (Complex)((Matrix)a / b);
|
public static Complex operator /(Complex a, Matrix b) => (Complex)((Matrix)a / b);
|
||||||
public static Complex operator ~(Complex v) => v.Conjugate;
|
public static Complex operator ~(Complex v) => v.Conjugate;
|
||||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator >(Complex a, Complex b) => a.CompareTo(b) > 0;
|
|
||||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator <(Complex a, Complex b) => a.CompareTo(b) < 0;
|
|
||||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
|
||||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator >=(Complex a, Complex b) => a == b || a > b;
|
|
||||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
|
||||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator <=(Complex a, Complex b) => a == b || a < b;
|
|
||||||
|
|
||||||
public static explicit operator Complex(Quaternion val) => new(val.u, val.i);
|
public static explicit operator Complex(Quaternion val) => new(val.u, val.i);
|
||||||
public static implicit operator Complex(Float2 val) => new(val.x, val.y);
|
public static implicit operator Complex(Float2 val) => new(val.x, val.y);
|
||||||
|
|||||||
@ -4,21 +4,15 @@ public record struct Quaternion(float u, float i, float j, float k) : IAbsolute<
|
|||||||
ICeiling<Quaternion>, IClamp<Quaternion>, IClampMagnitude<Quaternion, float>, IComparable<Quaternion>,
|
ICeiling<Quaternion>, IClamp<Quaternion>, IClampMagnitude<Quaternion, float>, IComparable<Quaternion>,
|
||||||
IDivide<Quaternion>, IDot<Quaternion, float>, IEquatable<Quaternion>, IFloor<Quaternion>, IGroup<float>,
|
IDivide<Quaternion>, IDot<Quaternion, float>, IEquatable<Quaternion>, IFloor<Quaternion>, IGroup<float>,
|
||||||
IIndexAll<float>, IIndexRangeAll<float>, ILerp<Quaternion, float>, IMax<Quaternion>, IMedian<Quaternion>,
|
IIndexAll<float>, IIndexRangeAll<float>, ILerp<Quaternion, float>, IMax<Quaternion>, IMedian<Quaternion>,
|
||||||
IMin<Quaternion>, IPresets4D<Quaternion>, IProduct<Quaternion>, IRound<Quaternion>,
|
IMin<Quaternion>, IPresets4d<Quaternion>, IProduct<Quaternion>, IRound<Quaternion>,
|
||||||
ISplittable<Quaternion, (float[] Us, float[] Is, float[] Js, float[] Ks)>, ISum<Quaternion>
|
ISplittable<Quaternion, (float[] Us, float[] Is, float[] Js, float[] Ks)>, ISum<Quaternion>
|
||||||
{
|
{
|
||||||
public static Quaternion Back => new(0, 0, -1, 0);
|
public static Quaternion Back => new(0, 0, -1, 0);
|
||||||
public static Quaternion Down => new(0, -1, 0, 0);
|
public static Quaternion Down => new(0, -1, 0, 0);
|
||||||
[Obsolete("Field has been replaced by " + nameof(HighW) + ", because it has a better name. " +
|
|
||||||
"This field will be removed in v2.4.0.", false)]
|
|
||||||
public static Quaternion Far => new(0, 0, 0, 1);
|
|
||||||
public static Quaternion Forward => new(0, 0, 1, 0);
|
public static Quaternion Forward => new(0, 0, 1, 0);
|
||||||
public static Quaternion HighW => new(0, 0, 0, 1);
|
public static Quaternion HighW => new(0, 0, 0, 1);
|
||||||
public static Quaternion Left => new(-1, 0, 0, 0);
|
public static Quaternion Left => new(-1, 0, 0, 0);
|
||||||
public static Quaternion LowW => new(0, 0, 0, -1);
|
public static Quaternion LowW => new(0, 0, 0, -1);
|
||||||
[Obsolete("Field has been replaced by " + nameof(LowW) + ", because it has a better name. " +
|
|
||||||
"This field will be removed in v2.4.0.", false)]
|
|
||||||
public static Quaternion Near => new(0, 0, 0, -1);
|
|
||||||
public static Quaternion Right => new(1, 0, 0, 0);
|
public static Quaternion Right => new(1, 0, 0, 0);
|
||||||
public static Quaternion Up => new(0, 1, 0, 0);
|
public static Quaternion Up => new(0, 1, 0, 0);
|
||||||
|
|
||||||
@ -323,18 +317,6 @@ public record struct Quaternion(float u, float i, float j, float k) : IAbsolute<
|
|||||||
public static Quaternion operator /(Quaternion a, Matrix b) => (Quaternion)((Matrix)a / b);
|
public static Quaternion operator /(Quaternion a, Matrix b) => (Quaternion)((Matrix)a / b);
|
||||||
public static Quaternion operator /(Quaternion a, Float3 b) => a / new Quaternion(b);
|
public static Quaternion operator /(Quaternion a, Float3 b) => a / new Quaternion(b);
|
||||||
public static Quaternion operator ~(Quaternion v) => v.Conjugate;
|
public static Quaternion operator ~(Quaternion v) => v.Conjugate;
|
||||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator >(Quaternion a, Quaternion b) => a.CompareTo(b) > 0;
|
|
||||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
|
||||||
nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator <(Quaternion a, Quaternion b) => a.CompareTo(b) < 0;
|
|
||||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
|
||||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator >=(Quaternion a, Quaternion b) => a == b || a > b;
|
|
||||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
|
||||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
|
||||||
public static bool operator <=(Quaternion a, Quaternion b) => a == b || a < b;
|
|
||||||
|
|
||||||
public static implicit operator Quaternion(Complex val) => new(val.u, val.i, 0, 0);
|
public static implicit operator Quaternion(Complex val) => new(val.u, val.i, 0, 0);
|
||||||
public static implicit operator Quaternion(Int2 val) => new(val);
|
public static implicit operator Quaternion(Int2 val) => new(val);
|
||||||
|
|||||||
7
Nerd_STF/Mathematics/PrimeCheckMethod.cs
Normal file
7
Nerd_STF/Mathematics/PrimeCheckMethod.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace Nerd_STF.Mathematics;
|
||||||
|
|
||||||
|
public enum PrimeCheckMethod
|
||||||
|
{
|
||||||
|
Classic,
|
||||||
|
MillerRabin
|
||||||
|
}
|
||||||
177
Nerd_STF/Mathematics/Rational.cs
Normal file
177
Nerd_STF/Mathematics/Rational.cs
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
namespace Nerd_STF.Mathematics;
|
||||||
|
|
||||||
|
public readonly record struct Rational : IAbsolute<Rational>, IAverage<Rational>, ICeiling<Rational, int>, IClamp<Rational>,
|
||||||
|
IComparable<Rational>, IComparable<float>, IDivide<Rational>, IEquatable<Rational>, IEquatable<float>,
|
||||||
|
IFloor<Rational, int>, IIndexGet<int>, IIndexRangeGet<int>, ILerp<Rational, float>, IMathOperators<Rational>,
|
||||||
|
IMax<Rational>, IMedian<Rational>, IMin<Rational>, IPresets1d<Rational>, IProduct<Rational>,
|
||||||
|
IRound<Rational, int>, ISplittable<Rational, (int[] nums, int[] dens)>, ISubtract<Rational>,
|
||||||
|
ISum<Rational>
|
||||||
|
{
|
||||||
|
public static Rational One => new(1, 1);
|
||||||
|
public static Rational Zero => new(0, 1);
|
||||||
|
|
||||||
|
public readonly int numerator;
|
||||||
|
public readonly int denominator;
|
||||||
|
|
||||||
|
public Rational Reciprocal => new(denominator, numerator);
|
||||||
|
public Rational Simplified
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
int[] denFactors = Mathf.PrimeFactors(denominator);
|
||||||
|
|
||||||
|
int newNum = numerator,
|
||||||
|
newDen = denominator;
|
||||||
|
|
||||||
|
foreach (int factor in denFactors)
|
||||||
|
{
|
||||||
|
if (newNum % factor != 0) continue;
|
||||||
|
|
||||||
|
newNum /= factor;
|
||||||
|
newDen /= factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new(newNum, newDen, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rational() : this(0, 1) { }
|
||||||
|
public Rational(int numerator, int denominator, bool simplified = true)
|
||||||
|
{
|
||||||
|
this.numerator = numerator * Math.Sign(denominator);
|
||||||
|
this.denominator = Mathf.Absolute(denominator);
|
||||||
|
if (simplified) this = Simplified;
|
||||||
|
}
|
||||||
|
public Rational(Fill<int> fill, bool simplified = true) : this(fill(0), fill(1), simplified) { }
|
||||||
|
|
||||||
|
public int this[int index]
|
||||||
|
{
|
||||||
|
get => index switch
|
||||||
|
{
|
||||||
|
0 => numerator,
|
||||||
|
1 => denominator,
|
||||||
|
_ => throw new IndexOutOfRangeException(nameof(index))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public int this[Index index]
|
||||||
|
{
|
||||||
|
get => this[index.IsFromEnd ? 2 - index.Value : index.Value];
|
||||||
|
}
|
||||||
|
public int[] this[Range range]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value;
|
||||||
|
int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value;
|
||||||
|
List<int> res = new();
|
||||||
|
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||||
|
return res.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rational FromFloat(float value, float tolerance = 1e-5f,
|
||||||
|
SimplificationMethod method = SimplificationMethod.FareySequence, int maxIterations = 100) =>
|
||||||
|
method switch
|
||||||
|
{
|
||||||
|
SimplificationMethod.AutoSimplify => RationalHelper.SimplifyAuto(value),
|
||||||
|
SimplificationMethod.FareySequence => RationalHelper.SimplifyFarey(value, tolerance, maxIterations),
|
||||||
|
_ => throw new ArgumentException("Unknown simplification method.", nameof(method))
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Rational Absolute(Rational value) =>
|
||||||
|
new(Mathf.Absolute(value.numerator), value.denominator);
|
||||||
|
public static Rational Average(params Rational[] vals) => Sum(vals) / (float)vals.Length;
|
||||||
|
public static int Ceiling(Rational r)
|
||||||
|
{
|
||||||
|
int mod = r.numerator % r.denominator;
|
||||||
|
|
||||||
|
if (mod == 0) return r.numerator / r.denominator;
|
||||||
|
return r.numerator + (r.denominator - mod);
|
||||||
|
}
|
||||||
|
public static Rational Clamp(Rational val, Rational min, Rational max)
|
||||||
|
=> FromFloat(Mathf.Clamp(val.GetValue(), min.GetValue(), max.GetValue()));
|
||||||
|
public static Rational Divide(Rational val, params Rational[] vals) =>
|
||||||
|
val / Product(vals);
|
||||||
|
public static int Floor(Rational val) => val.numerator / val.denominator;
|
||||||
|
public static Rational Lerp(Rational a, Rational b, float t, bool clamp = true) =>
|
||||||
|
FromFloat(Mathf.Lerp(a.GetValue(), b.GetValue(), t, clamp));
|
||||||
|
public static Rational Product(params Rational[] vals)
|
||||||
|
{
|
||||||
|
Rational res = One;
|
||||||
|
foreach (Rational r in vals) res *= r;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
public static int Round(Rational r) => (int)Mathf.Round(r.numerator, r.denominator) / r.denominator;
|
||||||
|
public static Rational Subtract(Rational val, params Rational[] vals) =>
|
||||||
|
val - Sum(vals);
|
||||||
|
public static Rational Sum(params Rational[] vals)
|
||||||
|
{
|
||||||
|
Rational sum = Zero;
|
||||||
|
foreach (Rational r in vals) sum += r;
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static (int[] nums, int[] dens) SplitArray(params Rational[] vals)
|
||||||
|
{
|
||||||
|
int[] nums = new int[vals.Length], dens = new int[vals.Length];
|
||||||
|
for (int i = 0; i < vals.Length; i++)
|
||||||
|
{
|
||||||
|
nums[i] = vals[i].numerator;
|
||||||
|
dens[i] = vals[i].denominator;
|
||||||
|
}
|
||||||
|
return (nums, dens);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetValue() => numerator / (float)denominator;
|
||||||
|
|
||||||
|
public int CompareTo(Rational other) => GetValue().CompareTo(other.GetValue());
|
||||||
|
public int CompareTo(float other) => GetValue().CompareTo(other);
|
||||||
|
public bool Equals(Rational other)
|
||||||
|
{
|
||||||
|
Rational thisSim = Simplified,
|
||||||
|
otherSim = other.Simplified;
|
||||||
|
return thisSim.numerator == otherSim.numerator &&
|
||||||
|
thisSim.denominator == otherSim.denominator;
|
||||||
|
}
|
||||||
|
public bool Equals(float other) => GetValue() == other;
|
||||||
|
public override int GetHashCode() => base.GetHashCode();
|
||||||
|
|
||||||
|
private bool PrintMembers(StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Append(numerator);
|
||||||
|
builder.Append(" / ");
|
||||||
|
builder.Append(denominator);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rational operator +(Rational a, Rational b)
|
||||||
|
{
|
||||||
|
int sharedDen = a.denominator * b.denominator,
|
||||||
|
newNumA = a.numerator * b.denominator,
|
||||||
|
newNumB = b.numerator * a.denominator;
|
||||||
|
return new Rational(newNumA + newNumB, sharedDen).Simplified;
|
||||||
|
}
|
||||||
|
public static Rational operator +(Rational a, float b) => a + FromFloat(b);
|
||||||
|
public static Rational operator +(float a, Rational b) => FromFloat(a) + b;
|
||||||
|
public static Rational operator -(Rational r) => new(-r.numerator, r.denominator);
|
||||||
|
public static Rational operator -(Rational a, Rational b)
|
||||||
|
{
|
||||||
|
int sharedDen = a.denominator * b.denominator,
|
||||||
|
newNumA = a.numerator * b.denominator,
|
||||||
|
newNumB = b.numerator * a.denominator;
|
||||||
|
return new Rational(newNumA - newNumB, sharedDen).Simplified;
|
||||||
|
}
|
||||||
|
public static Rational operator -(Rational a, float b) => a - FromFloat(b);
|
||||||
|
public static Rational operator -(float a, Rational b) => FromFloat(a) - b;
|
||||||
|
public static Rational operator *(Rational a, Rational b) =>
|
||||||
|
new Rational(a.numerator * b.numerator, a.denominator * b.denominator).Simplified;
|
||||||
|
public static Rational operator *(Rational a, float b) => a * FromFloat(b);
|
||||||
|
public static Rational operator *(float a, Rational b) => FromFloat(a) * b;
|
||||||
|
public static Rational operator /(Rational a, Rational b) => a * b.Reciprocal;
|
||||||
|
public static Rational operator /(Rational a, float b) => a * FromFloat(b).Reciprocal;
|
||||||
|
public static Rational operator /(float a, Rational b) => FromFloat(a) * b.Reciprocal;
|
||||||
|
|
||||||
|
public static implicit operator float(Rational r) => r.GetValue();
|
||||||
|
public static implicit operator Rational(float f) => FromFloat(f);
|
||||||
|
}
|
||||||
@ -2,10 +2,11 @@
|
|||||||
|
|
||||||
public static class Equations
|
public static class Equations
|
||||||
{
|
{
|
||||||
public static readonly Fill<int> SgnFill = i => i % 2 == 0 ? 1 : -1;
|
public static Equation CosWave => Mathf.Cos;
|
||||||
|
public static Equation SinWave => Mathf.Sin;
|
||||||
|
public static Equation SawWave => x => x % 1;
|
||||||
|
public static Equation SquareWave => x => x % 2 < 1 ? 1 : 0;
|
||||||
|
|
||||||
public static readonly Equation CosWave = x => Mathf.Cos(x);
|
public static Equation FlatLine => x => 0;
|
||||||
public static readonly Equation SinWave = x => Mathf.Sin(x);
|
public static Equation XLine => x => x;
|
||||||
public static readonly Equation SawWave = x => x % 1;
|
|
||||||
public static readonly Equation SquareWave = x => x % 2 < 1 ? 1 : 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
6
Nerd_STF/Mathematics/Samples/Fills.cs
Normal file
6
Nerd_STF/Mathematics/Samples/Fills.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace Nerd_STF.Mathematics.Samples;
|
||||||
|
|
||||||
|
public static class Fills
|
||||||
|
{
|
||||||
|
public static Fill<int> SignFill => i => i % 2 == 0 ? 1 : -1;
|
||||||
|
}
|
||||||
7
Nerd_STF/Mathematics/SimplificationMethod.cs
Normal file
7
Nerd_STF/Mathematics/SimplificationMethod.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace Nerd_STF.Mathematics;
|
||||||
|
|
||||||
|
public enum SimplificationMethod
|
||||||
|
{
|
||||||
|
AutoSimplify,
|
||||||
|
FareySequence
|
||||||
|
}
|
||||||
@ -1,4 +1,2 @@
|
|||||||
using System.Reflection;
|
// Includes assembly configuration that isn't automatically handled by the compiler.
|
||||||
|
|
||||||
// Includes assembly configuration that isn't automatically handled by the compiler.
|
|
||||||
// So far, there is none. There may be some in the future. We will see.
|
// So far, there is none. There may be some in the future. We will see.
|
||||||
|
|||||||
@ -3,6 +3,7 @@ global using Nerd_STF.Graphics;
|
|||||||
global using Nerd_STF.Graphics.Abstract;
|
global using Nerd_STF.Graphics.Abstract;
|
||||||
global using Nerd_STF.Exceptions;
|
global using Nerd_STF.Exceptions;
|
||||||
global using Nerd_STF.Extensions;
|
global using Nerd_STF.Extensions;
|
||||||
|
global using Nerd_STF.Helpers;
|
||||||
global using Nerd_STF.Mathematics;
|
global using Nerd_STF.Mathematics;
|
||||||
global using Nerd_STF.Mathematics.Abstract;
|
global using Nerd_STF.Mathematics.Abstract;
|
||||||
global using Nerd_STF.Mathematics.Algebra;
|
global using Nerd_STF.Mathematics.Algebra;
|
||||||
@ -16,6 +17,7 @@ global using System.Diagnostics.CodeAnalysis;
|
|||||||
global using System.IO;
|
global using System.IO;
|
||||||
global using System.Linq;
|
global using System.Linq;
|
||||||
global using System.Net.Http;
|
global using System.Net.Http;
|
||||||
|
global using System.Reflection;
|
||||||
global using System.Runtime.Serialization;
|
global using System.Runtime.Serialization;
|
||||||
global using System.Text;
|
global using System.Text;
|
||||||
global using System.Threading;
|
global using System.Threading;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
namespace Nerd_STF;
|
namespace Nerd_STF;
|
||||||
|
|
||||||
public delegate float Modifier2D(Int2 index, float value);
|
public delegate float Modifier2d(Int2 index, float value);
|
||||||
public delegate T Modifier2D<T>(Int2 index, T value);
|
public delegate T Modifier2d<T>(Int2 index, T value);
|
||||||
public delegate VT Modifier2D<IT, VT>(IT x, IT y, VT value);
|
public delegate VT Modifier2d<IT, VT>(IT x, IT y, VT value);
|
||||||
|
|||||||
113
Nerd_STF/NDArray.cs
Normal file
113
Nerd_STF/NDArray.cs
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
namespace Nerd_STF;
|
||||||
|
|
||||||
|
public class NDArray<T> : IEnumerable<T>, IEquatable<NDArray<T>>
|
||||||
|
{
|
||||||
|
public int Dimensions => dimensions;
|
||||||
|
public int[] Lengths => sizes;
|
||||||
|
public long FullLength
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
long prod = 1;
|
||||||
|
foreach (int size in sizes) prod *= size;
|
||||||
|
return prod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected readonly T[] arr;
|
||||||
|
protected readonly int dimensions;
|
||||||
|
protected readonly int[] sizes;
|
||||||
|
|
||||||
|
public NDArray()
|
||||||
|
{
|
||||||
|
arr = Array.Empty<T>();
|
||||||
|
dimensions = 0;
|
||||||
|
sizes = Array.Empty<int>();
|
||||||
|
}
|
||||||
|
public NDArray(int dimensions)
|
||||||
|
{
|
||||||
|
arr = Array.Empty<T>();
|
||||||
|
this.dimensions = dimensions;
|
||||||
|
sizes = new int[dimensions];
|
||||||
|
|
||||||
|
Array.Fill(sizes, 0);
|
||||||
|
}
|
||||||
|
public NDArray(int dimensions, int allLengths)
|
||||||
|
{
|
||||||
|
this.dimensions = dimensions;
|
||||||
|
sizes = new int[dimensions];
|
||||||
|
Array.Fill(sizes, allLengths);
|
||||||
|
|
||||||
|
arr = new T[Mathf.Product(sizes)];
|
||||||
|
}
|
||||||
|
public NDArray(int[] lengths)
|
||||||
|
{
|
||||||
|
arr = new T[Mathf.Product(lengths)];
|
||||||
|
dimensions = lengths.Length;
|
||||||
|
sizes = lengths;
|
||||||
|
}
|
||||||
|
public NDArray(int dimensions, int[] lengths)
|
||||||
|
{
|
||||||
|
if (dimensions != lengths.Length) throw new InvalidSizeException("Dimension count doesn't match length count.");
|
||||||
|
|
||||||
|
arr = new T[Mathf.Product(lengths)];
|
||||||
|
this.dimensions = lengths.Length;
|
||||||
|
sizes = lengths;
|
||||||
|
}
|
||||||
|
public NDArray(T[] items, int[] lengths)
|
||||||
|
{
|
||||||
|
arr = items;
|
||||||
|
dimensions = lengths.Length;
|
||||||
|
sizes = lengths;
|
||||||
|
|
||||||
|
if (arr.Length != Mathf.Product(lengths)) throw new InvalidSizeException("Too many or too few items were provided.");
|
||||||
|
}
|
||||||
|
public NDArray(T[] items, int dimensions, int[] lengths)
|
||||||
|
{
|
||||||
|
if (dimensions != lengths.Length) throw new InvalidSizeException("Dimension count doesn't match length count.");
|
||||||
|
|
||||||
|
arr = items;
|
||||||
|
this.dimensions = lengths.Length;
|
||||||
|
sizes = lengths;
|
||||||
|
|
||||||
|
if (arr.Length != Mathf.Product(lengths)) throw new InvalidSizeException("Too many or too few items were provided.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public T this[params int[] indexes]
|
||||||
|
{
|
||||||
|
get => arr[FlattenIndex(indexes)];
|
||||||
|
set => arr[FlattenIndex(indexes)] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int FlattenIndex(params int[] indexes)
|
||||||
|
{
|
||||||
|
if (indexes.Length != sizes.Length) throw new InvalidSizeException("Too many or too few indexes were provided.");
|
||||||
|
|
||||||
|
int ind = indexes[^1];
|
||||||
|
Console.WriteLine($"Start at {ind}");
|
||||||
|
for (int i = indexes.Length - 2; i >= 0; i--)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[{ind}] * {sizes[i]} + {indexes[i]}");
|
||||||
|
ind = ind * sizes[i] + indexes[i];
|
||||||
|
}
|
||||||
|
return ind;
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
public IEnumerator<T> GetEnumerator()
|
||||||
|
{
|
||||||
|
foreach (T item in arr) yield return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
if (obj is null) return false;
|
||||||
|
else if (obj is NDArray<T> arr) return Equals(arr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public bool Equals(NDArray<T>? obj) => obj is not null && arr.Equals(obj.arr);
|
||||||
|
public override int GetHashCode() => base.GetHashCode();
|
||||||
|
|
||||||
|
public static bool operator ==(NDArray<T> a, NDArray<T> b) => a.Equals(b);
|
||||||
|
public static bool operator !=(NDArray<T> a, NDArray<T> b) => !a.Equals(b);
|
||||||
|
}
|
||||||
@ -17,5 +17,5 @@ public static class Nerd_STF
|
|||||||
{ "nuget", "https://www.nuget.org/packages/Nerd_STF/" }
|
{ "nuget", "https://www.nuget.org/packages/Nerd_STF/" }
|
||||||
};
|
};
|
||||||
public const string MainDeveloper = "That_One_Nerd";
|
public const string MainDeveloper = "That_One_Nerd";
|
||||||
public const string Version = "2.3.2";
|
public const string Version = "2.4.0";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,28 +8,39 @@
|
|||||||
<AssemblyName>Nerd_STF</AssemblyName>
|
<AssemblyName>Nerd_STF</AssemblyName>
|
||||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||||
<Authors>That_One_Nerd</Authors>
|
<Authors>That_One_Nerd</Authors>
|
||||||
<Description>Nerd_STF is a general-purpose .NET library.</Description>
|
<Description>Nerd_STF is a general-purpose .NET library for .NET 7.0.</Description>
|
||||||
<Copyright>Copyright (c) 2022 That_One_Nerd</Copyright>
|
<Copyright>Copyright (c) 2023 That_One_Nerd</Copyright>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<RepositoryUrl>https://github.com/That-One-Nerd/Nerd_STF</RepositoryUrl>
|
<RepositoryUrl>https://github.com/That-One-Nerd/Nerd_STF</RepositoryUrl>
|
||||||
<AssemblyVersion>2.3.2</AssemblyVersion>
|
<AssemblyVersion>2.4.0</AssemblyVersion>
|
||||||
<PackageTags>c#;csharp;c sharp;math;mathematics;mathametics;maths;color;rgb;rgba;cmyk;cmyka;hsv;hsva;calculus;linear algebra;linalg;linearalgebra;matrix;matrix2x2;matrix 2x2;matrix3x3;matrix 3x3;matrix4x4;matrix 4x4;matrix multiplication;vector;vector2d;vector3d;vector2;vector3;float2;float3;float4;int2;int3;int4;angle;geometry;vert;line;polygon;triangle;quadrilateral;sphere;circle;number system;numbersystem;complex numbers;complex;2d numbers;2dnumbers;quaternions;4d numbers;4dnumbers</PackageTags>
|
<PackageTags>c#;csharp;c sharp;math;mathematics;mathametics;maths;color;rgb;rgba;cmyk;cmyka;hsv;hsva;calculus;linear algebra;linalg;linearalgebra;matrix;matrix2x2;matrix 2x2;matrix3x3;matrix 3x3;matrix4x4;matrix 4x4;matrix multiplication;vector;vector2d;vector3d;vector2;vector3;float2;float3;float4;int2;int3;int4;angle;geometry;vert;line;polygon;triangle;quadrilateral;sphere;circle;number system;numbersystem;complex numbers;complex;2d numbers;2dnumbers;quaternions;4d numbers;4dnumbers</PackageTags>
|
||||||
<Version>2.3.2</Version>
|
<Version>2.4.0</Version>
|
||||||
<Product>Nerd_STF</Product>
|
<Product>Nerd_STF</Product>
|
||||||
<PackageId>Nerd_STF</PackageId>
|
<PackageId>Nerd_STF</PackageId>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
<PackageIcon>Logo Square.png</PackageIcon>
|
<PackageIcon>Logo Square.png</PackageIcon>
|
||||||
<PackageReleaseNotes>A bunch of stuff has changed, hasn't it?
|
<PackageReleaseNotes>I've done a pretty good amount of stuff in this update, and I'm pretty proud of it. Good improvement.
|
||||||
|
|
||||||
This update was originally intended to be a support update. But among other problems, I don't want to maintain 3 slightly different versions of Nerd_STF at the same time. So I'm going to put the support update on hold for now. I won't delete my progress on it (I got about a quarter of the way done with support for .NET Standard 2.0. It's a big undertaking), I won't promise any completion date either.
|
First of all, I've gone and added all of the applicable `Mathf` functions as an extension to the `Equation` delegate. That way if you want to say, calculate the square root of an entire equation, rather than going:
|
||||||
|
```csharp
|
||||||
|
Equation result = x => Mathf.Sqrt(equ(x));
|
||||||
|
// Where `equ` is an `Equation` that represents the function we want to take the square root of.
|
||||||
|
```
|
||||||
|
you can shorten it down and remove some of the weirdness.
|
||||||
|
```csharp
|
||||||
|
Equation result = equ.Sqrt();
|
||||||
|
// Where `equ` is an `Equation` that represents the function we want to take the square root of.
|
||||||
|
```
|
||||||
|
|
||||||
Instead, this update ended up being a quality-of-life update. I already finished this part of the update before I decided to cancel the support update. This update now has lots of support for the new .NET 7 features. I'm now using a bunch of static abstract interfaces. I also added range indexing to almost all of the types available. The color byte types now have int fields instead of byte fields because ints are much more common. The values are automatically clamped between 0 and 255 just in case. Basically all types are records now because records are really nice. Lastly, some stuff has been marked as deprecated and to be removed in a future release because they already, exist, are kind of useless, and/or are misleading. Most of the deprecated stuff will be removed in either 2.4.0 or 2.5.0.
|
It works for any common function you'd want to apply to an equation.
|
||||||
|
|
||||||
Also, just want to note that despite the Vert`struct not being marked as deprecated, it will still be removed in 2.5.0. I didn't mark it because that would have created a bunch of warnings in my library. And I don't like warnings.
|
---
|
||||||
|
|
||||||
One final note, I've changed the description of the library and I've changed a bunch of the assembly and compilation settings.
|
Speaking of math functions (I guess that's the whole update, given the name), I'm now utilizing an implementation of CORDIC I made to calculate all trigonometric functions, hyperbolic trig functions, exponents, and logs. It's quite a neat process, and I could also have it completely wrong, but whatever I have, CORDIC or something else, works wonders, and is considerably faster than some other methods I tried. Of course, it's still nowhere near as fast as the built-in math functions, but they will always be on a whole other level. Maybe in the optimization update I'll bother to improve them, but they work quite well as-is for most use cases.
|
||||||
|
|
||||||
Anyway, that's it for this update. The longest delay was just getting this project to other versions of .NET. Stay tuned for v2.4.0, the Equations and Numbers update!</PackageReleaseNotes>
|
I've also implemented taylor series into the `Calculus` class. It's not particularly useful is most cases, so I wouldn't bother. The only time it would be a good idea to use it is if you've got some incredibly slow to calculate equation and want to optimize it. The function will take a long time at first, as it will have to generate second-derivatives and beyond, but afterwards the output equation will just be a simple-to-calculate polynomial (though the approximation gets worse the further you are from the reference point). If you've got an equation that's already fast to calculate, using the taylor series approximation will only be a negative. So take it with a grain of salt.
|
||||||
|
|
||||||
|
That's mostly it. I've fixed some issues/bugs here and there, renamed some small stuff (check the full changelog for more information), removed all the stuff marked obsolete and to be removed in this update, added some more math stuff like prime calculators, and other tiny changes. The next update will be focused on reworking the badly made geometry stuff I did a while back ([Version 2.1](https://github.com/That-One-Nerd/Nerd_STF/releases/tag/v2.1.0)). I know I say this all the time, but version 2.5 should be substantially bigger than this one. I'm going to be reworking the `Polygon` object entirely and will be improving quite a lot of other things in the whole `Nerd_STF.Mathematics.Geometry` namespace. Stay tuned!</PackageReleaseNotes>
|
||||||
<PackageProjectUrl>https://github.com/That-One-Nerd/Nerd_STF</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/That-One-Nerd/Nerd_STF</PackageProjectUrl>
|
||||||
<GenerateDocumentationFile>False</GenerateDocumentationFile>
|
<GenerateDocumentationFile>False</GenerateDocumentationFile>
|
||||||
<SignAssembly>False</SignAssembly>
|
<SignAssembly>False</SignAssembly>
|
||||||
@ -40,6 +51,7 @@ Anyway, that's it for this update. The longest delay was just getting this proje
|
|||||||
<EnforceCodeStyleInBuild>False</EnforceCodeStyleInBuild>
|
<EnforceCodeStyleInBuild>False</EnforceCodeStyleInBuild>
|
||||||
<AssemblyOriginatorKeyFile>C:\Users\kyley\Desktop\Misc Items\Private Keys\SNA\Nerd_STF.snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>C:\Users\kyley\Desktop\Misc Items\Private Keys\SNA\Nerd_STF.snk</AssemblyOriginatorKeyFile>
|
||||||
<DelaySign>False</DelaySign>
|
<DelaySign>False</DelaySign>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
@ -51,7 +63,7 @@ Anyway, that's it for this update. The longest delay was just getting this proje
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
|
||||||
<WarningLevel>9999</WarningLevel>
|
<WarningLevel>9999</WarningLevel>
|
||||||
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
|
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user