diff --git a/Changelog.md b/Changelog.md index 3668d65..71d4b4b 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,1112 +1,242 @@ -# Nerd_STF v2.3.2 +# Nerd_STF v2.4.0 (Equations and Numbers) -A bunch of stuff has changed, hasn't it? +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 `int`s 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! +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! + +Here's the full changelog: ``` * Nerd_STF * Exceptions - * InvalidSizeException - = Swapped a `this` method call for a `base` method call in `InvalidSizeException()` - * MathException - = Made `MathException()` have a default message - * Nerd_STFException - + Nerd_STFException(Exception) - = Made `Nerd_STFException()` have a default message - = Made `Nerd_STFException()` invoke the base constructor - * NoInverseException - = Changed base parent from `Exception` to `Nerd_STFException` - * UndefinedException - = Gave a better default message in `UndefinedException()` + + BadMethodException * Extensions * ConversionExtension - * ToFill(T[,]) - = Made the type parameter `size` nullable (if null, will be replaced with automatic size) - = Marked `ToDictionary(IEnumerable>)` as obsolete, as the `Dictionary` type already has a constructor for it. - * Graphics - + Abstract - + IColor - + IColorByte - + IColorFloat - + IColorPresets - * CMYKA - + Made `CMYKA` a record - + : IAverage - + : IClamp - + : IColorFloat - + : IColorPresets - + : IIndexAll - + : IIndexRangeAll - + : ILerp - + : IMedian - + : ISplittable - + float this[Index] - + float[] this[Range] - + Equals(IColor?) - + PrintMembers(StringBuilder) - - : IColorFloat - - Ceiling(CMYKA) - - Floor(CMYKA) - - Max(CMYKA[]) - - Min(CMYKA[]) - - Round(CMYKA) - - override Equals(object?) - - Equals(IColorFloat?) - - Equals(IColorByte?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - Clone() - - operator ==(CMYKA, CMYKA) - - operator !=(CMYKA, CMYKA) - = Made `GetHashCode()` invoke the base method - * CMYKAByte - + Made `CMYKAByte` a record - + : IAverage - + : IClamp - + : IColorByte - + : IColorPresets - + : IIndexAll - + : IIndexRangeAll - + : ILerp - + : IMedian - + : ISplittable - + p_c - + p_m - + p_y - + p_k - + p_a - + int this[Index] - + int[] this[Range] - + Equals(IColor?) - + PrintMembers(StringBuilder) - + ToArrayInt() - + ToFillInt() - + ToListInt() - - : IColorByte - - Max(CMYKAByte[]) - - Min(CMYKAByte[]) - - override Equals(object?) - - Equals(IColorFloat?) - - Equals(IColorByte?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - Clone() - - operator ==(CMYKAByte, CMYKAByte) - - operator !=(CMYKAByte, CMYKAByte) - = Changed the return type of `Black` from `CMYKA` to `CMYKAByte` - = Changed the return type of `Blue` from `CMYKA` to `CMYKAByte` - = Changed the return type of `Clear` from `CMYKA` to `CMYKAByte` - = Changed the return type of `Cyan` from `CMYKA` to `CMYKAByte` - = Changed the return type of `Gray` from `CMYKA` to `CMYKAByte` - = Changed the return type of `Green` from `CMYKA` to `CMYKAByte` - = Changed the return type of `Magenta` from `CMYKA` to `CMYKAByte` - = Changed the return type of `Orange` from `CMYKA` to `CMYKAByte` - = Changed the return type of `Purple` from `CMYKA` to `CMYKAByte` - = Changed the return type of `Red` from `CMYKA` to `CMYKAByte` - = Changed the return type of `White` from `CMYKA` to `CMYKAByte` - = Changed the return type of `Yellow` from `CMYKA` to `CMYKAByte` - = Made `C` a property that relates to `p_c` - = Made `M` a property that relates to `p_m` - = Made `Y` a property that relates to `p_y` - = Made `K` a property that relates to `p_k` - = Made `A` a property that relates to `p_a` - = Made `this[int]` return an `int` instead of a `byte` - = Made `SplitArray(CMYKAByte[])` use the private members of the type. - = Made `ToArray()` use the private members of the type. - = Made `ToList()` use the private members of the type. - = Made `GetEnumerator()` use the private members of the type. - = Made `GetHashCode()` invoke the base method - * HSVA - + Made `HSVA` a record - + : IAverage - + : IClamp - + : IColorFloat - + : IColorPresets - + : IIndexAll - + : IIndexRangeAll - + : ILerp - + : IMedian - + : ISplittable - + float this[Index] - + float[] this[Range] - + Equals(IColor?) - + PrintMembers(StringBuilder) - - : IColorFloat - - Ceiling(HSVA) - - Floor(HSVA) - - Max(HSVA[]) - - Min(HSVA[]) - - Round(HSVA) - - override Equals(object?) - - Equals(IColorFloat?) - - Equals(IColorByte?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - Clone() - - operator ==(HSVA, HSVA) - - operator !=(HSVA, HSVA) - = Made `GetHashCode()` invoke the base method - = Optimized some clamping in `this[int]` - * HSVAByte - + Made `HSVAByte` a record - + : IAverage - + : IClamp - + : IColorByte - + : IColorPresets - + : IIndexAll - + : IIndexRangeAll - + : ILerp - + : IMedian - + : ISplittable - + p_h - + p_s - + p_v - + p_a - + int this[Index] - + int[] this[Range] - + Equals(IColor?) - + PrintMembers(StringBuilder) - + ToArrayInt() - + ToFillInt() - + ToListInt() - - : IColorByte - - Max(HSVAByte[]) - - Min(HSVAByte[]) - - override Equals(object?) - - Equals(IColorFloat?) - - Equals(IColorByte?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - Clone() - - operator ==(HSVAByte, HSVAByte) - - operator !=(HSVAByte, HSVAByte) - = Changed the return type of `Black` from `HSVA` to `HSVAByte` - = Changed the return type of `Blue` from `HSVA` to `HSVAByte` - = Changed the return type of `Clear` from `HSVA` to `HSVAByte` - = Changed the return type of `Cyan` from `HSVA` to `HSVAByte` - = Changed the return type of `Gray` from `HSVA` to `HSVAByte` - = Changed the return type of `Green` from `HSVA` to `HSVAByte` - = Changed the return type of `Magenta` from `HSVA` to `HSVAByte` - = Changed the return type of `Orange` from `HSVA` to `HSVAByte` - = Changed the return type of `Purple` from `HSVA` to `HSVAByte` - = Changed the return type of `Red` from `HSVA` to `HSVAByte` - = Changed the return type of `White` from `HSVA` to `HSVAByte` - = Changed the return type of `Yellow` from `HSVA` to `HSVAByte` - = Changed the type of the parameter `t` from a `byte` to a `float` in `Lerp(HSVAByte, HSVAByte, byte, bool)` - = Made `H` a property that relates to `p_h` - = Made `S` a property that relates to `p_s` - = Made `V` a property that relates to `p_v` - = Made `A` a property that relates to `p_a` - = Made `this[int]` return an `int` instead of a `byte` - = Made `SplitArray(HSVAByte[])` use the private members of the type. - = Made `ToArray()` use the private members of the type. - = Made `ToList()` use the private members of the type. - = Made `GetEnumerator()` use the private members of the type. - = Made `GetHashCode()` invoke the base method - * Image - + : IEnumerable - - : IEnumerable - = Added a nullabilty modifier in `Equals(Image)` - = Changed a modifier in `Pixels` from `init` to `private set` - = Changed a modifier in `Size` from `init` to `private set` - = Fixed some random bug in `ModifySaturation(float, bool)` where if `set` is set to `true`, the saturation is completely zeroed out. - = Replaced a `this` assignment in `Scale(Float2)` with individual component assignments - = Turned `Image` into a `class` (from a `struct`) - * RGBA - + Made `RGBA` a record - + : IAverage - + : IClamp - + : IColorFloat - + : IColorPresets - + : IIndexAll - + : IIndexRangeAll - + : ILerp - + : IMedian - + : ISplittable - + float this[Index] - + float[] this[Range] - + Equals(IColor?) - + PrintMembers(StringBuilder) - - : IColorFloat - - Ceiling(RGBA) - - Floor(RGBA) - - Max(RGBA[]) - - Min(RGBA[]) - - Round(RGBA) - - override Equals(object?) - - Equals(IColorFloat?) - - Equals(IColorByte?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - Clone() - - operator ==(RGBA, RGBA) - - operator !=(RGBA, RGBA) - = Made `GetHashCode()` invoke the base method - * RGBAByte - + Made `RGBAByte` a record - + : IAverage - + : IClamp - + : IColorByte - + : IColorPresets - + : IIndexAll - + : IIndexRangeAll - + : ILerp - + : IMedian - + : ISplittable - + p_r - + p_g - + p_b - + p_a - + int this[Index] - + int[] this[Range] - + Equals(IColor?) - + PrintMembers(StringBuilder) - + ToArrayInt() - + ToFillInt() - + ToListInt() - - : IColorByte - - Max(RGBAByte[]) - - Min(RGBAByte[]) - - override Equals(object?) - - Equals(IColorFloat?) - - Equals(IColorByte?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - Clone() - - operator ==(RGBAByte, RGBAByte) - - operator !=(RGBAByte, RGBAByte) - = Changed the type of the parameter `t` from a `byte` to a `float` in `Lerp(RGBAByte, RGBAByte, byte, bool)` - = Made `R` a property that relates to `p_r` - = Made `G` a property that relates to `p_g` - = Made `B` a property that relates to `p_b` - = Made `A` a property that relates to `p_a` - = Made `this[int]` return an `int` instead of a `byte` - = Made `SplitArray(RGBAByte[])` use the private members of the type. - = Made `ToArray()` use the private members of the type. - = Made `ToList()` use the private members of the type. - = Made `GetEnumerator()` use the private members of the type. - = Made `GetHashCode()` invoke the base method - = Fixed a bug in `ToFill()` where it would return `HSVAByte` values instead - = Moved `IColor` to `Nerd_STF.Graphics.Abstract` - + : IEquatable - - : ICloneable - - : IEquatable - - : IEquatable - = Moved `IColorByte` to `Nerd_STF.Graphics.Abstract` - + ToArrayInt() - + ToFillInt() - + ToListInt() - = Moved `IColorFloat` to `Nerd_STF.Graphics.Abstract` + - ToDictionary(IEnumerable>) + * EquationExtension + + ValidNumberTypes + + Absolute(Equation) + + AbsoluteMod(Equation, float) + + ArcCos(Equation) + + ArcCot(Equation) + + ArcCsc(Equation) + + ArcSec(Equation) + + ArcSin(Equation) + + ArcTan(Equation) + + ArcCosh(Equation) + + ArcCoth(Equation) + + ArcCsch(Equation) + + ArcSech(Equation) + + ArcSinh(Equation) + + ArcTanh(Equation) + + Average(Equation, float, float, float) + + Average(Equation, Equation, Equation, float) + + Binomial(Equation, int, float) + + Binomial(Equation, Equation, Equation) + + Cbrt(Equation) + + Ceiling(Equation) + + Clamp(Equation, float, float) + + Clamp(Equation, Equation, Equation) + + Combinations(Equation, int) + + Combinations(Equation, Equation) + + Cos(Equation) + + Cosh(Equation) + + Cot(Equation) + + Coth(Equation) + + Csc(Equation) + + Csch(Equation) + + Divide(Equation, float[]) + + Divide(Equation, Equation[]) + + Factorial(Equation) + + Floor(Equation) + + GetDerivative(Equation, float) + + GetDerivativeAtPoint(Equation, float, float) + + GetIntegral(Equation, float, float, float) + + GetDynamicIntegral(Equation, Equation, Equation, float) + + GetTaylorSeries(Equation, float, int, float) + + GetValues(Equation, float, float, float) + + GradientDescent(Equation, float, float, int, float) + + InverseSqrt(Equation) + + Log(Equation, float) + + Max(Equation, float, float, float) + + Min(Equation, float, float, float) + + Permutations(Equation, int) + + Permutations(Equation, Equation) + + Power(Equation, float) + + Power(Equation, Equation) + + Product(Equation, float[]) + + Product(Equation, Equation[]) + + Root(Equation, float) + + Root(Equation, Equation) + + Round(Equation) + + Sec(Equation) + + Sech(Equation) + + Sin(Equation) + + Sinh(Equation) + + SolveBisection(Equation, float, float, float, float, int) + + SolveEquation(Equation, float, float, float, int) + + SolveNewton(Equation, float, float, float, int) + + Sqrt(Equation) + + Subtract(Equation, float[]) + + Subtract(Equation, Equation[]) + + Sum(Equation, float[]) + + Sum(Equation, Equation[]) + + Tan(Equation) + + Tanh(Equation) + + ZScore(Equation, float[]) + + ZScore(Equation, Equation[]) + + ZScore(Equation, float, float) + + ZScore(Equation, Equation, Equation) + + InvokeMethod(Equation, MethodInfo, object?[]?) + + InvokeMathMethod(Equation, string, object?[]?) + + StringExtension + + Helpers + + CordicHelper + + MathfHelper + + RationalHelper + + UnsafeHelper * Mathematics - + Abstract - + IAbsolute - + IAverage - + ICeiling - + ICeiling - + IClamp - + IClampMagnitude - + IClampMagnitude - + ICross - + ICross - + IDivide - + IDot - + IDot - + IFloor - + IFloor - + IIndexAll - + IIndexGet - + IIndexRangeAll - + IIndexRangeGet - + IIndexRangeSet - + IIndexSet - + ILerp - + ILerp - + IMagnitude - + IMax - + IMatrixPresets - + IMedian - + IMin - + IPresets1D - + IPresets2D - + IPresets3D - + IPresets4D - + IProduct - + IRound - + IRound - + IShape2D - + IShape3D - + ISplittable - + IStaticMatrix - + ISubtract - + ISum - + IVector2 - * Algebra - * Matrix - + this[Index, Index] - + this[Range, Range] - - ToString(string?) - - ToString(IFormatProvider) - = Added a better exception description in `Identity(Int2)` - = Added a nullability attribute to the return type of `Inverse()` - = Added a nullability attribute to the return type of `operator -(Matrix)` - = Added a nullability check in `Equals(Matrix)` - = Turned `Matrix` into a `class` (from a `struct`) - = Changed the parameter `other` in `Equals(Matrix)` to a nullable equivalent and added a nullability check - = Made `Inverse()` return `null` if there is no inverse instead of throwing an exception. - = Made `operator /(Matrix, Matrix)` throw an exception if no inverse exists for matrix `b` - = Marked `Equals(Matrix)` as virtual - * Matrix2x2 - + Made `Matrix2x2` into a record - + : IStaticMatrix - + this[Index, Index] - + this[Range, Range] - - : IMatrix - - override Equals(object?) - - ToString(string?) - - ToString(IFormatProvider) - - Clone() - - operator ==(Matrix2x2, Matrix2x2) - - operator !=(Matrix2x2, Matrix2x2) - = Added a nullability attribute to the return type of `Inverse()` - = Turned `Matrix2x2` into a `class` (from a `struct`) - = Marked `Equals(Matrix2x2)` as virtual - = Made `GetHashCode()` invoke the base method - = Made `Inverse()` return `null` if there is no inverse instead of throwing an exception. - = Made `operator /(Matrix2x2, Matrix2x2)` throw an exception if no inverse exists for matrix `b` - = Changed the parameter `other` in `Equals(Matrix2x2)` to a nullable equivalent and added a nullability check - * Matrix3x3 - + Made `Matrix3x3` into a record - + : IStaticMatrix - + this[Index, Index] - + this[Range, Range] - - : IMatrix - - override Equals(object?) - - ToString(string?) - - ToString(IFormatProvider) - - Clone() - - operator ==(Matrix3x3, Matrix3x3) - - operator !=(Matrix3x3, Matrix3x3) - = Turned `Matrix3x3` into a `class` (from a `struct`) - = Added a nullability attribute to the return type of `Inverse()` - = Added a nullability attribute to the return type of `operator -(Matrix3x3)` - = Marked `Equals(Matrix3x3)` as virtual - = Made `GetHashCode()` invoke the base method - = Changed the parameter `other` in `Equals(Matrix3x3)` to a nullable equivalent and added a nullability check - = Made `Cofactor()` use a preset rather than parameterless constructor - = Made `operator /(Matrix3x3, Matrix3x3)` throw an exception if no inverse exists for matrix `b` - * Matrix4x4 - + Made `Matrix4x4` into a record - + : IStaticMatrix - + this[Index, Index] - + this[Range, Range] - - : IMatrix - - override Equals(object?) - - ToString(string?) - - ToString(IFormatProvider) - - Clone() - - operator ==(Matrix4x4, Matrix4x4) - - operator !=(Matrix4x4, Matrix4x4) - = Added a nullability attribute to the return type of `Inverse()` - = Added a nullability attribute to the return type of `operator -(Matrix4x4)` - = Turned `Matrix4x4` into a `class` (from a `struct`) - = Marked `Equals(Matrix4x4)` as virtual - = Made `GetHashCode()` invoke the base method - = Changed the parameter `other` in `Equals(Matrix4x4)` to a nullable equivalent and added a nullability check - = Made `Cofactor()` use a preset rather than parameterless constructor - = Made `operator /(Matrix4x4, Matrix4x4)` throw an exception if no inverse exists for matrix `b` - * Vector2d - + Made `Vector2d` into a record - + : IAbsolute - + : IAverage - + : IClampMagnitude - + : ICross - + : IDot - + : IFromTuple - + : ILerp - + : IMax - + : IMagnitude - + : IMedian - + : IMin - + : IPresets2D - + : ISplittable - + : ISubtract - + : ISum - + float Magnitude - + operator Vector2d((Angle angle, float mag)) - - : ICloneable - - Clone() - - override Equals(object?) - - override ToString() - - ToString(string?, Angle.Type) - - ToString(IFormatProvider, Angle.Type) - - operator ==(Vector2d, Vector2d) - - operator !=(Vector2d, Vector2d) - = Made the tuple variable names lowercase in `SplitArray(Vector2d[])` - = Made `GetHashCode()` invoke the base method - = Made `ToString(Angle.Type)` resemble a record string - * Vector3d - + Made `Vector3d` into a record - + : IAbsolute - + : IAverage - + : IClampMagnitude - + : ICross - + : IDot - + : IFromTuple - + : IIndexAll - + : IIndexRangeAll - + : ILerp - + : IMax - + : IMagnitude - + : IMedian - + : IMin - + : IPresets3D - + : ISplittable - + : ISubtract - + : ISum - + float Magnitude - + this[Index] - + this[Range] - + operator Vector3d((Angle yaw, Angle pitch, float mag)) - - ICloneable - - Clone() - - override Equals(object?) - - override ToString() - - ToString(string?, Angle.Type) - - ToString(IFormatProvider, Angle.Type) - - operator ==(Vector3d, Vector3d) - - operator !=(Vector3d, Vector3d) - = Renamed the tuple variable names in `SplitArray(Vector3d[])` - = Made `GetHashCode()` invoke the base method - = Made `ToString(Angle.Type)` resemble a record string - = Moved `IMatrix` to `Nerd_STF.Mathematics.Abstract` - + : IAbsolute - + : ICeiling - + : IClamp - + : IDivide - + : IFloor - + : ILerp - + : IProduct - + : IRound - - : ICloneable - - : IEnumerable - = Added a nullability attribute to the return type of `Inverse()` - * Geometry - * Box2D - + Made `Box2D` into a record - + : IAbsolute - + : IAverage - + : ICeiling - + : IClamp - + : IFloor - + : ILerp - + : IMedian - + : IRound - + : IShape2D - + : ISplittable - + Round(Box2D) - + PrintMembers(StringBuilder) - - : ICloneable - - Max(Box2D[]) - - Min(Box2D[]) - - Clone() - - override Equals(object?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - operator ==(Box2D, Box2D) - - operator !=(Box2D, Box2D) - = Turned `Box2D` into `class` (from a `struct`) - = Marked `Equals(Box2D)` as virtual - = Made `GetHashCode()` invoke the base method - = Changed the parameter `other` in `Equals(Box2D)` to a nullable equivalent and added a nullability check - * Box3D - + Made `Box3D` into a record - + : IAbsolute - + : IAverage - + : ICeiling - + : IClamp - + : IFloor - + : ILerp - + : IMedian - + : IRound - + : IShape3D - + : ISplittable - + Round(Box3D) - + PrintMembers(StringBuilder) - - : ICloneable - - Clone() - - override Equals(object?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - operator ==(Box3D, Box3D) - - operator !=(Box3D, Box3D) - = Fixed an ambiguity in `Ceiling(Box3D)` - = Fixed an ambiguity in `Floor(Box3D)` - = Turned `Box3D` into `class` (from a `struct`) - = Marked `Equals(Box3D)` as virtual - = Made `GetHashCode()` invoke the base method - = Changed the parameter `other` in `Equals(Box3D)` to a nullable equivalent and added a nullability check - * Line - + Made `Line` into a record - + : IAbsolute - + : IAverage - + : ICeiling - + : IClamp - + : IFloor - + : IFromTuple - + : IIndexAll - + : IIndexRangeAll - + : ILerp - + : IMedian - + : IPresets3D - + : IRound - + : ISplittable - + Round(Line) - + PrintMembers(StringBuilder) - + operator Line((Vert start, Vert end)) - - : ICloneable - - Clone() - - Max(Line[]) - - Min(Line[]) - - override Equals(object?) - - ToString(string?) - - ToString(IFormatProvider) - - operator ==(Line, Line) - - operator !=(Line, Line) - = Turned `Line` into `class` (from a `struct`) - = Made `GetHashCode()` invoke the base method - = Marked `CompareTo(Line)` as deprecated, as it's a bit confusing - = Marked `operator >(Line, Line)` as deprecated, as it's a bit confusing - = Marked `operator <(Line, Line)` as deprecated, as it's a bit confusing - = Marked `operator >=(Line, Line)` as deprecated, as it's a bit confusing - = Marked `operator <=(Line, Line)` as deprecated, as it's a bit confusing - = Changed the parameter `other` in `Equals(Line)` to a nullable equivalent and added a nullability check - = Changed the parameter `other` in `CompareTo(Line)` to a nullable equivalent and added a nullability check - * Polygon - * Triangulate - = Replaced all `Exception`s thrown with `Nerd_STFException`s - - Max(Polygon[]) - - Min(Polygon[]) - - ToString(string?) - - ToString(IFormatProvider) - = Changed the deprecation removal notice from version 2.4.0 to 2.5.0 - * Quadrilateral - + Made `Quadrilateral` a record - + : IAbsolute - + : IAverage - + : ICeiling - + : IClamp - + : IFloor - + : IFromTuple - + : IIndexAll - + : IIndexRangeAll - + : ILerp - + : IRound - + : IShape2D - + Round(Quadrilateral) - + PrintMembers(StringBuilder) - + operator Quadrilateral((Vert a, Vert b, Vert c, Vert d)) - - : ICloneable - - Clone() - - override Equals(object?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - operator ==(Quadrilateral, Quadrilateral) - - operator !=(Quadrilateral, Quadrilateral) - = Turned `Quadrilateral` into a `class` (from a `struct`) - = Made `GetHashCode()` invoke the base method - = Marked `Equals(Quadrilateral)` as virtual - = Changed the parameter `other` in `Equals(Quadrilateral)` to a nullable equivalent and added a nullability check - * Sphere - + Made `Sphere` a record - + : IAverage - + : ICeiling - + : IClamp - + : IFloor - + : IFromTuple - + : ILerp - + : IMax - + : IMedian - + : IMin - + : IRound - + : ISplittable - + Round(Sphere) - + PrintMembers(StringBuilder) - + operator Sphere((Vert center, float radius)) - - : ICloneable - - Clone() - - override Equals(object?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - operator ==(Sphere, Sphere) - - operator !=(Sphere, Sphere) - = Made `GetHashCode()` invoke the base method - = Marked `Equals(float)` as deprecated. It will be removed in 2.5.0 - = Marked `CompareTo(float)` as deprecated. It will be removed in 2.5.0 - = Marked `operator ==(Sphere, float)` as deprecated. It will be removed in 2.5.0 - = Marked `operator !=(Sphere, float)` as deprecated. It will be removed in 2.5.0 - = Marked `operator >(Sphere, Sphere)` as deprecated. It will be removed in 2.5.0 - = Marked `operator <(Sphere, Sphere)` as deprecated. It will be removed in 2.5.0 - = Marked `operator >(Sphere, float)` as deprecated. It will be removed in 2.5.0 - = Marked `operator <(Sphere, float)` as deprecated. It will be removed in 2.5.0 - = Marked `operator >=(Sphere, Sphere)` as deprecated. It will be removed in 2.5.0 - = Marked `operator <=(Sphere, Sphere)` as deprecated. It will be removed in 2.5.0 - = Marked `operator >=(Sphere, float)` as deprecated. It will be removed in 2.5.0 - = Marked `operator <=(Sphere, float)` as deprecated. It will be removed in 2.5.0 - = Marked `Equals(Sphere)` as virtual - = Changed the parameter `other` in `Equals(Sphere)` to a nullable equivalent and added a nullability check - = Changed the parameter `other` in `CompareTo(Sphere)` to a nullable equivalent and added a nullability check - = Turned `Sphere` into a `class` (from a `struct`) - * Triangle - + Made `Triangle` a record - + : IAbsolute - + : IAverage - + : ICeiling - + : IClamp - + : IFloor - + : IFromTuple - + : IIndexAll - + : IIndexRangeAll - + : ILerp - + : IRound - + : IShape2D - + Round(Triangle) - + PrintMembers(StringBuilder) - + operator Triangle((Vert a, Vert b, Vert c)) - - : ICloneable - - Clone() - - override Equals(object?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - operator ==(Triangle, Triangle) - - operator !=(Triangle, Triangle) - = Turned `Triangle` into a `class` (from a `struct`) - = Made `GetHashCode()` invoke the base method - = Marked `Equals(Triangle)` as virtual - = Changed the parameter `other` in `Equals(Triangle)` to a nullable equivalent and added a nullability check - * Vert - + Round(Vert) - - ToString(string?) - - ToString(IFormatProvider) - = Moved `ISubdividable` to `Nerd_STF.Mathematics.Abstract` and renamed it to `ISubdivide` - = Moved `ITriangulatable` to `Nerd_STF.Mathematics.Abstract` and renamed it to `ITriangulate` + * Abstract + = Renamed `IPresets1D` to `IPresets1d` + = Renamed `IPresets2D` to `IPresets2d` + = Renamed `IPresets3D` to `IPresets3d` + = Renamed `IPresets4D` to `IPresets4d` + = Renamed `IShape2D` to `IShape2d` + = Renamed `IShape3D` to `IShape3d` * NumberSystems * Complex - + Marked `Complex` as a record - + Added parameters `float`, `float` - + : IAbsolute - + : IAverage - + : ICeiling - + : IClamp - + : IClampMagnitude - + : IDivide - + : IDot - + : IFloor - + : IIndexAll - + : IIndexRangeAll - + : ILerp - + : IMax - + : IMedian - + : IMin - + : IPresets2D - + : IProduct - + : IRound - + : ISplittable - + : ISum - + this[Index] - + this[Range] - + PrintMembers(StringBuilder) - + operator Complex((float, float)) - - : ICloneable - - Complex(float, float) - - Clone() - - override Equals(object?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - operator ==(Complex, Complex) - - operator !=(Complex, Complex) - = Added an assignment for `u` - = Added an assignment for `i` - = Marked `operator >(Complex, Complex)` as deprecated, as it's a bit confusing - = Marked `operator <(Complex, Complex)` as deprecated, as it's a bit confusing - = Marked `operator >=(Complex, Complex)` as deprecated, as it's a bit confusing - = Marked `operator <=(Complex, Complex)` as deprecated, as it's a bit confusing + - operator >(Complex, Complex) + - operator <(Complex, Complex) + - operator >=(Complex, Complex) + - operator <=(Complex, Complex) * Quaternion - + Marked `Quaternion` as a record - + Added parameters `float`, `float`, `float`, `float` - + : IAbsolute - + : IAverage - + : ICeiling - + : IClamp - + : IClampMagnitude - + : IDivide - + : IDot - + : IFloor - + : IIndexAll - + : IIndexRangeAll - + : ILerp - + : IMax - + : IMedian - + : IMin - + : IPresets4D - + : IProduct - + : IRound - + : ISplittable - + : ISum - + HighW - + LowW - + this[Index] - + this[Range] - + PrintMembers(StringBuilder) - + operator Quaternion((float, float, float, float)) - - : ICloneable - - Quaternion(float, float, float, float) - - Clone() - - override Equals(object?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - operator ==(Quaternion, Quaternion) - - operator !=(Quaternion, Quaternion) - = Added an assignment for `u` - = Added an assignment for `i` - = Added an assignment for `j` - = Added an assignment for `k` - = Fixed a mistake in `operator -(Quaternion)` that would just return the clone of the current instance rather than the proper negative. - = Made `GetHashCode()` invoke the base method - = Marked `operator >(Quaternion, Quaternion)` as deprecated, as it's a bit confusing - = Marked `operator <(Quaternion, Quaternion)` as deprecated, as it's a bit confusing - = Marked `operator >=(Quaternion, Quaternion)` as deprecated, as it's a bit confusing - = Marked `operator <=(Quaternion, Quaternion)` as deprecated, as it's a bit confusing - = Marked `Near` as deprecated, as it's replaced with `LowW`. - = Marked `Far` as deprecated, as it's replaced with `HighW`. + - Far + - Near + - operator >(Complex, Complex) + - operator <(Complex, Complex) + - operator >=(Complex, Complex) + - operator <=(Complex, Complex) * Samples - * Constants - = Fixed a typo and renamed `TwelthRoot2` to `TwelfthRoot2` - = Made `EulerMascheroniConstant` reference `EulerConstant`, since they are the same - = Made `LiebSquareIceConstant` more simplified - = Renamed `UniversalHyperbolicConstant` to `UniversalParabolicConstant` (oops) - = Renamed `RegularPaperfoldingSequence` to `RegularPaperfoldingConstant` - = Simplified `SecondHermiteConstant` - * Angle - + : IAbsolute - + : IAverage - + : IClamp - + : ILerp - + : IMax - + : IMedian - + : IMin - + : IPresets2D - + operator Angle((float, Type)) - - ToString(string?, Type) - - ToString(IFormatProvider, Type) - = Improved the `SplitArray(Type, Angle[])` to use another function for conversion. + + Fills + * Equations + + FlatLine + + XLine + = Simplified `CosWave` + = Simplified `SinWave` + = Replaced a `readonly` term with a generating field in `CosWave` + = Replaced a `readonly` term with a generating field in `SinWave` + = Replaced a `readonly` term with a generating field in `SawWave` + = Replaced a `readonly` term with a generating field in `SquareWave` + = Replaced a `readonly` term with a generating field in `SgnFill` + = Moved `SgnFill` to `Fills` and renamed it to `SignFill` + * Calculus + + GetTaylorSeries(Equation, float, int, float) + = Fixed a blunder in `GetDerivativeAtPoint(Equation, float, float)` + = Renamed the `stepCount` parameter in `GradientDescent(Equation, float, float, float, float)` to "iterations" and changed its type from `float` to `int` * Float2 - + Marked `Float2` as a record - + : IAbsolute - + : IAverage - + : ICeiling - + : IClamp - + : IClampMagnitude - + : ICross - + : IDivide - + : IDot - + : IFloor - + : IFromTuple - + : IIndexAll - + : IIndexRangeAll - + : ILerp - + : IMax - + : IMedian - + : IMin - + : IPresets2D - + : IProduct - + : IRound - + : ISplittable - + : ISubtract - + : ISum - + this[Index] - + this[Range] - + PrintMembers(StringBuilder) - + operator Float2((float, float)) - - : ICloneable - - Clone() - - override Equals(object?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - operator ==(Float2, Float2) - - operator !=(Float2, Float2) - = Made `Ceiling(Float2)` return an `Int2` instead of a `Float2` - = Made `Floor(Float2)` return an `Int2` instead of a `Float2` - = Made `Round(Float2)` return an `Int2` instead of a `Float2` - = Made `Max(Float2[])` compare magnitudes directly - = Made `Min(Float2[])` compare magnitudes directly - = Marked `CompareTo(Float2)` as deprecated, as it's a bit confusing - = Marked `operator >(Float2, Float2)` as deprecated, as it's a bit confusing - = Marked `operator <(Float2, Float2)` as deprecated, as it's a bit confusing - = Marked `operator >=(Float2, Float2)` as deprecated, as it's a bit confusing - = Marked `operator <=(Float2, Float2)` as deprecated, as it's a bit confusing + - Removed the `Obsolete` attribute from `CompareTo(Float2)` + - operator >(Float2, Float2) + - operator <(Float2, Float2) + - operator >=(Float2, Float2) + - operator <=(Float2, Float2) * Float3 - + Marked `Float3` as a record - + : IAbsolute - + : IAverage - + : ICeiling - + : IClamp - + : IClampMagnitude - + : ICross - + : IDivide - + : IDot - + : IFloor - + : IFromTuple - + : IIndexAll - + : IIndexRangeAll - + : ILerp - + : IMathOperators - + : IMax - + : IMedian - + : IMin - + : IPresets3D - + : IProduct - + : IRound - + : ISplittable - + : ISubtract - + : ISum - + this[Index] - + this[Range] - + PrintMembers(StringBuilder) - + operator Float3((float, float, float)) - - : ICloneable - - Float3(float, float, float) - - Clone() - - override Equals(object?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - operator ==(Float3, Float3) - - operator !=(Float3, Float3) - = Made `Ceiling(Float3)` return an `Int3` instead of a `Float3` - = Made `Floor(Float3)` return an `Int3` instead of a `Float3` - = Made `Round(Float3)` return an `Int3` instead of a `Float3` - = Made `Max(Float3[])` compare magnitudes directly - = Made `Min(Float3[])` compare magnitudes directly - = Made `GetHashCode()` invoke the base method - = Marked `CompareTo(Float3)` as deprecated, as it's a bit confusing - = Marked `operator >(Float3, Float3)` as deprecated, as it's a bit confusing - = Marked `operator <(Float3, Float3)` as deprecated, as it's a bit confusing - = Marked `operator >=(Float3, Float3)` as deprecated, as it's a bit confusing - = Marked `operator <=(Float3, Float3)` as deprecated, as it's a bit confusing + - Removed the `Obsolete` attribute from `CompareTo(Float3)` + - operator >(Float3, Float3) + - operator <(Float3, Float3) + - operator >=(Float3, Float3) + - operator <=(Float3, Float3) * Float4 - + Marked `Float4` as a record - + : IAbsolute - + : IAverage - + : ICeiling - + : IClamp - + : IClampMagnitude - + : IDivide - + : IDot - + : IFloor - + : IFromTuple - + : IIndexAll - + : IIndexRangeAll - + : ILerp - + : IMathOperators - + : IMax - + : IMedian - + : IMin - + : IPresets4D - + : IProduct - + : IRound - + : ISplittable - + : ISubtract - + : ISum - + this[Index] - + this[Range] - + PrintMembers(StringBuilder) - + operator Float4((float, float, float, float)) - - : ICloneable - - Float4(float, float, float, float) - - Clone() - - override Equals(object?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - operator ==(Float4, Float4) - - operator !=(Float4, Float4) - = Made `Ceiling(Float4)` return an `Int4` instead of a `Float4` - = Made `Floor(Float4)` return an `Int4` instead of a `Float4` - = Made `Round(Float4)` return an `Int4` instead of a `Float4` - = Made `Max(Float4[])` compare magnitudes directly - = Made `Min(Float4[])` compare magnitudes directly - = Made `GetHashCode()` invoke the base method - = Marked `CompareTo(Float4)` as deprecated, as it's a bit confusing - = Marked `operator >(Float4, Float4)` as deprecated, as it's a bit confusing - = Marked `operator <(Float4, Float4)` as deprecated, as it's a bit confusing - = Marked `operator >=(Float4, Float4)` as deprecated, as it's a bit confusing - = Marked `operator <=(Float4, Float4)` as deprecated, as it's a bit confusing + - Far + - Near + - Removed the `Obsolete` attribute from `CompareTo(Float4)` + - operator >(Float4, Float4) + - operator <(Float4, Float4) + - operator >=(Float4, Float4) + - operator <=(Float4, Float4) * Int2 - + Marked `Int2` as a record - + : IAbsolute - + : IAverage - + : IClamp - + : IClampMagnitude - + : ICross - + : IDivide - + : IDot - + : IFromTuple - + : IIndexAll - + : IIndexRangeAll - + : ILerp - + : IMathOperators - + : IMax - + : IMedian - + : IMin - + : IPresets2D - + : IProduct - + : ISplittable - + : ISubtract - + : ISum - + this[Index] - + this[Range] - + PrintMembers(StringBuilder) - + operator Int2((int, int)) - - : ICloneable - - Clone() - - override Equals(object?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - operator ==(Int2, Int2) - - operator !=(Int2, Int2) - = Made `Max(Int2[])` compare magnitudes directly - = Made `Min(Int2[])` compare magnitudes directly - = Made `GetHashCode()` invoke the base method - = Marked `CompareTo(Int2)` as deprecated, as it's a bit confusing - = Marked `operator >(Int2, Int2)` as deprecated, as it's a bit confusing - = Marked `operator <(Int2, Int2)` as deprecated, as it's a bit confusing - = Marked `operator >=(Int2, Int2)` as deprecated, as it's a bit confusing - = Marked `operator <=(Int2, Int2)` as deprecated, as it's a bit confusing + - Removed the `Obsolete` attribute from `CompareTo(Int2)` + - operator >(Int2, Int2) + - operator <(Int2, Int2) + - operator >=(Int2, Int2) + - operator <=(Int2, Int2) * Int3 - + Marked `Int3` as a record - + : IAbsolute - + : IAverage - + : IClamp - + : IClampMagnitude, - + : ICross - + : IDivide - + : IDot - + : IFromTuple - + : IIndexAll - + : IIndexRangeAll - + : ILerp - + : IMathOperators - + : IMax - + : IMedian - + : IMin - + : IProduct - + : ISplittable - + : ISubtract - + : ISum - + this[Index] - + this[Range] - + PrintMembers(StringBuilder) - + operator Int3((int, int, int)) - - : ICloneable() - - Int3(int, int, int) - - Clone() - - override Equals(object?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - operator ==(Int3, Int3) - - operator !=(Int3, Int3) - = Made `Max(Int3[])` compare magnitudes directly - = Made `Min(Int3[])` compare magnitudes directly - = Made `GetHashCode()` invoke the base method - = Marked `CompareTo(Int3)` as deprecated, as it's a bit confusing - = Marked `operator >(Int3, Int3)` as deprecated, as it's a bit confusing - = Marked `operator <(Int3, Int3)` as deprecated, as it's a bit confusing - = Marked `operator >=(Int3, Int3)` as deprecated, as it's a bit confusing - = Marked `operator <=(Int3, Int3)` as deprecated, as it's a bit confusing + - Removed the `Obsolete` attribute from `CompareTo(Int3)` + - operator >(Int3, Int3) + - operator <(Int3, Int3) + - operator >=(Int3, Int3) + - operator <=(Int3, Int3) * Int4 - + Marked `Int4` as a record - + : IAbsolute - + : IAverage - + : IClamp - + : IClampMagnitude - + : IDivide - + : IDot - + : IFromTuple - + : IIndexAll - + : IIndexRangeAll - + : ILerp - + : IMathOperators - + : IMax - + : IMedian - + : IMin - + : IProduct - + : ISplittable - + : ISubtract - + : ISum - + this[Index] - + this[Range] - + PrintMembers(StringBuilder) - + operator Int4((int, int, int, int)) - - : ICloneable - - Int4(int, int, int, int) - - Clone() - - override Equals(object?) - - override ToString() - - ToString(string?) - - ToString(IFormatProvider) - - operator ==(Int4, Int4) - - operator !=(Int4, Int4) - = Marked `Deep` as deprecated - = Made `Max(Int4[])` compare magnitudes directly - = Made `Min(Int4[])` compare magnitudes directly - = Made `GetHashCode()` invoke the base method - = Marked `CompareTo(Int4)` as deprecated, as it's a bit confusing - = Marked `operator >(Int4, Int4)` as deprecated, as it's a bit confusing - = Marked `operator <(Int4, Int4)` as deprecated, as it's a bit confusing - = Marked `operator >=(Int4, Int4)` as deprecated, as it's a bit confusing - = Marked `operator <=(Int4, Int4)` as deprecated, as it's a bit confusing + - Far + - Deep + - Removed the `Obsolete` attribute from `CompareTo(Int4)` + - operator >(Int4, Int4) + - operator <(Int4, Int4) + - operator >=(Int4, Int4) + - operator <=(Int4, Int4) * Mathf - = Forced `Max(T[])` to not return a nullable object - = Forced `Min(T[])` to not return a nullable object - = Renamed a parameter `value` in `Mathf.Lerp(int, int, float, bool)` to `t` - = Replaced a `ContainsKey(float)` call with a `TryGetValue(float, out float)` call in `MakeEquation(Dictionary)` - = Removed a useless call to `Absolute(int)` in `PowerMod(int, int, int)` - = Simplified a list initialization in `Factors(int)` + + ArcCosh(float) + + ArcCoth(float) + + ArcCsch(float) + + ArcSech(float) + + ArcSinh(float) + + ArcTanh(float) + + ArcTanh2(float, float) + + Cbrt(float) + + Cosh(float) + + Coth(float) + + Csch(float) + + IsPrime(int, PrimeCheckMethod) + + Lerp(float, float, Equation, bool) + + Lerp(Equation, Equation, float, bool) + + Lerp(Equation, Equation, Equation, bool) + + Log(float, float) + + PrimeFactors(int) + + PowerMod(long, long, long) + + Sech(float) + + Sinh(float) + + SharedItems(T[][]) + + SolveBisection(Equation, float, float, float, float, int) + + SolveEquation(Equation, float, float, float, int) + + SolveNewton(Equation, float, float, float, int) + + Tanh(float) + = Improved the `Sqrt(float)` method by using a solution finder + = The `ArcSin(float)` method now uses a solution finder rather than the base math library + = The `Power(float, float)` method now utilizes a custom CORDIC implementation rather than the base math library + + PrimeCheckMethod + + Equation2d + + Rational + + SimplificationMethod * Miscellaneous - + AssemblyConfig + * AssemblyConfig + - using System.Reflection * GlobalUsings - + global using Nerd_STF.Graphics.Abstract - + global using Nerd_STF.Mathematics.Abstract - + global using System.Text - + global using System.Runtime.Serialization - + Nerd_STF - = Marked `Foreach(object)` as deprecated. Why would you even use this? - = Marked `Foreach(T)` as deprecated. Why would you even use this? - = Moved `IClosest` to `Nerd_STF.Mathematics.Abstract` and renamed it to `IClosestTo` - = Moved `IContainer` to `Nerd_STF.Mathematics.Abstract` and renamed it to `IContains` + + global using Nerd_STF.Helpers + + global using System.Reflection + - Foreach(object) + - Foreach(T) + = Moved `IEncapsulator` to `Nerd_STF.Mathematics.Abstract` and renamed it to `IEncapsulate` + = Renamed `Fill2D` to `Fill2d` + = Renamed `IGroup2D` to `IGroup2d` + = Renamed `Modifier2D` to `IModifier2d` + = Renamed `Modifier2D` to `IModifier2d` + = Renamed `Modifier2D` to `IModifier2d` += Made `Nerd_STF` allow unsafe code blocks ``` diff --git a/Extras/Banner.png b/Extras/Banner.png new file mode 100644 index 0000000..e9f150e Binary files /dev/null and b/Extras/Banner.png differ diff --git a/Extras/Logo Square High Res.png b/Extras/Logo Square High Res.png new file mode 100644 index 0000000..f1763b0 Binary files /dev/null and b/Extras/Logo Square High Res.png differ diff --git a/Extras/Logo Square.png b/Extras/Logo Square.png index 1290c08..0f1ecca 100644 Binary files a/Extras/Logo Square.png and b/Extras/Logo Square.png differ diff --git a/Nerd_STF/Exceptions/BadMethodException.cs b/Nerd_STF/Exceptions/BadMethodException.cs new file mode 100644 index 0000000..9c7a7ba --- /dev/null +++ b/Nerd_STF/Exceptions/BadMethodException.cs @@ -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) { } +} diff --git a/Nerd_STF/Extensions/ConversionExtension.cs b/Nerd_STF/Extensions/ConversionExtension.cs index 6f82334..f34fc20 100644 --- a/Nerd_STF/Extensions/ConversionExtension.cs +++ b/Nerd_STF/Extensions/ConversionExtension.cs @@ -2,18 +2,7 @@ public static class ConversionExtension { - [Obsolete("This extension turns out to already exist as a constructor in the " + - "System.Collections.Generic.Dictionary type. This will be removed in v2.4.0")] - public static Dictionary ToDictionary - (this IEnumerable> pairs) - where TKey : notnull - { - Dictionary res = new(); - foreach (KeyValuePair pair in pairs) res.Add(pair.Key, pair.Value); - return res; - } - public static Fill ToFill(this T[] arr) => i => arr[i]; public static Fill ToFill(this T[,] arr, Int2? size) => arr.Flatten(size).ToFill(); - public static Fill2D ToFill2D(this T[,] arr) => (x, y) => arr[x, y]; + public static Fill2d ToFill2D(this T[,] arr) => (x, y) => arr[x, y]; } diff --git a/Nerd_STF/Extensions/EquationExtension.cs b/Nerd_STF/Extensions/EquationExtension.cs index b3b82d8..e533133 100644 --- a/Nerd_STF/Extensions/EquationExtension.cs +++ b/Nerd_STF/Extensions/EquationExtension.cs @@ -2,6 +2,299 @@ public static class EquationExtension { + private static readonly List 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 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(); + 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 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(); + 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 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(); + 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 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 { ScaleType.X => x => equ(x / value), diff --git a/Nerd_STF/Extensions/StringExtension.cs b/Nerd_STF/Extensions/StringExtension.cs new file mode 100644 index 0000000..d19df3f --- /dev/null +++ b/Nerd_STF/Extensions/StringExtension.cs @@ -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 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 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(); + } +} diff --git a/Nerd_STF/Fill2D.cs b/Nerd_STF/Fill2D.cs index 56e92ec..3df2f71 100644 --- a/Nerd_STF/Fill2D.cs +++ b/Nerd_STF/Fill2D.cs @@ -1,3 +1,3 @@ namespace Nerd_STF; -public delegate T Fill2D(int indexX, int indexY); +public delegate T Fill2d(int indexX, int indexY); diff --git a/Nerd_STF/Foreach.cs b/Nerd_STF/Foreach.cs deleted file mode 100644 index 8004551..0000000 --- a/Nerd_STF/Foreach.cs +++ /dev/null @@ -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 item); diff --git a/Nerd_STF/Graphics/Image.cs b/Nerd_STF/Graphics/Image.cs index e72308f..f15fa0c 100644 --- a/Nerd_STF/Graphics/Image.cs +++ b/Nerd_STF/Graphics/Image.cs @@ -29,7 +29,7 @@ public class Image : ICloneable, IEnumerable, IEquatable 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); } - public Image(int width, int height, Fill2D fill) + public Image(int width, int height, Fill2d fill) { Pixels = new IColor[width, height]; Size = new(width, height); @@ -39,7 +39,7 @@ public class Image : ICloneable, IEnumerable, IEquatable 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 fill) : this(size.x, size.y, fill) { } - public Image(Int2 size, Fill2D fill) : this(size.x, size.y, fill) { } + public Image(Int2 size, Fill2d fill) : this(size.x, size.y, fill) { } public IColor this[int indexX, int indexY] { diff --git a/Nerd_STF/Helpers/CordicHelper.cs b/Nerd_STF/Helpers/CordicHelper.cs new file mode 100644 index 0000000..bcd90ae --- /dev/null +++ b/Nerd_STF/Helpers/CordicHelper.cs @@ -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(data); + } +} diff --git a/Nerd_STF/Helpers/MathfHelper.cs b/Nerd_STF/Helpers/MathfHelper.cs new file mode 100644 index 0000000..4cbaba2 --- /dev/null +++ b/Nerd_STF/Helpers/MathfHelper.cs @@ -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. + } +} diff --git a/Nerd_STF/Helpers/RationalHelper.cs b/Nerd_STF/Helpers/RationalHelper.cs new file mode 100644 index 0000000..645d8a0 --- /dev/null +++ b/Nerd_STF/Helpers/RationalHelper.cs @@ -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; + } +} diff --git a/Nerd_STF/Helpers/UnsafeHelper.cs b/Nerd_STF/Helpers/UnsafeHelper.cs new file mode 100644 index 0000000..30fbc00 --- /dev/null +++ b/Nerd_STF/Helpers/UnsafeHelper.cs @@ -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 obj) + where CT : unmanaged + where NT : unmanaged + => *(NT*)&obj; +} diff --git a/Nerd_STF/IEncapsulator.cs b/Nerd_STF/IEncapsulator.cs deleted file mode 100644 index f02b25d..0000000 --- a/Nerd_STF/IEncapsulator.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Nerd_STF; - -public interface IEncapsulator : IContains where T : IEquatable where TE : IEquatable -{ - public T Encapsulate(TE val); -} diff --git a/Nerd_STF/IGroup2D.cs b/Nerd_STF/IGroup2D.cs index ae1e3fc..251f9ce 100644 --- a/Nerd_STF/IGroup2D.cs +++ b/Nerd_STF/IGroup2D.cs @@ -1,7 +1,7 @@ namespace Nerd_STF; -public interface IGroup2D : IGroup +public interface IGroup2d : IGroup { public T[,] ToArray2D(); - public Fill2D ToFill2D(); + public Fill2d ToFill2D(); } diff --git a/Nerd_STF/Mathematics/Abstract/IEncapsulate.cs b/Nerd_STF/Mathematics/Abstract/IEncapsulate.cs new file mode 100644 index 0000000..9cc537b --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IEncapsulate.cs @@ -0,0 +1,6 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IEncapsulate : IContains where T : IEquatable where TE : IEquatable +{ + public T Encapsulate(TE val); +} diff --git a/Nerd_STF/Mathematics/Abstract/IMatrix.cs b/Nerd_STF/Mathematics/Abstract/IMatrix.cs index deb1b0a..84429c2 100644 --- a/Nerd_STF/Mathematics/Abstract/IMatrix.cs +++ b/Nerd_STF/Mathematics/Abstract/IMatrix.cs @@ -1,7 +1,7 @@ namespace Nerd_STF.Mathematics.Abstract; public interface IMatrix : IAbsolute, ICeiling, IClamp, IDivide, - IEquatable, IFloor, IGroup2D, ILerp, IProduct, IRound, + IEquatable, IFloor, IGroup2d, ILerp, IProduct, IRound, ISubtract, ISum where T : IMatrix { diff --git a/Nerd_STF/Mathematics/Abstract/IPresets1D.cs b/Nerd_STF/Mathematics/Abstract/IPresets1D.cs index 8caa6f3..832a484 100644 --- a/Nerd_STF/Mathematics/Abstract/IPresets1D.cs +++ b/Nerd_STF/Mathematics/Abstract/IPresets1D.cs @@ -1,6 +1,6 @@ namespace Nerd_STF.Mathematics.Abstract; -public interface IPresets1D where T : IPresets1D +public interface IPresets1d where T : IPresets1d { public static abstract T One { get; } public static abstract T Zero { get; } diff --git a/Nerd_STF/Mathematics/Abstract/IPresets2D.cs b/Nerd_STF/Mathematics/Abstract/IPresets2D.cs index b9f4b00..ab38cfa 100644 --- a/Nerd_STF/Mathematics/Abstract/IPresets2D.cs +++ b/Nerd_STF/Mathematics/Abstract/IPresets2D.cs @@ -1,6 +1,6 @@ namespace Nerd_STF.Mathematics.Abstract; -public interface IPresets2D : IPresets1D where T : IPresets2D +public interface IPresets2d : IPresets1d where T : IPresets2d { public static abstract T Down { get; } public static abstract T Left { get; } diff --git a/Nerd_STF/Mathematics/Abstract/IPresets3D.cs b/Nerd_STF/Mathematics/Abstract/IPresets3D.cs index 68772cc..893ba07 100644 --- a/Nerd_STF/Mathematics/Abstract/IPresets3D.cs +++ b/Nerd_STF/Mathematics/Abstract/IPresets3D.cs @@ -1,6 +1,6 @@ namespace Nerd_STF.Mathematics.Abstract; -public interface IPresets3D : IPresets2D where T : IPresets3D +public interface IPresets3d : IPresets2d where T : IPresets3d { public static abstract T Back { get; } public static abstract T Forward { get; } diff --git a/Nerd_STF/Mathematics/Abstract/IPresets4D.cs b/Nerd_STF/Mathematics/Abstract/IPresets4D.cs index 188bfd7..5e6fa91 100644 --- a/Nerd_STF/Mathematics/Abstract/IPresets4D.cs +++ b/Nerd_STF/Mathematics/Abstract/IPresets4D.cs @@ -1,6 +1,6 @@ namespace Nerd_STF.Mathematics.Abstract; -public interface IPresets4D : IPresets2D, IPresets3D where T : IPresets4D +public interface IPresets4d : IPresets2d, IPresets3d where T : IPresets4d { public static abstract T HighW { get; } public static abstract T LowW { get; } diff --git a/Nerd_STF/Mathematics/Abstract/IShape2D.cs b/Nerd_STF/Mathematics/Abstract/IShape2D.cs index 83bc19c..2a85863 100644 --- a/Nerd_STF/Mathematics/Abstract/IShape2D.cs +++ b/Nerd_STF/Mathematics/Abstract/IShape2D.cs @@ -2,7 +2,7 @@ namespace Nerd_STF.Mathematics.Abstract; -public interface IShape2D where TNumber : INumber +public interface IShape2d where TNumber : INumber { public TNumber Area { get; } public TNumber Perimeter { get; } diff --git a/Nerd_STF/Mathematics/Abstract/IShape3D.cs b/Nerd_STF/Mathematics/Abstract/IShape3D.cs index babb384..e30f435 100644 --- a/Nerd_STF/Mathematics/Abstract/IShape3D.cs +++ b/Nerd_STF/Mathematics/Abstract/IShape3D.cs @@ -2,7 +2,7 @@ namespace Nerd_STF.Mathematics.Abstract; -public interface IShape3D where TNumber : INumber +public interface IShape3d where TNumber : INumber { public TNumber SurfaceArea { get; } public TNumber Volume { get; } diff --git a/Nerd_STF/Mathematics/Algebra/Matrix.cs b/Nerd_STF/Mathematics/Algebra/Matrix.cs index e3fcacd..3d13abc 100644 --- a/Nerd_STF/Mathematics/Algebra/Matrix.cs +++ b/Nerd_STF/Mathematics/Algebra/Matrix.cs @@ -20,7 +20,7 @@ public class Matrix : IMatrix return m; } 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 bool HasMinors => Size.x > 1 && Size.y > 1; @@ -85,13 +85,13 @@ public class Matrix : IMatrix 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]; } - public Matrix(Int2 size, Fill2D vals) + public Matrix(Int2 size, Fill2d vals) { Size = size; 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); } - public Matrix(Int2 size, Fill2D vals) + public Matrix(Int2 size, Fill2d vals) { Size = size; array = new float[size.x, size.y]; @@ -188,7 +188,7 @@ public class Matrix : IMatrix 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++) array[r, c] = modifier(new(r, c), array[r, c]); @@ -310,7 +310,7 @@ public class Matrix : IMatrix public float[] ToArray() => array.Flatten(new(Size.y, Size.x)); public float[,] ToArray2D() => array; public Fill ToFill() => ToFillExtension.ToFill(this); - public Fill2D ToFill2D() + public Fill2d ToFill2D() { Matrix @this = this; return (x, y) => @this[x, y]; diff --git a/Nerd_STF/Mathematics/Algebra/Matrix2x2.cs b/Nerd_STF/Mathematics/Algebra/Matrix2x2.cs index a969cd5..620b6a2 100644 --- a/Nerd_STF/Mathematics/Algebra/Matrix2x2.cs +++ b/Nerd_STF/Mathematics/Algebra/Matrix2x2.cs @@ -68,8 +68,8 @@ public record class Matrix2x2 : IStaticMatrix public Matrix2x2(Fill 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(int[,] nums) : this(nums[0, 0], nums[0, 1], nums[1, 0], nums[1, 1]) { } - public Matrix2x2(Fill2D fill) : this(fill(0, 0), fill(0, 1), fill(1, 0), fill(1, 1)) { } - public Matrix2x2(Fill2D fill) : this(fill(0, 0), fill(0, 1), fill(1, 0), fill(1, 1)) { } + public Matrix2x2(Fill2d fill) : this(fill(0, 0), fill(0, 1), fill(1, 0), fill(1, 1)) { } + public Matrix2x2(Fill2d 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(Fill fill) : this(fill(0), fill(1)) { } public Matrix2x2(Fill fill) : this((IEnumerable)fill(0), fill(1)) { } @@ -265,7 +265,7 @@ public record class Matrix2x2 : IStaticMatrix { r2c1, r2c2 } }; public Fill ToFill() => ToFillExtension.ToFill(this); - public Fill2D ToFill2D() + public Fill2d ToFill2D() { Matrix2x2 @this = this; return (x, y) => @this[x, y]; diff --git a/Nerd_STF/Mathematics/Algebra/Matrix3x3.cs b/Nerd_STF/Mathematics/Algebra/Matrix3x3.cs index 17a111a..d028038 100644 --- a/Nerd_STF/Mathematics/Algebra/Matrix3x3.cs +++ b/Nerd_STF/Mathematics/Algebra/Matrix3x3.cs @@ -106,9 +106,9 @@ public record class Matrix3x3 : IStaticMatrix 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], nums[1, 0], nums[1, 1], nums[1, 2], nums[2, 0], nums[2, 1], nums[2, 2]) { } - public Matrix3x3(Fill2D fill) : this(fill(0, 0), fill(0, 1), fill(0, 2), + public Matrix3x3(Fill2d 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)) { } - public Matrix3x3(Fill2D fill) : this(fill(0, 0), fill(0, 1), fill(0, 2), + public Matrix3x3(Fill2d 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)) { } 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 fill) : this(fill(0), fill(1), fill(2)) { } @@ -371,7 +371,7 @@ public record class Matrix3x3 : IStaticMatrix { r3c1, r3c2, r3c3 } }; public Fill ToFill() => ToFillExtension.ToFill(this); - public Fill2D ToFill2D() + public Fill2d ToFill2D() { Matrix3x3 @this = this; return (x, y) => @this[x, y]; diff --git a/Nerd_STF/Mathematics/Algebra/Matrix4x4.cs b/Nerd_STF/Mathematics/Algebra/Matrix4x4.cs index 0f2a96b..1297034 100644 --- a/Nerd_STF/Mathematics/Algebra/Matrix4x4.cs +++ b/Nerd_STF/Mathematics/Algebra/Matrix4x4.cs @@ -146,10 +146,10 @@ public record class Matrix4x4 : IStaticMatrix 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[3, 1], nums[3, 2], nums[3, 3]) { } - public Matrix4x4(Fill2D fill) : this(fill(0, 0), fill(0, 1), fill(0, 2), fill(0, 3), fill(1, 0), + public Matrix4x4(Fill2d 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(3, 1), fill(3, 2), fill(3, 3)) { } - public Matrix4x4(Fill2D fill) : this(fill(0, 0), fill(0, 1), fill(0, 2), fill(0, 3), fill(1, 0), + public Matrix4x4(Fill2d 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(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, @@ -502,7 +502,7 @@ public record class Matrix4x4 : IStaticMatrix { r4c1, r4c2, r4c3, r4c4 } }; public Fill ToFill() => ToFillExtension.ToFill(this); - public Fill2D ToFill2D() + public Fill2d ToFill2D() { Matrix4x4 @this = this; return (x, y) => @this[x, y]; diff --git a/Nerd_STF/Mathematics/Algebra/Vector2d.cs b/Nerd_STF/Mathematics/Algebra/Vector2d.cs index 3e3488b..98a3e10 100644 --- a/Nerd_STF/Mathematics/Algebra/Vector2d.cs +++ b/Nerd_STF/Mathematics/Algebra/Vector2d.cs @@ -4,7 +4,7 @@ public record struct Vector2d : IAbsolute, IAverage, IClampMagnitude, IComparable, ICross, IDot, IEquatable, IFromTuple, ILerp, IMax, IMagnitude, IMedian, IMin, - IPresets2D, ISplittable, ISubtract, + IPresets2d, ISplittable, ISubtract, ISum { public static Vector2d Down => new(Angle.Down); diff --git a/Nerd_STF/Mathematics/Algebra/Vector3d.cs b/Nerd_STF/Mathematics/Algebra/Vector3d.cs index 1798ac6..ecb3040 100644 --- a/Nerd_STF/Mathematics/Algebra/Vector3d.cs +++ b/Nerd_STF/Mathematics/Algebra/Vector3d.cs @@ -4,7 +4,7 @@ public record struct Vector3d : IAbsolute, IAverage, IClampM IComparable, ICross, IDot, IEquatable, IFromTuple, IIndexAll, IIndexRangeAll, ILerp, IMagnitude, IMax, IMedian, IMin, - IPresets3D, ISubtract, ISum + IPresets3d, ISubtract, ISum { public static Vector3d Back => new(Angle.Zero, Angle.Up); public static Vector3d Down => new(Angle.Down, Angle.Zero); diff --git a/Nerd_STF/Mathematics/Angle.cs b/Nerd_STF/Mathematics/Angle.cs index 712f12c..f691faa 100644 --- a/Nerd_STF/Mathematics/Angle.cs +++ b/Nerd_STF/Mathematics/Angle.cs @@ -2,7 +2,7 @@ public struct Angle : IAbsolute, IAverage, IClamp, ICloneable, IComparable, IEquatable, ILerp, IMax, IMedian, - IMin, IPresets2D + IMin, IPresets2d { public static Angle Down => new(270); public static Angle Left => new(180); diff --git a/Nerd_STF/Mathematics/Calculus.cs b/Nerd_STF/Mathematics/Calculus.cs index 5eba207..c61d5ab 100644 --- a/Nerd_STF/Mathematics/Calculus.cs +++ b/Nerd_STF/Mathematics/Calculus.cs @@ -7,7 +7,7 @@ public static class Calculus public static Equation GetDerivative(Equation equ, float step = DefaultStep) => x => GetDerivativeAtPoint(equ, x, step); 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) { @@ -19,14 +19,38 @@ public static class Calculus public static Equation GetDynamicIntegral(Equation equ, Equation lowerBound, Equation upperBound, 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 // 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. - 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 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; } } diff --git a/Nerd_STF/Mathematics/Equation2d.cs b/Nerd_STF/Mathematics/Equation2d.cs new file mode 100644 index 0000000..da6c876 --- /dev/null +++ b/Nerd_STF/Mathematics/Equation2d.cs @@ -0,0 +1,3 @@ +namespace Nerd_STF.Mathematics; + +public delegate Complex Equation2d(Complex input); diff --git a/Nerd_STF/Mathematics/Float2.cs b/Nerd_STF/Mathematics/Float2.cs index 1de768d..460b3de 100644 --- a/Nerd_STF/Mathematics/Float2.cs +++ b/Nerd_STF/Mathematics/Float2.cs @@ -5,7 +5,7 @@ public record struct Float2 : IAbsolute, IAverage, ICeiling, IDivide, IDot, IEquatable, IFloor, IFromTuple, IGroup, ILerp, IMathOperators, IMax, IMedian, IMin, - IIndexAll, IIndexRangeAll, IPresets2D, IProduct, IRound, + IIndexAll, IIndexRangeAll, IPresets2d, IProduct, IRound, ISplittable, ISubtract, ISum { public static Float2 Down => new(0, -1); @@ -162,8 +162,6 @@ public record struct Float2 : IAbsolute, IAverage, ICeiling Magnitude.CompareTo(other.Magnitude); public bool Equals(Float2 other) => x == other.x && y == other.y; public override int GetHashCode() => base.GetHashCode(); @@ -204,18 +202,6 @@ public record struct Float2 : IAbsolute, IAverage, ICeiling 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, 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 explicit operator Float2(Quaternion val) => new(val.u, val.i); diff --git a/Nerd_STF/Mathematics/Float3.cs b/Nerd_STF/Mathematics/Float3.cs index 7674707..c31186c 100644 --- a/Nerd_STF/Mathematics/Float3.cs +++ b/Nerd_STF/Mathematics/Float3.cs @@ -7,7 +7,7 @@ public record struct Float3 : IAbsolute, IAverage, ICross, IDivide, IDot, IEquatable, IFloor, IFromTuple, IGroup, IIndexAll, IIndexRangeAll, ILerp, IMathOperators, IMax, - IMedian, IMin, IPresets3D, IProduct, IRound, + IMedian, IMin, IPresets3d, IProduct, IRound, ISplittable, ISubtract, ISum { public static Float3 Back => new(0, 0, -1); @@ -186,8 +186,6 @@ public record struct Float3 : IAbsolute, IAverage, 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 bool Equals(Float3 other) => x == other.x && y == other.y && z == other.z; public override int GetHashCode() => base.GetHashCode(); @@ -238,18 +236,6 @@ public record struct Float3 : IAbsolute, IAverage, 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, 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 explicit operator Float3(Quaternion val) => new(val.u, val.i, val.j); diff --git a/Nerd_STF/Mathematics/Float4.cs b/Nerd_STF/Mathematics/Float4.cs index b8af96c..2c0a0ae 100644 --- a/Nerd_STF/Mathematics/Float4.cs +++ b/Nerd_STF/Mathematics/Float4.cs @@ -5,22 +5,16 @@ public record struct Float4 : IAbsolute, IComparable, IDivide, IDot, IEquatable, IFloor, IFromTuple, IGroup, IIndexAll, IIndexRangeAll, ILerp, IMathOperators, - IMax, IMedian, IMin, IPresets4D, IProduct, IRound, + IMax, IMedian, IMin, IPresets4d, IProduct, IRound, ISplittable, ISubtract, ISum { public static Float4 Back => new(0, 0, -1, 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 HighW => new(0, 0, 0, 1); public static Float4 Left => new(-1, 0, 0, 0); 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 Up => new(0, 1, 0, 0); @@ -207,8 +201,6 @@ public record struct Float4 : IAbsolute, 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 bool Equals(Float4 other) => x == other.x && y == other.y && z == other.z && w == other.w; public override int GetHashCode() => base.GetHashCode(); @@ -252,18 +244,6 @@ public record struct Float4 : IAbsolute, 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, 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(Quaternion val) => new(val.u, val.i, val.j, val.k); diff --git a/Nerd_STF/Mathematics/Geometry/Box2D.cs b/Nerd_STF/Mathematics/Geometry/Box2D.cs index 68d18ac..e2c02c4 100644 --- a/Nerd_STF/Mathematics/Geometry/Box2D.cs +++ b/Nerd_STF/Mathematics/Geometry/Box2D.cs @@ -1,7 +1,7 @@ namespace Nerd_STF.Mathematics.Geometry; public record class Box2D : IAbsolute, IAverage, ICeiling, IClamp, IContains, - IEquatable, IFloor, ILerp, IMedian, IRound, IShape2D, + IEquatable, IFloor, ILerp, IMedian, IRound, IShape2d, ISplittable { public static Box2D Unit => new(Vert.Zero, Float2.One); diff --git a/Nerd_STF/Mathematics/Geometry/Box3D.cs b/Nerd_STF/Mathematics/Geometry/Box3D.cs index aa4cedb..77a0559 100644 --- a/Nerd_STF/Mathematics/Geometry/Box3D.cs +++ b/Nerd_STF/Mathematics/Geometry/Box3D.cs @@ -2,7 +2,7 @@ public record class Box3D : IAbsolute, IAverage, ICeiling, IClamp, IContains, IEquatable, IFloor, ILerp, IMedian, - IRound, IShape3D, ISplittable + IRound, IShape3d, ISplittable { public static Box3D Unit => new(Vert.Zero, Float3.One); diff --git a/Nerd_STF/Mathematics/Geometry/Line.cs b/Nerd_STF/Mathematics/Geometry/Line.cs index 9fb1fe2..98c0b33 100644 --- a/Nerd_STF/Mathematics/Geometry/Line.cs +++ b/Nerd_STF/Mathematics/Geometry/Line.cs @@ -4,7 +4,7 @@ namespace Nerd_STF.Mathematics.Geometry; public record class Line : IAbsolute, IAverage, ICeiling, IClamp, IClosestTo, IComparable, IContains, IEquatable, IFloor, IFromTuple, - IGroup, IIndexAll, IIndexRangeAll, ILerp, IMedian, IPresets3D, + IGroup, IIndexAll, IIndexRangeAll, ILerp, IMedian, IPresets3d, IRound, ISplittable, ISubdivide { public static Line Back => new(Vert.Zero, Vert.Back); diff --git a/Nerd_STF/Mathematics/Geometry/Quadrilateral.cs b/Nerd_STF/Mathematics/Geometry/Quadrilateral.cs index e5e62fa..2f006fa 100644 --- a/Nerd_STF/Mathematics/Geometry/Quadrilateral.cs +++ b/Nerd_STF/Mathematics/Geometry/Quadrilateral.cs @@ -3,7 +3,7 @@ public record class Quadrilateral : IAbsolute, IAverage, ICeiling, IClamp, IEquatable, IFloor, IFromTuple, IGroup, IIndexAll, IIndexRangeAll, - ILerp, IRound, IShape2D, ITriangulate + ILerp, IRound, IShape2d, ITriangulate { public Vert A { diff --git a/Nerd_STF/Mathematics/Geometry/Triangle.cs b/Nerd_STF/Mathematics/Geometry/Triangle.cs index 415c75e..105f853 100644 --- a/Nerd_STF/Mathematics/Geometry/Triangle.cs +++ b/Nerd_STF/Mathematics/Geometry/Triangle.cs @@ -4,7 +4,7 @@ namespace Nerd_STF.Mathematics.Geometry; public record class Triangle : IAbsolute, IAverage, ICeiling, IClamp, IEquatable, IFloor, IFromTuple, IGroup, - IIndexAll, IIndexRangeAll, ILerp, IRound, IShape2D + IIndexAll, IIndexRangeAll, ILerp, IRound, IShape2d { public Vert A { diff --git a/Nerd_STF/Mathematics/Int2.cs b/Nerd_STF/Mathematics/Int2.cs index 55482ae..04aaff0 100644 --- a/Nerd_STF/Mathematics/Int2.cs +++ b/Nerd_STF/Mathematics/Int2.cs @@ -3,7 +3,7 @@ public record struct Int2 : IAbsolute, IAverage, IClamp, IClampMagnitude, IComparable, ICross, IDivide, IDot, IEquatable, IFromTuple, IGroup, IIndexAll, IIndexRangeAll, ILerp, - IMathOperators, IMax, IMedian, IMin, IPresets2D, IProduct, + IMathOperators, IMax, IMedian, IMin, IPresets2d, IProduct, ISplittable, ISubtract, ISum { public static Int2 Down => new(0, -1); @@ -154,8 +154,6 @@ public record struct Int2 : IAbsolute, IAverage, IClamp, IClam 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 bool Equals(Int2 other) => x == other.x && y == other.y; public override int GetHashCode() => base.GetHashCode(); @@ -198,18 +196,6 @@ public record struct Int2 : IAbsolute, IAverage, IClamp, 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); - [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(Quaternion val) => new((int)val.u, (int)val.i); diff --git a/Nerd_STF/Mathematics/Int3.cs b/Nerd_STF/Mathematics/Int3.cs index 2b3c881..22385a7 100644 --- a/Nerd_STF/Mathematics/Int3.cs +++ b/Nerd_STF/Mathematics/Int3.cs @@ -5,7 +5,7 @@ namespace Nerd_STF.Mathematics; public record struct Int3 : IAbsolute, IAverage, IClamp, IClampMagnitude, IComparable, ICross, IDivide, IDot, IEquatable, IFromTuple, IGroup, IIndexAll, IIndexRangeAll, ILerp, - IMathOperators, IMax, IMedian, IMin, IPresets3D, IProduct, + IMathOperators, IMax, IMedian, IMin, IPresets3d, IProduct, ISplittable, ISubtract, ISum { public static Int3 Back => new(0, 0, -1); @@ -177,8 +177,6 @@ public record struct Int3 : IAbsolute, IAverage, IClamp, IClam 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 bool Equals(Int3 other) => x == other.x && y == other.y && z == other.z; public override int GetHashCode() => base.GetHashCode(); @@ -224,18 +222,6 @@ public record struct Int3 : IAbsolute, IAverage, IClamp, 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); - [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(Quaternion val) => new((int)val.u, (int)val.i, (int)val.j); diff --git a/Nerd_STF/Mathematics/Int4.cs b/Nerd_STF/Mathematics/Int4.cs index 9598d29..f125c86 100644 --- a/Nerd_STF/Mathematics/Int4.cs +++ b/Nerd_STF/Mathematics/Int4.cs @@ -3,17 +3,11 @@ public record struct Int4 : IAbsolute, IAverage, IClamp, IClampMagnitude, IComparable, IDivide, IDot, IEquatable, IFromTuple, IGroup, IIndexAll, IIndexRangeAll, - ILerp, IMathOperators, IMax, IMedian, IMin, IPresets4D, + ILerp, IMathOperators, IMax, IMedian, IMin, IPresets4d, IProduct, ISplittable, ISubtract, ISum { 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); - [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 HighW => new(0, 0, 0, 1); public static Int4 Left => new(-1, 0, 0, 0); @@ -196,8 +190,6 @@ public record struct Int4 : IAbsolute, IAverage, IClamp, IClam 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 bool Equals(Int4 other) => x == other.x && y == other.y && z == other.z && w == other.w; public override int GetHashCode() => base.GetHashCode(); @@ -244,18 +236,6 @@ public record struct Int4 : IAbsolute, IAverage, IClamp, 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); - [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(Quaternion val) => new((int)val.u, (int)val.i, (int)val.j, (int)val.k); diff --git a/Nerd_STF/Mathematics/Mathf.cs b/Nerd_STF/Mathematics/Mathf.cs index 788638c..113c528 100644 --- a/Nerd_STF/Mathematics/Mathf.cs +++ b/Nerd_STF/Mathematics/Mathf.cs @@ -19,19 +19,28 @@ public static class Mathf } 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 ArcCsc(float value) => ArcSin(1 / value); - public static Angle ArcSec(float value) => ArcCos(1 / 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); - + public static Angle ArcSin(float value) + { + 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 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) { List vals = new(); @@ -44,6 +53,8 @@ public static class Mathf public static float Binomial(int n, int total, float successRate) => 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) { 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(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(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(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 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 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 float Lerp(float a, float b, float t, bool clamp = true) @@ -144,6 +174,19 @@ public static class Mathf return v; } 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 vals) => delegate (float x) { @@ -280,6 +323,20 @@ public static class Mathf // nPr (n = total, r = size) public static int Permutations(int total, int size) => Factorial(total) / Factorial(total - size); + public static int[] PrimeFactors(int num) + { + List 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) { if (vals.Length < 1) return 0; @@ -301,7 +358,12 @@ public static class Mathf 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) { if (pow <= 0) return 0; @@ -329,6 +391,14 @@ public static class Mathf for (int i = 0; i < pow; i++) val = val * num % mod; 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); @@ -339,6 +409,18 @@ public static class Mathf public static float Sec(Angle angle) => Sec(angle.Radians); public static float Sec(float radians) => 1 / Cos(radians); + public static float Sech(float value) => 1 / Cosh(value); + + public static T[] SharedItems(params T[][] arrays) where T : IEquatable + { + if (arrays.Length < 1) return Array.Empty(); + + IEnumerable 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(float radians) { @@ -361,7 +443,77 @@ public static class Mathf + (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 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(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(params T[] vals) where T : IEquatable { List unique = new(); diff --git a/Nerd_STF/Mathematics/NumberSystems/Complex.cs b/Nerd_STF/Mathematics/NumberSystems/Complex.cs index 85db4ae..6727473 100644 --- a/Nerd_STF/Mathematics/NumberSystems/Complex.cs +++ b/Nerd_STF/Mathematics/NumberSystems/Complex.cs @@ -3,7 +3,7 @@ public record struct Complex(float u, float i) : IAbsolute, IAverage, ICeiling, IClampMagnitude, IComparable, IDivide, IDot, IEquatable, IFloor, IGroup, IIndexAll, IIndexRangeAll, - ILerp, IMax, IMedian, IMin, IPresets2D, IProduct, + ILerp, IMax, IMedian, IMin, IPresets2d, IProduct, IRound, ISplittable, ISum { public static Complex Down => new(0, -1); @@ -190,18 +190,6 @@ public record struct Complex(float u, float i) : IAbsolute, IAverage new(a.u / b, a.i / b); public static Complex operator /(Complex a, Matrix b) => (Complex)((Matrix)a / b); 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 implicit operator Complex(Float2 val) => new(val.x, val.y); diff --git a/Nerd_STF/Mathematics/NumberSystems/Quaternion.cs b/Nerd_STF/Mathematics/NumberSystems/Quaternion.cs index ea74f48..9dd6991 100644 --- a/Nerd_STF/Mathematics/NumberSystems/Quaternion.cs +++ b/Nerd_STF/Mathematics/NumberSystems/Quaternion.cs @@ -4,21 +4,15 @@ public record struct Quaternion(float u, float i, float j, float k) : IAbsolute< ICeiling, IClamp, IClampMagnitude, IComparable, IDivide, IDot, IEquatable, IFloor, IGroup, IIndexAll, IIndexRangeAll, ILerp, IMax, IMedian, - IMin, IPresets4D, IProduct, IRound, + IMin, IPresets4d, IProduct, IRound, ISplittable, ISum { public static Quaternion Back => new(0, 0, -1, 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 HighW => new(0, 0, 0, 1); public static Quaternion Left => new(-1, 0, 0, 0); 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 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, Float3 b) => a / new Quaternion(b); 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(Int2 val) => new(val); diff --git a/Nerd_STF/Mathematics/PrimeCheckMethod.cs b/Nerd_STF/Mathematics/PrimeCheckMethod.cs new file mode 100644 index 0000000..f24c0e3 --- /dev/null +++ b/Nerd_STF/Mathematics/PrimeCheckMethod.cs @@ -0,0 +1,7 @@ +namespace Nerd_STF.Mathematics; + +public enum PrimeCheckMethod +{ + Classic, + MillerRabin +} diff --git a/Nerd_STF/Mathematics/Rational.cs b/Nerd_STF/Mathematics/Rational.cs new file mode 100644 index 0000000..a7410c6 --- /dev/null +++ b/Nerd_STF/Mathematics/Rational.cs @@ -0,0 +1,177 @@ +namespace Nerd_STF.Mathematics; + +public readonly record struct Rational : IAbsolute, IAverage, ICeiling, IClamp, + IComparable, IComparable, IDivide, IEquatable, IEquatable, + IFloor, IIndexGet, IIndexRangeGet, ILerp, IMathOperators, + IMax, IMedian, IMin, IPresets1d, IProduct, + IRound, ISplittable, ISubtract, + ISum +{ + 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 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 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); +} diff --git a/Nerd_STF/Mathematics/Samples/Equations.cs b/Nerd_STF/Mathematics/Samples/Equations.cs index 033622d..b83ad54 100644 --- a/Nerd_STF/Mathematics/Samples/Equations.cs +++ b/Nerd_STF/Mathematics/Samples/Equations.cs @@ -2,10 +2,11 @@ public static class Equations { - public static readonly Fill 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 readonly Equation SinWave = x => Mathf.Sin(x); - public static readonly Equation SawWave = x => x % 1; - public static readonly Equation SquareWave = x => x % 2 < 1 ? 1 : 0; + public static Equation FlatLine => x => 0; + public static Equation XLine => x => x; } diff --git a/Nerd_STF/Mathematics/Samples/Fills.cs b/Nerd_STF/Mathematics/Samples/Fills.cs new file mode 100644 index 0000000..c0c0f70 --- /dev/null +++ b/Nerd_STF/Mathematics/Samples/Fills.cs @@ -0,0 +1,6 @@ +namespace Nerd_STF.Mathematics.Samples; + +public static class Fills +{ + public static Fill SignFill => i => i % 2 == 0 ? 1 : -1; +} diff --git a/Nerd_STF/Mathematics/SimplificationMethod.cs b/Nerd_STF/Mathematics/SimplificationMethod.cs new file mode 100644 index 0000000..5824b0b --- /dev/null +++ b/Nerd_STF/Mathematics/SimplificationMethod.cs @@ -0,0 +1,7 @@ +namespace Nerd_STF.Mathematics; + +public enum SimplificationMethod +{ + AutoSimplify, + FareySequence +} diff --git a/Nerd_STF/Miscellaneous/AssemblyInfo.cs b/Nerd_STF/Miscellaneous/AssemblyInfo.cs index a3721d3..49667c0 100644 --- a/Nerd_STF/Miscellaneous/AssemblyInfo.cs +++ b/Nerd_STF/Miscellaneous/AssemblyInfo.cs @@ -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. diff --git a/Nerd_STF/Miscellaneous/GlobalUsings.cs b/Nerd_STF/Miscellaneous/GlobalUsings.cs index f5408f2..d78b7b5 100644 --- a/Nerd_STF/Miscellaneous/GlobalUsings.cs +++ b/Nerd_STF/Miscellaneous/GlobalUsings.cs @@ -3,6 +3,7 @@ global using Nerd_STF.Graphics; global using Nerd_STF.Graphics.Abstract; global using Nerd_STF.Exceptions; global using Nerd_STF.Extensions; +global using Nerd_STF.Helpers; global using Nerd_STF.Mathematics; global using Nerd_STF.Mathematics.Abstract; global using Nerd_STF.Mathematics.Algebra; @@ -16,6 +17,7 @@ global using System.Diagnostics.CodeAnalysis; global using System.IO; global using System.Linq; global using System.Net.Http; +global using System.Reflection; global using System.Runtime.Serialization; global using System.Text; global using System.Threading; diff --git a/Nerd_STF/Modifier2D.cs b/Nerd_STF/Modifier2D.cs index ddac9b9..9ac456e 100644 --- a/Nerd_STF/Modifier2D.cs +++ b/Nerd_STF/Modifier2D.cs @@ -1,5 +1,5 @@ namespace Nerd_STF; -public delegate float Modifier2D(Int2 index, float value); -public delegate T Modifier2D(Int2 index, T value); -public delegate VT Modifier2D(IT x, IT y, VT value); +public delegate float Modifier2d(Int2 index, float value); +public delegate T Modifier2d(Int2 index, T value); +public delegate VT Modifier2d(IT x, IT y, VT value); diff --git a/Nerd_STF/NDArray.cs b/Nerd_STF/NDArray.cs new file mode 100644 index 0000000..56c799f --- /dev/null +++ b/Nerd_STF/NDArray.cs @@ -0,0 +1,113 @@ +namespace Nerd_STF; + +public class NDArray : IEnumerable, IEquatable> +{ + 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(); + dimensions = 0; + sizes = Array.Empty(); + } + public NDArray(int dimensions) + { + arr = Array.Empty(); + 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 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 arr) return Equals(arr); + return false; + } + public bool Equals(NDArray? obj) => obj is not null && arr.Equals(obj.arr); + public override int GetHashCode() => base.GetHashCode(); + + public static bool operator ==(NDArray a, NDArray b) => a.Equals(b); + public static bool operator !=(NDArray a, NDArray b) => !a.Equals(b); +} diff --git a/Nerd_STF/Nerd_STF.cs b/Nerd_STF/Nerd_STF.cs index 559b45b..dfb78f5 100644 --- a/Nerd_STF/Nerd_STF.cs +++ b/Nerd_STF/Nerd_STF.cs @@ -17,5 +17,5 @@ public static class Nerd_STF { "nuget", "https://www.nuget.org/packages/Nerd_STF/" } }; public const string MainDeveloper = "That_One_Nerd"; - public const string Version = "2.3.2"; + public const string Version = "2.4.0"; } diff --git a/Nerd_STF/Nerd_STF.csproj b/Nerd_STF/Nerd_STF.csproj index fcbba69..ee59f67 100644 --- a/Nerd_STF/Nerd_STF.csproj +++ b/Nerd_STF/Nerd_STF.csproj @@ -8,28 +8,39 @@ Nerd_STF True That_One_Nerd - Nerd_STF is a general-purpose .NET library. - Copyright (c) 2022 That_One_Nerd + Nerd_STF is a general-purpose .NET library for .NET 7.0. + Copyright (c) 2023 That_One_Nerd README.md https://github.com/That-One-Nerd/Nerd_STF - 2.3.2 + 2.4.0 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 - 2.3.2 + 2.4.0 Nerd_STF Nerd_STF MIT Logo Square.png - A bunch of stuff has changed, hasn't it? + 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! +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! https://github.com/That-One-Nerd/Nerd_STF False False @@ -40,6 +51,7 @@ Anyway, that's it for this update. The longest delay was just getting this proje False C:\Users\kyley\Desktop\Misc Items\Private Keys\SNA\Nerd_STF.snk False + true @@ -51,7 +63,7 @@ Anyway, that's it for this update. The longest delay was just getting this proje True 9999 - True + False