Beta2 completed.

This commit is contained in:
That-One-Nerd 2024-11-25 10:20:20 -05:00
parent 10e70a3574
commit e59f253cc8
2 changed files with 72 additions and 166 deletions

View File

@ -1,108 +1,61 @@
# Nerd_STF v3.0-beta1
# Nerd_STF v3.0-beta2
Hi! Pretty much nothing has remained the same from version 2. There are plenty of breaking changes, and the betas will have plenty of missing features from 2.4.1. The betas will continue until every feature from 2.4.1 has been added to 3.0 or scrapped.
I've added a substantial number of things in this update, mostly matrix related.
In the mean time, here's what's new.
## List Tuples
## More Compatibility
Nerd_STF now targets several versions of .NET and .NET Standard, making it basically run anywhere. You can use [this website](https://dotnet.microsoft.com/en-us/platform/dotnet-standard#versions) to see what different versions of .NET Standard support, but if your project uses a version of .NET that was released in the last 10 years, chances are Nerd_STF supports it.
In addition, Nerd_STF uses some of the new C# features while still retaining older compatibility. If you want to use Nerd_STF in your .NET 8.0 project, you will reference the version of Nerd_STF compiled for .NET 7.0 and retain those fancy new interface features (among others) found in C# 11. Nullability support has been added to all versions of .NET that use C# 8 and above. And if I decide to use more new C# features for Nerd_STF, I'll just target another version of .NET.
## Committed to Doubles
Nerd_STF is a precision library, not one meant to be highly optimized at the sacrifice of precision. So I've decided to fully commit to doubles. The double groups are still called `Float2`, `Float3` and `Float4`, because `Double2` doesn't have quite the same ring to it now, does it? Hope it doesn't get too confusing.
But all math functions are now using doubles (with a few exceptions).
## 'w' Goes in Front Now
I think this is how it should have been. I was really breaking the rules of the alphabet before. Previously in a `Float4`, the `w` component was fourth. Now it is first. The order goes w, x, y, z. You know, how it should.
This means though that casting a `Float3` to a `Float4` will put the extra zero at the start, not the end (because `x` -> `x` in the cast).
```csharp
Float3 xyz = (5, 6, 7);
Float4 wxyz = xyz; // Gives (0, 5, 6, 7)
```
This also means that truncating a `Float4` removes the front `w` first, giving some odd results.
```csharp
Float2 xy = (10, 9);
Float4 wxyz = xy; // Gives (0, 10, 9, 0)
```
```csharp
Float4 wxyz = (9, 8, 7, 6);
Float2 xy = (Float2)wxyz; // Must be explicitly stated. Yields (8, 7)
```
But `x` always goes to `x` when casting between groups, same with the other variables. Hopefully that'll make more sense.
## Combination Indexers
One thing I've always been envious of was HLSL's ability to easily make a subset of a group.
```c++
float3 group = float3(1, 2, 3);
float2 part = group.yz; // Like this.
```
And I had a crude version of this in Nerd_STF before, with properties for `XY`, `YZW`, and stuff like that. But you couldn't do things out of order (for example, you could never do `.ZY`). Also, the naming scheme would not make very much sense. `x` was always the first item Now, you can do it with an indexer.
In the previous beta, I introduced **Combination Indexers** for the double and int groups, however a problem was that they only returned `IEnumerable`s. So while some interesting things were supported, some things were not.
```csharp
Float4 wxyz = (1, 2, 3, 4);
IEnumerable<double> zyx = wxyz["zyx"]; // Yields [ 4, 3, 2 ]
IEnumerable<double> vals1 = wxyz["xy"]; // Yields [2, 3]
Float2 vals2 = wxyz["xy"]; // Not allowed!
```
I think you get it, it makes sense. It returns an IEnumerable though, so support has been added in the group constructors to read data from an IEnumerable. You can also set things this way.
And that kind of sucked. So I created the `ListTuple<T>` type. It's job is to act like a regular tuple, but be able to impliclty convert to either an `IEnumerable` or a regular `ValueTuple<T>`, thus allowing conversions to the double and int groups indirectly. Now, all combination indexers return a `ListTuple` instead of an `IEnumerable`.
Under the hood, the `ListTuple` actually uses an array, but you get the idea.
```csharp
Float4 wxyz = (1, 2, 3, 4);
wxyz["xy"] = [ 9, 8 ]; // Yields (9, 8, 3, 4)
ListTuple<double> vals1 = wxyz["xy"]; // Yields (2, 3)
Float2 vals2 = vals1; // Yields (2, 3)
IEnumerable<double> vals3 = vals1; // Yields [2, 3]
```
You can also have duplicates. Why you would want duplicates is beyond me. And the order can be whatever you'd like.
Problem is, now the names have the potential to make much less sense.
```csharp
Float4 wxyz = (1, 2, 3, 4);
IEnumerable<double> nums = wxyz["wyyxzzwy"]; // Yields [ 1, 3, 3, 2, 4, 4, 1, 3 ]
Float2 xy = wxyz["xy"]; // x <- x, y <- y
Float2 wz = wxyz["wz"]; // x <- w, y <- z
```
## Better Equations
But whatever. You can always stick to using `IEnumerable`s if you want.
The previous equation system was just a delegate to a method. While it worked for unoptimized things, it won't automatically give precise results. So that system has been overhauled.
## No More `*.Abstract`
Now, every equation derives from the `IEquation` interface, which defines a few operators (most importantly the `Get(double)` method, which is intended to evaluate the equation at the given input). And there are multiple types. There's the base `Equation` type that replicates the method delegate it used to be, but there are also now `Polynomial` equations which specialize in... uh... polynomials, including `Quadratic` and `Linear` along with the dynamic `Polynomial` type.
I got rid of all the `Abstract` namespaces, since they don't really make much sense in the grand scheme of things. They've all been moved to the namespace that applies to them most (eg. `INumberGroup` went to `Nerd_STF.Mathematics`, `ICombinationIndexer` went to `Nerd_STF` since it applies to more than just mathematics).
The indexer is equivalent to calling the `Get(double)` method.
## The `Fraction` Type
Creating your own is easy, simply derive from the interface and implement the methods required. You should never throw an exception if the two equations you are adding (or multiplying or whatever) are not the same type. If they cannot be combined in a nice way, you should default to the delegate-based approach. Here is an example:
```csharp
public IEquation Add(IEquation other) {
if (other is YourEquation yourEqu) {
// Properly add your two equations.
} else {
// Unknown other equation type, do a basic addition system.
return new Equation(x => Get(x) + other.Get(x));
}
}
```
This type originally went under the name of `Rational` in Nerd_STF 2.x, but that name is actually incorrect, right? So in the rework, it changed names. But it also can do much more now thanks to the `INumber` interface added in .NET 7.0. If you're using that framework or above, the fraction type is fully compatible with that type, and all the math functions in `MathE` and elsewhere that use `INumber` will work with it.
And in practice, you should avoid referring to a general equation by its type. Go by the interface operators instead.
```csharp
double Fun(double x) => 0.5 * MathE.Sin(x);
Equation a = (Equation)Fun; // The traditional delegate approach from previous versions.
Polynomial b = new Polynomial(1, 5, 4); // x^2 + 5x + 4
IEquation c = a.Add(b).Multiply(2); // Result is technically an `Equation`, but we should not cast here.
```
## Renamed the `Mathf` class.
I chose that name because I thought Unity did it well, but I also intend for this project to be compatible with Unity. So I've renamed it to `MathE`. I'm still iffy on that name. I'll commit to one before this project goes out of beta, but it might change until then. Other ideas I'm considering are `Mathe` and `Math2`. Feel free to give your input!
## Support for `System.Drawing` types.
I've tried to use this library when working with Windows Forms a few times. Problem is, it sucks having to manually set the variables from `Point` and `Size`. So Nerd_STF 3.0 now does that for you, with implicit casts to and from both, along with their float variations.
**It's worth mentioning that `Float2` is a double group, while `PointF` is a float group. Data *will* be lost slightly when implicitly casting. Watch out!**
Can I just say that the `INumber` interface is really annoying to write a type for? There's so many weird casting functions and a whole lot of methods that even the .NET developers will hide in public declarations. Why have them at all?
---
Anyway, that's most of the big changes! I don't know if I'll do the full changelog like I have before. It takes a really long time to compile for large updates. We'll see. Thanks for checking out the update and I hope you use it well (or wait for the release version, that's fine too)!
And I want to change the name of the `MathE` class. I'm thinking `Math2`, but I'm open to suggestions.
## And Best of All, Matrices
Oh yeah, we're adding those things again. I haven't completed (or even started) the dynamic `Matrix` class, that will arrive in beta3. But I have the `Matrix2x2`, `Matrix3x3`, and `Matrix4x4` fully implemented. The `ToString()` methods are much better with the new implementation than previously, and the `GetHashCode()` methods give different results even if the numbers have their positions swapped (which they originally didn't do).
And it's much faster. Much, much faster. Don't get me wrong, multiplying a 4x4 matrix still requires 64 multiplications and 48 additions, which is quite a lot, but my original implementation was littered with many method calls, easily doubling the runtime. I have now super-inlined basically all of the static matrix code. And I mean, replacing all method calls with nothing but multiplication and addition for things like the determinants, the cofactors, the inverses, and more. Don't look at the source, it's really ugly.
---
That's all the major stuff in this update! I'll see you guys in beta3!
P.S. I know that the System library also includes `Vector2`, `Vector3`, and `Vector4` types. I'll add casting support for them soon.

View File

@ -28,114 +28,67 @@
<PackageTags>c#;csharp;c sharp;math;mathematics;mathametics;maths;color;rgb;rgba;cmyk;cmyka;hsv;hsva;calculus;linear algebra;linalg;linearalgebra;matrix;matrix2x2;matrix 2x2;matrix3x3;matrix 3x3;matrix4x4;matrix 4x4;matrix multiplication;vector;vector2d;vector3d;vector2;vector3;float2;float3;float4;int2;int3;int4;angle;geometry;vert;line;polygon;triangle;quadrilateral;sphere;circle;number system;numbersystem;complex numbers;complex;2d numbers;2dnumbers;quaternions;4d numbers;4dnumbers;equation;equations;polynomial;quadratic;linear equation</PackageTags>
<!-- Sorry this is stupidly long, wish I could have linked a markdown file instead. -->
<PackageReleaseNotes># Nerd_STF v3.0-beta1
<PackageReleaseNotes># Nerd_STF v3.0-beta2
Hi! Pretty much nothing has remained the same from version 2. There are plenty of breaking changes, and the betas will have plenty of missing features from 2.4.1. The betas will continue until every feature from 2.4.1 has been added to 3.0 or scrapped.
I've added a substantial number of things in this update, mostly matrix related.
In the mean time, here's what's new.
## List Tuples
## More Compatibility
Nerd_STF now targets several versions of .NET and .NET Standard, making it basically run anywhere. You can use [this website](https://dotnet.microsoft.com/en-us/platform/dotnet-standard#versions) to see what different versions of .NET Standard support, but if your project uses a version of .NET that was released in the last 10 years, chances are Nerd_STF supports it.
In addition, Nerd_STF uses some of the new C# features while still retaining older compatibility. If you want to use Nerd_STF in your .NET 8.0 project, you will reference the version of Nerd_STF compiled for .NET 7.0 and retain those fancy new interface features (among others) found in C# 11. Nullability support has been added to all versions of .NET that use C# 8 and above. And if I decide to use more new C# features for Nerd_STF, I'll just target another version of .NET.
## Committed to Doubles
Nerd_STF is a precision library, not one meant to be highly optimized at the sacrifice of precision. So I've decided to fully commit to doubles. The double groups are still called `Float2`, `Float3` and `Float4`, because `Double2` doesn't have quite the same ring to it now, does it? Hope it doesn't get too confusing.
But all math functions are now using doubles (with a few exceptions).
## 'w' Goes in Front Now
I think this is how it should have been. I was really breaking the rules of the alphabet before. Previously in a `Float4`, the `w` component was fourth. Now it is first. The order goes w, x, y, z. You know, how it should.
This means though that casting a `Float3` to a `Float4` will put the extra zero at the start, not the end (because `x` -&gt; `x` in the cast).
```csharp
Float3 xyz = (5, 6, 7);
Float4 wxyz = xyz; // Gives (0, 5, 6, 7)
```
This also means that truncating a `Float4` removes the front `w` first, giving some odd results.
```csharp
Float2 xy = (10, 9);
Float4 wxyz = xy; // Gives (0, 10, 9, 0)
```
```csharp
Float4 wxyz = (9, 8, 7, 6);
Float2 xy = (Float2)wxyz; // Must be explicitly stated. Yields (8, 7)
```
But `x` always goes to `x` when casting between groups, same with the other variables. Hopefully that'll make more sense.
## Combination Indexers
One thing I've always been envious of was HLSL's ability to easily make a subset of a group.
```c++
float3 group = float3(1, 2, 3);
float2 part = group.yz; // Like this.
```
And I had a crude version of this in Nerd_STF before, with properties for `XY`, `YZW`, and stuff like that. But you couldn't do things out of order (for example, you could never do `.ZY`). Also, the naming scheme would not make very much sense. `x` was always the first item Now, you can do it with an indexer.
In the previous beta, I introduced **Combination Indexers** for the double and int groups, however a problem was that they only returned `IEnumerable`s. So while some interesting things were supported, some things were not.
```csharp
Float4 wxyz = (1, 2, 3, 4);
IEnumerable&lt;double&gt; zyx = wxyz["zyx"]; // Yields [ 4, 3, 2 ]
IEnumerable&lt;double&gt; vals1 = wxyz["xy"]; // Yields [2, 3]
Float2 vals2 = wxyz["xy"]; // Not allowed!
```
I think you get it, it makes sense. It returns an IEnumerable though, so support has been added in the group constructors to read data from an IEnumerable. You can also set things this way.
And that kind of sucked. So I created the `ListTuple&lt;T&gt;` type. It's job is to act like a regular tuple, but be able to impliclty convert to either an `IEnumerable` or a regular `ValueTuple&lt;T&gt;`, thus allowing conversions to the double and int groups indirectly. Now, all combination indexers return a `ListTuple` instead of an `IEnumerable`.
Under the hood, the `ListTuple` actually uses an array, but you get the idea.
```csharp
Float4 wxyz = (1, 2, 3, 4);
wxyz["xy"] = [ 9, 8 ]; // Yields (9, 8, 3, 4)
ListTuple&lt;double&gt; vals1 = wxyz["xy"]; // Yields (2, 3)
Float2 vals2 = vals1; // Yields (2, 3)
IEnumerable&lt;double&gt; vals3 = vals1; // Yields [2, 3]
```
You can also have duplicates. Why you would want duplicates is beyond me. And the order can be whatever you'd like.
Problem is, now the names have the potential to make much less sense.
```csharp
Float4 wxyz = (1, 2, 3, 4);
IEnumerable&lt;double&gt; nums = wxyz["wyyxzzwy"]; // Yields [ 1, 3, 3, 2, 4, 4, 1, 3 ]
Float2 xy = wxyz["xy"]; // x &lt;- x, y &lt;- y
Float2 wz = wxyz["wz"]; // x &lt;- w, y &lt;- z
```
## Better Equations
But whatever. You can always stick to using `IEnumerable`s if you want.
The previous equation system was just a delegate to a method. While it worked for unoptimized things, it won't automatically give precise results. So that system has been overhauled.
## No More `*.Abstract`
Now, every equation derives from the `IEquation` interface, which defines a few operators (most importantly the `Get(double)` method, which is intended to evaluate the equation at the given input). And there are multiple types. There's the base `Equation` type that replicates the method delegate it used to be, but there are also now `Polynomial` equations which specialize in... uh... polynomials, including `Quadratic` and `Linear` along with the dynamic `Polynomial` type.
I got rid of all the `Abstract` namespaces, since they don't really make much sense in the grand scheme of things. They've all been moved to the namespace that applies to them most (eg. `INumberGroup` went to `Nerd_STF.Mathematics`, `ICombinationIndexer` went to `Nerd_STF` since it applies to more than just mathematics).
The indexer is equivalent to calling the `Get(double)` method.
## The `Fraction` Type
Creating your own is easy, simply derive from the interface and implement the methods required. You should never throw an exception if the two equations you are adding (or multiplying or whatever) are not the same type. If they cannot be combined in a nice way, you should default to the delegate-based approach. Here is an example:
```csharp
public IEquation Add(IEquation other) {
if (other is YourEquation yourEqu) {
// Properly add your two equations.
} else {
// Unknown other equation type, do a basic addition system.
return new Equation(x =&gt; Get(x) + other.Get(x));
}
}
```
This type originally went under the name of `Rational` in Nerd_STF 2.x, but that name is actually incorrect, right? So in the rework, it changed names. But it also can do much more now thanks to the `INumber` interface added in .NET 7.0. If you're using that framework or above, the fraction type is fully compatible with that type, and all the math functions in `MathE` and elsewhere that use `INumber` will work with it.
And in practice, you should avoid referring to a general equation by its type. Go by the interface operators instead.
```csharp
double Fun(double x) =&gt; 0.5 * MathE.Sin(x);
Equation a = (Equation)Fun; // The traditional delegate approach from previous versions.
Polynomial b = new Polynomial(1, 5, 4); // x^2 + 5x + 4
IEquation c = a.Add(b).Multiply(2); // Result is technically an `Equation`, but we should not cast here.
```
## Renamed the `Mathf` class.
I chose that name because I thought Unity did it well, but I also intend for this project to be compatible with Unity. So I've renamed it to `MathE`. I'm still iffy on that name. I'll commit to one before this project goes out of beta, but it might change until then. Other ideas I'm considering are `Mathe` and `Math2`. Feel free to give your input!
## Support for `System.Drawing` types.
I've tried to use this library when working with Windows Forms a few times. Problem is, it sucks having to manually set the variables from `Point` and `Size`. So Nerd_STF 3.0 now does that for you, with implicit casts to and from both, along with their float variations.
**It's worth mentioning that `Float2` is a double group, while `PointF` is a float group. Data *will* be lost slightly when implicitly casting. Watch out!**
Can I just say that the `INumber` interface is really annoying to write a type for? There's so many weird casting functions and a whole lot of methods that even the .NET developers will hide in public declarations. Why have them at all?
---
Anyway, that's most of the big changes! I don't know if I'll do the full changelog like I have before. It takes a really long time to compile for large updates. We'll see. Thanks for checking out the update and I hope you use it well (or wait for the release version, that's fine too)!</PackageReleaseNotes>
And I want to change the name of the `MathE` class. I'm thinking `Math2`, but I'm open to suggestions.
## And Best of All, Matrices
Oh yeah, we're adding those things again. I haven't completed (or even started) the dynamic `Matrix` class, that will arrive in beta3. But I have the `Matrix2x2`, `Matrix3x3`, and `Matrix4x4` fully implemented. The `ToString()` methods are much better with the new implementation than previously, and the `GetHashCode()` methods give different results even if the numbers have their positions swapped (which they originally didn't do).
And it's much faster. Much, much faster. Don't get me wrong, multiplying a 4x4 matrix still requires 64 multiplications and 48 additions, which is quite a lot, but my original implementation was littered with many method calls, easily doubling the runtime. I have now super-inlined basically all of the static matrix code. And I mean, replacing all method calls with nothing but multiplication and addition for things like the determinants, the cofactors, the inverses, and more. Don't look at the source, it's really ugly.
---
That's all the major stuff in this update! I'll see you guys in beta3!
P.S. I know that the System library also includes `Vector2`, `Vector3`, and `Vector4` types. I'll add casting support for them soon.</PackageReleaseNotes>
</PropertyGroup>
<!-- ItemGroup customization based on framework. -->