Enhance mathematical capabilities and job system
Added new numeric types for unsigned integers, including uint2, uint3, and uint4, along with their matrix types. Added a new `quaternion` struct with constructors and methods for creating and manipulating quaternions. Added methods for projecting and reflecting vectors, enhancing geometric operations. Added utility functions for generating orthonormal bases and changing vector signs. Added comprehensive unit tests for new mathematical functions and quaternion operations. Added a high-performance job scheduling system with job management features and worker thread management. Added new structs for job execution, allowing efficient job scheduling and execution. Added utility functions for job execution, including methods for obtaining unique job IDs. Changed access modifiers and property definitions in several files for improved clarity and maintainability. Changed property definitions and method implementations in `ImageInfo.cs`, `ImageResult.cs`, and `ImageResultFloat.cs` for better readability. Changed memory management functions in `CRuntime.cs` and improved memory allocation tracking in `MemoryStats.cs`. Changed the project file to include references to necessary projects and enable unsafe code blocks. Removed the `WorkerThreadPool.cs` file, integrating worker thread management directly into the `JobScheduler`. Removed the `float4` struct and its associated methods and properties, transitioning to a new code generation strategy. Removed the `float4.tt` template and other related files, indicating a shift in code generation approach. Removed the `Vectorize.cs` file, indicating a change in how vector operations are handled. Updated the `.gitignore` file to include IDE-specific settings. Updated various XML files to define project components and structure. Updated the `AllocationManager.cs` to improve memory allocation management and introduce new strategies. Updated the `UnsafeArray.cs`, `UnsafeHashMap.cs`, and `UnsafeList.cs` to enhance performance and safety in unsafe contexts. Updated error handling and function pointer management in `MemoryLeakException.cs` and `FunctionPointer.cs`. Updated the `AssemblyInfo.cs` file to include global using directives for better code organization.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
|
||||
namespace Misaki.HighPerformance.Test;
|
||||
namespace Misaki.HighPerformance.Test.Benchmark;
|
||||
|
||||
[MemoryDiagnoser]
|
||||
public unsafe class CollectionBenchmark
|
||||
@@ -34,7 +34,7 @@ public unsafe class CollectionBenchmark
|
||||
array[i] = i;
|
||||
}
|
||||
|
||||
AllocationManager.TempAllocator.Reset();
|
||||
((ArenaAllocator*)AllocationManager.TempHandle.Allocator)->Reset();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
@@ -3,7 +3,7 @@ using Misaki.HighPerformance.LowLevel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Misaki.HighPerformance.Test;
|
||||
namespace Misaki.HighPerformance.Test.Benchmark;
|
||||
|
||||
[MemoryDiagnoser]
|
||||
public unsafe class FunctionPtrBenchmark
|
||||
@@ -17,7 +17,7 @@ public unsafe class FunctionPtrBenchmark
|
||||
|
||||
public FunctionPtrBenchmark()
|
||||
{
|
||||
_addManaged = new(Marshal.GetFunctionPointerForDelegate<FunctionPointerDelegate>(Add));
|
||||
_addManaged = new(Add);
|
||||
_addUnmanaged = &AddUnmanaged;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public unsafe class FunctionPtrBenchmark
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public void InvokeManaged()
|
||||
{
|
||||
_sink = _addManaged.Invoke(1.0f, 2.0f);
|
||||
_sink = _addManaged.Delegate(1.0f, 2.0f);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
@@ -1,7 +1,7 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Misaki.HighPerformance.Test;
|
||||
namespace Misaki.HighPerformance.Test.Benchmark;
|
||||
|
||||
public class HashCodeBenchmark
|
||||
{
|
||||
@@ -1,7 +1,7 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
|
||||
namespace Misaki.HighPerformance.Test;
|
||||
namespace Misaki.HighPerformance.Test.Benchmark;
|
||||
|
||||
public class HashMapBenchmark
|
||||
{
|
||||
@@ -0,0 +1,37 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Misaki.HighPerformance.Mathematics;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Misaki.HighPerformance.Test.Benchmark;
|
||||
|
||||
public class MathematicsBenchmark
|
||||
{
|
||||
[Params(10, 100)]
|
||||
public int count = 10;
|
||||
|
||||
[Benchmark(Baseline = true)]
|
||||
public void Vector2Add()
|
||||
{
|
||||
var a = new Vector2(1, 2);
|
||||
var b = new Vector2(5, 6);
|
||||
var result = new Vector2();
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
result += a + b;
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void Float2Add()
|
||||
{
|
||||
var a = new float2(1);
|
||||
var b = new float2(5);
|
||||
var result = new float2();
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
result += a + b;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Misaki.HighPerformance.Jobs;
|
||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
using Misaki.HighPerformance.Test.Jobs;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Misaki.HighPerformance.Test;
|
||||
namespace Misaki.HighPerformance.Test.Benchmark;
|
||||
|
||||
[MemoryDiagnoser]
|
||||
public class ParallelNoiseBenchmark
|
||||
@@ -13,23 +13,35 @@ public class ParallelNoiseBenchmark
|
||||
private const int _HEIGHT = 512;
|
||||
private const int _LENGTH = _WIDTH * _HEIGHT;
|
||||
|
||||
[Benchmark]
|
||||
public static void JobSystem()
|
||||
{
|
||||
using var buffers = new UnsafeArray<float>(_LENGTH, Allocator.Persistent, AllocationOption.None);
|
||||
var job = new NoiseJob()
|
||||
{
|
||||
buffers = buffers,
|
||||
width = _WIDTH,
|
||||
height = _HEIGHT
|
||||
};
|
||||
//[GlobalSetup]
|
||||
//public void Setup()
|
||||
//{
|
||||
// JobScheduler.Initialize();
|
||||
//}
|
||||
|
||||
using var handle = job.Schedule(_LENGTH, 64);
|
||||
handle.WaitComplete();
|
||||
}
|
||||
//[GlobalCleanup]
|
||||
//public void Cleanup()
|
||||
//{
|
||||
// JobScheduler.Shutdown();
|
||||
//}
|
||||
|
||||
//[Benchmark]
|
||||
//public void JobSystem()
|
||||
//{
|
||||
// using var buffers = new UnsafeArray<float>(_LENGTH, Allocator.Persistent, AllocationOption.None);
|
||||
// var job = new NoiseJob()
|
||||
// {
|
||||
// buffers = buffers,
|
||||
// width = _WIDTH,
|
||||
// height = _HEIGHT
|
||||
// };
|
||||
|
||||
// var handle = job.Schedule(_LENGTH, 64);
|
||||
// handle.Complete();
|
||||
//}
|
||||
|
||||
[Benchmark]
|
||||
public static void ParallelFor()
|
||||
public void ParallelFor()
|
||||
{
|
||||
using var buffers = new UnsafeArray<float>(_LENGTH, Allocator.Persistent, AllocationOption.None);
|
||||
|
||||
@@ -42,8 +54,8 @@ public class ParallelNoiseBenchmark
|
||||
});
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public static void For()
|
||||
[Benchmark(Baseline = true)]
|
||||
public void For()
|
||||
{
|
||||
using var buffers = new UnsafeArray<float>(_LENGTH, Allocator.Persistent, AllocationOption.None);
|
||||
for (var i = 0; i < _LENGTH; i++)
|
||||
184
Misaki.HighPerformance.Test/Jobs/JobSystemExample.cs
Normal file
184
Misaki.HighPerformance.Test/Jobs/JobSystemExample.cs
Normal file
@@ -0,0 +1,184 @@
|
||||
using Misaki.HighPerformance.Jobs;
|
||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
|
||||
namespace Misaki.HighPerformance.Test.Jobs;
|
||||
|
||||
/// <summary>
|
||||
/// Simple job that adds a value to each element in an array.
|
||||
/// </summary>
|
||||
public unsafe class AddValueJob : IJobParallelFor
|
||||
{
|
||||
public float* Data;
|
||||
public float Value;
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
Data[index] += Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple job that multiplies each element in an array by a value.
|
||||
/// </summary>
|
||||
public unsafe class MultiplyJob : IJobParallelFor
|
||||
{
|
||||
public float* Data;
|
||||
public float Multiplier;
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
Data[index] *= Multiplier;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple job that computes the sum of an array (single-threaded).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This job uses the Kahan summation algorithm to reduce numerical error.
|
||||
/// </remarks>
|
||||
public unsafe class KahanSumJob : IJob
|
||||
{
|
||||
public float* Data;
|
||||
public int Length;
|
||||
public float* Result;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
var sum = 0f;
|
||||
var c = 0f; // Compensation for lost low-order bits
|
||||
|
||||
for (var i = 0; i < Length; i++)
|
||||
{
|
||||
var y = Data[i] - c; // So far, so good: c is zero
|
||||
var t = sum + y; // Alas, sum is big, y small, so low-order digits of y are lost
|
||||
c = (t - sum) - y; // (t - sum) cancels the high-order part of y; subtracting y recovers negative (low part of y)
|
||||
sum = t; // Algebraically, c should always be zero. Beware overly-clever compilers!
|
||||
}
|
||||
|
||||
*Result = sum;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Example program demonstrating the job system with dependencies.
|
||||
/// </summary>
|
||||
public static class JobSystemExample
|
||||
{
|
||||
public static unsafe void RunExample()
|
||||
{
|
||||
Console.WriteLine("=== Job System Example ===");
|
||||
|
||||
const int arraySize = 10000;
|
||||
|
||||
// Create test data
|
||||
using var array = new UnsafeArray<float>(arraySize, Allocator.Persistent);
|
||||
|
||||
// Initialize with values 1, 2, 3, ...
|
||||
for (var i = 0; i < arraySize; i++)
|
||||
{
|
||||
array[i] = i + 1;
|
||||
}
|
||||
|
||||
Console.WriteLine($"Initial sum: {ComputeSum((float*)array.GetUnsafePtr(), arraySize)}");
|
||||
|
||||
// Job 1: Add 10 to each element
|
||||
var addJob = new AddValueJob
|
||||
{
|
||||
Data = (float*)array.GetUnsafePtr(),
|
||||
Value = 10f
|
||||
};
|
||||
|
||||
// Job 2: Multiply each element by 2 (depends on addJob)
|
||||
var multiplyJob = new MultiplyJob
|
||||
{
|
||||
Data = (float*)array.GetUnsafePtr(),
|
||||
Multiplier = 2f
|
||||
};
|
||||
|
||||
// Job 3: Compute final sum (depends on multiplyJob)
|
||||
var result = stackalloc float[1];
|
||||
var sumJob = new KahanSumJob
|
||||
{
|
||||
Data = (float*)array.GetUnsafePtr(),
|
||||
Length = arraySize,
|
||||
Result = result
|
||||
};
|
||||
|
||||
Console.WriteLine("Scheduling jobs with dependencies...");
|
||||
|
||||
// Schedule jobs with dependencies
|
||||
var addHandle = addJob.ScheduleParallel(arraySize, 64);
|
||||
var multiplyHandle = multiplyJob.ScheduleParallel(arraySize, 64, addHandle);
|
||||
var sumHandle = sumJob.Schedule(multiplyHandle);
|
||||
|
||||
// Wait for all jobs to complete
|
||||
sumHandle.Complete();
|
||||
|
||||
Console.WriteLine($"Final sum: {*result}");
|
||||
Console.WriteLine($"Expected sum: {ComputeExpectedSum(arraySize)}");
|
||||
Console.WriteLine("Jobs completed successfully!");
|
||||
|
||||
// Test dependency combination
|
||||
Console.WriteLine("\n=== Testing Dependency Combination ===");
|
||||
|
||||
// Reset array
|
||||
for (var i = 0; i < arraySize; i++)
|
||||
{
|
||||
array[i] = 1f;
|
||||
}
|
||||
|
||||
// Create multiple independent jobs
|
||||
var basePtr = (float*)array.GetUnsafePtr();
|
||||
var job1 = new AddValueJob { Data = basePtr, Value = 1f };
|
||||
var job2 = new AddValueJob { Data = basePtr + arraySize / 2, Value = 2f };
|
||||
var job3 = new AddValueJob { Data = basePtr + arraySize / 4, Value = 3f };
|
||||
|
||||
var handle1 = job1.ScheduleParallel(arraySize / 2, 32);
|
||||
var handle2 = job2.ScheduleParallel(arraySize / 2, 32);
|
||||
var handle3 = job3.ScheduleParallel(arraySize / 4, 32);
|
||||
|
||||
// Combine dependencies
|
||||
var combinedHandle = JobHandle.CombineDependencies(handle1, handle2, handle3);
|
||||
|
||||
// Final job that depends on all previous jobs
|
||||
var finalSum = stackalloc float[1];
|
||||
var finalSumJob = new KahanSumJob
|
||||
{
|
||||
Data = (float*)array.GetUnsafePtr(),
|
||||
Length = arraySize,
|
||||
Result = finalSum
|
||||
};
|
||||
|
||||
var finalHandle = finalSumJob.Schedule(combinedHandle);
|
||||
finalHandle.Complete();
|
||||
|
||||
Console.WriteLine($"Final sum after combined dependencies: {*finalSum}");
|
||||
Console.WriteLine("Dependency combination test completed!");
|
||||
}
|
||||
|
||||
private static unsafe float ComputeSum(float* data, int length)
|
||||
{
|
||||
var sum = 0f;
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
sum += data[i];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
private static float ComputeExpectedSum(int arraySize)
|
||||
{
|
||||
// Original sum: 1 + 2 + 3 + ... + n = n(n+1)/2
|
||||
var originalSum = arraySize * (arraySize + 1) / 2f;
|
||||
|
||||
// After adding 10: each element increases by 10, so total increases by 10 * n
|
||||
var afterAdd = originalSum + (10f * arraySize);
|
||||
|
||||
// After multiplying by 2: everything doubles
|
||||
var afterMultiply = afterAdd * 2f;
|
||||
|
||||
return afterMultiply;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,8 @@ using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Misaki.HighPerformance.Test.Jobs;
|
||||
internal struct NoiseJob : IJobParallelFor
|
||||
|
||||
internal unsafe struct NoiseJob : IJobParallelFor
|
||||
{
|
||||
public UnsafeArray<float> buffers;
|
||||
public int width;
|
||||
@@ -45,6 +46,6 @@ internal struct NoiseJob : IJobParallelFor
|
||||
var x = index % width;
|
||||
var y = index / height;
|
||||
var uv = new Vector2(x, y);
|
||||
buffers[index] = GradientNoise(uv);
|
||||
buffers[index] = float.Clamp(GradientNoise(uv), 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.14.0" />
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.15.2" />
|
||||
<PackageReference Include="MSTest" Version="3.10.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -21,4 +22,8 @@
|
||||
<ProjectReference Include="..\Misaki.HighPerformance\Misaki.HighPerformance.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="UnitTest\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
using BenchmarkDotNet.Running;
|
||||
using Misaki.HighPerformance.Test;
|
||||
using Misaki.HighPerformance.Test.Benchmark;
|
||||
using Misaki.HighPerformance.Test.Jobs;
|
||||
|
||||
BenchmarkRunner.Run<FunctionPtrBenchmark>();
|
||||
// Test the job system
|
||||
JobSystemExample.RunExample();
|
||||
|
||||
Console.WriteLine("\nPress any key to run benchmarks...");
|
||||
Console.ReadKey();
|
||||
|
||||
BenchmarkDotNet.Running.BenchmarkRunner.Run<MathematicsBenchmark>();
|
||||
//var b = new MathematicsBenchmark();
|
||||
//b.Vector2Add();
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
using Misaki.HighPerformance.Mathematics;
|
||||
|
||||
namespace Misaki.HighPerformance.Test.UnitTest.Mathematics;
|
||||
|
||||
[TestClass]
|
||||
public class TestBool2
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestConstructors()
|
||||
{
|
||||
// Default constructor
|
||||
var v1 = new bool2();
|
||||
Assert.IsFalse(v1.x);
|
||||
Assert.IsFalse(v1.y);
|
||||
|
||||
// Single value constructor
|
||||
var v2 = new bool2(true);
|
||||
Assert.IsTrue(v2.x);
|
||||
Assert.IsTrue(v2.y);
|
||||
|
||||
// Component constructor
|
||||
var v3 = new bool2(true, false);
|
||||
Assert.IsTrue(v3.x);
|
||||
Assert.IsFalse(v3.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestLogicalOperators()
|
||||
{
|
||||
var a = new bool2(true, false);
|
||||
var b = new bool2(false, true);
|
||||
|
||||
// Note: bool types don't typically have bitwise operators in this implementation
|
||||
// They are primarily used for conditional operations with math functions
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestComparisonOperators()
|
||||
{
|
||||
var a = new bool2(true, false);
|
||||
var b = new bool2(true, false);
|
||||
var c = new bool2(false, true);
|
||||
|
||||
// For bool vectors, we typically use math.all for equality comparison
|
||||
var isEqual = math.all(a == b);
|
||||
Assert.IsTrue(isEqual);
|
||||
|
||||
var isNotEqual = math.any(a != c);
|
||||
Assert.IsTrue(isNotEqual);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestSwizzleProperties()
|
||||
{
|
||||
var v = new bool2(true, false);
|
||||
|
||||
Assert.IsTrue(v.x);
|
||||
Assert.IsFalse(v.y);
|
||||
|
||||
var xy = v.xy;
|
||||
Assert.IsTrue(xy.x);
|
||||
Assert.IsFalse(xy.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMathFunctions()
|
||||
{
|
||||
var v = new bool2(true, false);
|
||||
|
||||
// Test any function
|
||||
var anyResult = math.any(v);
|
||||
Assert.IsTrue(anyResult);
|
||||
|
||||
var allFalse = new bool2(false, false);
|
||||
var anyFalse = math.any(allFalse);
|
||||
Assert.IsFalse(anyFalse);
|
||||
|
||||
// Test all function
|
||||
var allResult = math.all(v);
|
||||
Assert.IsFalse(allResult);
|
||||
|
||||
var allTrue = new bool2(true, true);
|
||||
var allTrueResult = math.all(allTrue);
|
||||
Assert.IsTrue(allTrueResult);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestIndexer()
|
||||
{
|
||||
var v = new bool2(true, false);
|
||||
|
||||
Assert.IsTrue(v[0]);
|
||||
Assert.IsFalse(v[1]);
|
||||
}
|
||||
}
|
||||
123
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestDouble2.cs
Normal file
123
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestDouble2.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
using Misaki.HighPerformance.Mathematics;
|
||||
|
||||
namespace Misaki.HighPerformance.Test.UnitTest.Mathematics;
|
||||
|
||||
[TestClass]
|
||||
public class TestDouble2
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestConstructors()
|
||||
{
|
||||
// Default constructor
|
||||
var v1 = new double2();
|
||||
Assert.AreEqual(0.0, v1.x, 1e-15);
|
||||
Assert.AreEqual(0.0, v1.y, 1e-15);
|
||||
|
||||
// Single value constructor
|
||||
var v2 = new double2(5.5);
|
||||
Assert.AreEqual(5.5, v2.x, 1e-15);
|
||||
Assert.AreEqual(5.5, v2.y, 1e-15);
|
||||
|
||||
// Component constructor
|
||||
var v3 = new double2(1.5, 2.5);
|
||||
Assert.AreEqual(1.5, v3.x, 1e-15);
|
||||
Assert.AreEqual(2.5, v3.y, 1e-15);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestArithmeticOperators()
|
||||
{
|
||||
var a = new double2(10.5, 20.5);
|
||||
var b = new double2(5.5, 4.5);
|
||||
|
||||
// Addition
|
||||
var add = a + b;
|
||||
Assert.AreEqual(16.0, add.x, 1e-15);
|
||||
Assert.AreEqual(25.0, add.y, 1e-15);
|
||||
|
||||
// Subtraction
|
||||
var sub = a - b;
|
||||
Assert.AreEqual(5.0, sub.x, 1e-15);
|
||||
Assert.AreEqual(16.0, sub.y, 1e-15);
|
||||
|
||||
// Multiplication
|
||||
var mul = a * b;
|
||||
Assert.AreEqual(57.75, mul.x, 1e-15);
|
||||
Assert.AreEqual(92.25, mul.y, 1e-15);
|
||||
|
||||
// Division
|
||||
var div = a / b;
|
||||
Assert.AreEqual(10.5 / 5.5, div.x, 1e-15);
|
||||
Assert.AreEqual(20.5 / 4.5, div.y, 1e-15);
|
||||
|
||||
// Scalar operations
|
||||
var scalarMul = a * 2.0;
|
||||
Assert.AreEqual(21.0, scalarMul.x, 1e-15);
|
||||
Assert.AreEqual(41.0, scalarMul.y, 1e-15);
|
||||
|
||||
var scalarDiv = a / 2.0;
|
||||
Assert.AreEqual(5.25, scalarDiv.x, 1e-15);
|
||||
Assert.AreEqual(10.25, scalarDiv.y, 1e-15);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestComparisonOperators()
|
||||
{
|
||||
var a = new double2(10.5, 20.5);
|
||||
var b = new double2(10.5, 20.5);
|
||||
var c = new double2(5.5, 30.5);
|
||||
|
||||
// Equality (approximate for floating point)
|
||||
Assert.IsTrue(math.all(math.abs(a - b) < 1e-15));
|
||||
Assert.IsFalse(math.all(math.abs(a - c) < 1e-15));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestSwizzleProperties()
|
||||
{
|
||||
var v = new double2(1.5, 2.5);
|
||||
|
||||
Assert.AreEqual(1.5, v.x, 1e-15);
|
||||
Assert.AreEqual(2.5, v.y, 1e-15);
|
||||
|
||||
// Test common swizzles
|
||||
var xy = v.xy;
|
||||
Assert.AreEqual(1.5, xy.x, 1e-15);
|
||||
Assert.AreEqual(2.5, xy.y, 1e-15);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestUnaryOperators()
|
||||
{
|
||||
var a = new double2(5.5, -3.5);
|
||||
|
||||
// Unary minus
|
||||
var neg = -a;
|
||||
Assert.AreEqual(-5.5, neg.x, 1e-15);
|
||||
Assert.AreEqual(3.5, neg.y, 1e-15);
|
||||
|
||||
// Unary plus
|
||||
var pos = +a;
|
||||
Assert.AreEqual(5.5, pos.x, 1e-15);
|
||||
Assert.AreEqual(-3.5, pos.y, 1e-15);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMathFunctions()
|
||||
{
|
||||
var v = new double2(3.0, 4.0);
|
||||
|
||||
// Test dot product
|
||||
var dot = math.dot(v, v);
|
||||
Assert.AreEqual(25.0, dot, 1e-15);
|
||||
|
||||
// Test length
|
||||
var length = math.length(v);
|
||||
Assert.AreEqual(5.0, length, 1e-15);
|
||||
|
||||
// Test normalize
|
||||
var normalized = math.normalize(v);
|
||||
var expectedLength = math.length(normalized);
|
||||
Assert.AreEqual(1.0, expectedLength, 1e-15);
|
||||
}
|
||||
}
|
||||
139
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestFloat2.cs
Normal file
139
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestFloat2.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
using Misaki.HighPerformance.Mathematics;
|
||||
|
||||
namespace Misaki.HighPerformance.Test.UnitTest.Mathematics;
|
||||
|
||||
[TestClass]
|
||||
public class TestFloat2
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestConstructors()
|
||||
{
|
||||
// Default constructor
|
||||
var v1 = new float2();
|
||||
Assert.AreEqual(0f, v1.x, 1e-6f);
|
||||
Assert.AreEqual(0f, v1.y, 1e-6f);
|
||||
|
||||
// Single value constructor
|
||||
var v2 = new float2(5.5f);
|
||||
Assert.AreEqual(5.5f, v2.x, 1e-6f);
|
||||
Assert.AreEqual(5.5f, v2.y, 1e-6f);
|
||||
|
||||
// Component constructor
|
||||
var v3 = new float2(1.5f, 2.5f);
|
||||
Assert.AreEqual(1.5f, v3.x, 1e-6f);
|
||||
Assert.AreEqual(2.5f, v3.y, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestArithmeticOperators()
|
||||
{
|
||||
var a = new float2(10.5f, 20.5f);
|
||||
var b = new float2(5.5f, 4.5f);
|
||||
|
||||
// Addition
|
||||
var add = a + b;
|
||||
Assert.AreEqual(16f, add.x, 1e-6f);
|
||||
Assert.AreEqual(25f, add.y, 1e-6f);
|
||||
|
||||
// Subtraction
|
||||
var sub = a - b;
|
||||
Assert.AreEqual(5f, sub.x, 1e-6f);
|
||||
Assert.AreEqual(16f, sub.y, 1e-6f);
|
||||
|
||||
// Multiplication
|
||||
var mul = a * b;
|
||||
Assert.AreEqual(57.75f, mul.x, 1e-6f);
|
||||
Assert.AreEqual(92.25f, mul.y, 1e-6f);
|
||||
|
||||
// Division
|
||||
var div = a / b;
|
||||
Assert.AreEqual(10.5f / 5.5f, div.x, 1e-6f);
|
||||
Assert.AreEqual(20.5f / 4.5f, div.y, 1e-6f);
|
||||
|
||||
// Scalar operations
|
||||
var scalarMul = a * 2f;
|
||||
Assert.AreEqual(21f, scalarMul.x, 1e-6f);
|
||||
Assert.AreEqual(41f, scalarMul.y, 1e-6f);
|
||||
|
||||
var scalarDiv = a / 2f;
|
||||
Assert.AreEqual(5.25f, scalarDiv.x, 1e-6f);
|
||||
Assert.AreEqual(10.25f, scalarDiv.y, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestComparisonOperators()
|
||||
{
|
||||
var a = new float2(10.5f, 20.5f);
|
||||
var b = new float2(10.5f, 20.5f);
|
||||
var c = new float2(5.5f, 30.5f);
|
||||
|
||||
// Equality (approximate for floating point)
|
||||
Assert.IsTrue(math.all(math.abs(a - b) < 1e-6f));
|
||||
Assert.IsFalse(math.all(math.abs(a - c) < 1e-6f));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestSwizzleProperties()
|
||||
{
|
||||
var v = new float2(1.5f, 2.5f);
|
||||
|
||||
Assert.AreEqual(1.5f, v.x, 1e-6f);
|
||||
Assert.AreEqual(2.5f, v.y, 1e-6f);
|
||||
|
||||
var xy = v.xy;
|
||||
Assert.AreEqual(1.5f, xy.x, 1e-6f);
|
||||
Assert.AreEqual(2.5f, xy.y, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestStaticProperties()
|
||||
{
|
||||
var zero = float2.zero;
|
||||
Assert.AreEqual(0f, zero.x, 1e-6f);
|
||||
Assert.AreEqual(0f, zero.y, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestUnaryOperators()
|
||||
{
|
||||
var a = new float2(5.5f, -3.5f);
|
||||
|
||||
// Unary minus
|
||||
var neg = -a;
|
||||
Assert.AreEqual(-5.5f, neg.x, 1e-6f);
|
||||
Assert.AreEqual(3.5f, neg.y, 1e-6f);
|
||||
|
||||
// Unary plus
|
||||
var pos = +a;
|
||||
Assert.AreEqual(5.5f, pos.x, 1e-6f);
|
||||
Assert.AreEqual(-3.5f, pos.y, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMathFunctions()
|
||||
{
|
||||
var v = new float2(3f, 4f);
|
||||
|
||||
// Test dot product
|
||||
var dot = math.dot(v, v);
|
||||
Assert.AreEqual(25f, dot, 1e-6f);
|
||||
|
||||
// Test length
|
||||
var length = math.length(v);
|
||||
Assert.AreEqual(5f, length, 1e-6f);
|
||||
|
||||
// Test normalize
|
||||
var normalized = math.normalize(v);
|
||||
var expectedLength = math.length(normalized);
|
||||
Assert.AreEqual(1f, expectedLength, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestIndexer()
|
||||
{
|
||||
var v = new float2(10.5f, 20.5f);
|
||||
|
||||
Assert.AreEqual(10.5f, v[0], 1e-6f);
|
||||
Assert.AreEqual(20.5f, v[1], 1e-6f);
|
||||
}
|
||||
}
|
||||
177
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestFloat3.cs
Normal file
177
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestFloat3.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
using Misaki.HighPerformance.Mathematics;
|
||||
|
||||
namespace Misaki.HighPerformance.Test.UnitTest.Mathematics;
|
||||
|
||||
[TestClass]
|
||||
public class TestFloat3
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestConstructors()
|
||||
{
|
||||
// Default constructor
|
||||
var v1 = new float3();
|
||||
Assert.AreEqual(0f, v1.x, 1e-6f);
|
||||
Assert.AreEqual(0f, v1.y, 1e-6f);
|
||||
Assert.AreEqual(0f, v1.z, 1e-6f);
|
||||
|
||||
// Single value constructor
|
||||
var v2 = new float3(5.5f);
|
||||
Assert.AreEqual(5.5f, v2.x, 1e-6f);
|
||||
Assert.AreEqual(5.5f, v2.y, 1e-6f);
|
||||
Assert.AreEqual(5.5f, v2.z, 1e-6f);
|
||||
|
||||
// Component constructor
|
||||
var v3 = new float3(1.5f, 2.5f, 3.5f);
|
||||
Assert.AreEqual(1.5f, v3.x, 1e-6f);
|
||||
Assert.AreEqual(2.5f, v3.y, 1e-6f);
|
||||
Assert.AreEqual(3.5f, v3.z, 1e-6f);
|
||||
|
||||
// Mixed constructors
|
||||
var v4 = new float3(new float2(1.5f, 2.5f), 3.5f);
|
||||
Assert.AreEqual(1.5f, v4.x, 1e-6f);
|
||||
Assert.AreEqual(2.5f, v4.y, 1e-6f);
|
||||
Assert.AreEqual(3.5f, v4.z, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestArithmeticOperators()
|
||||
{
|
||||
var a = new float3(10.5f, 20.5f, 30.5f);
|
||||
var b = new float3(5.5f, 4.5f, 6.5f);
|
||||
|
||||
// Addition
|
||||
var add = a + b;
|
||||
Assert.AreEqual(16f, add.x, 1e-6f);
|
||||
Assert.AreEqual(25f, add.y, 1e-6f);
|
||||
Assert.AreEqual(37f, add.z, 1e-6f);
|
||||
|
||||
// Subtraction
|
||||
var sub = a - b;
|
||||
Assert.AreEqual(5f, sub.x, 1e-6f);
|
||||
Assert.AreEqual(16f, sub.y, 1e-6f);
|
||||
Assert.AreEqual(24f, sub.z, 1e-6f);
|
||||
|
||||
// Multiplication
|
||||
var mul = a * b;
|
||||
Assert.AreEqual(57.75f, mul.x, 1e-6f);
|
||||
Assert.AreEqual(92.25f, mul.y, 1e-6f);
|
||||
Assert.AreEqual(198.25f, mul.z, 1e-6f);
|
||||
|
||||
// Scalar operations
|
||||
var scalarMul = a * 2f;
|
||||
Assert.AreEqual(21f, scalarMul.x, 1e-6f);
|
||||
Assert.AreEqual(41f, scalarMul.y, 1e-6f);
|
||||
Assert.AreEqual(61f, scalarMul.z, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestVectorOperations()
|
||||
{
|
||||
var a = new float3(1f, 0f, 0f);
|
||||
var b = new float3(0f, 1f, 0f);
|
||||
|
||||
// Cross product
|
||||
var cross = math.cross(a, b);
|
||||
Assert.AreEqual(0f, cross.x, 1e-6f);
|
||||
Assert.AreEqual(0f, cross.y, 1e-6f);
|
||||
Assert.AreEqual(1f, cross.z, 1e-6f);
|
||||
|
||||
// Dot product
|
||||
var dot = math.dot(a, b);
|
||||
Assert.AreEqual(0f, dot, 1e-6f);
|
||||
|
||||
// Test with non-orthogonal vectors
|
||||
var c = new float3(3f, 4f, 0f);
|
||||
var d = new float3(1f, 1f, 1f);
|
||||
|
||||
var dotCD = math.dot(c, d);
|
||||
Assert.AreEqual(7f, dotCD, 1e-6f); // 3*1 + 4*1 + 0*1 = 7
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestComparisonOperators()
|
||||
{
|
||||
var a = new float3(10.5f, 20.5f, 30.5f);
|
||||
var b = new float3(10.5f, 20.5f, 30.5f);
|
||||
var c = new float3(5.5f, 30.5f, 25.5f);
|
||||
|
||||
// Equality (approximate for floating point)
|
||||
Assert.IsTrue(math.all(math.abs(a - b) < 1e-6f));
|
||||
Assert.IsFalse(math.all(math.abs(a - c) < 1e-6f));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestSwizzleProperties()
|
||||
{
|
||||
var v = new float3(1.5f, 2.5f, 3.5f);
|
||||
|
||||
Assert.AreEqual(1.5f, v.x, 1e-6f);
|
||||
Assert.AreEqual(2.5f, v.y, 1e-6f);
|
||||
Assert.AreEqual(3.5f, v.z, 1e-6f);
|
||||
|
||||
|
||||
var xy = v.xy;
|
||||
Assert.AreEqual(1.5f, xy.x, 1e-6f);
|
||||
Assert.AreEqual(2.5f, xy.y, 1e-6f);
|
||||
|
||||
var xyz = v.xyz;
|
||||
Assert.AreEqual(1.5f, xyz.x, 1e-6f);
|
||||
Assert.AreEqual(2.5f, xyz.y, 1e-6f);
|
||||
Assert.AreEqual(3.5f, xyz.z, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestUnaryOperators()
|
||||
{
|
||||
var a = new float3(5.5f, -3.5f, 7.5f);
|
||||
|
||||
// Unary minus
|
||||
var neg = -a;
|
||||
Assert.AreEqual(-5.5f, neg.x, 1e-6f);
|
||||
Assert.AreEqual(3.5f, neg.y, 1e-6f);
|
||||
Assert.AreEqual(-7.5f, neg.z, 1e-6f);
|
||||
|
||||
// Unary plus
|
||||
var pos = +a;
|
||||
Assert.AreEqual(5.5f, pos.x, 1e-6f);
|
||||
Assert.AreEqual(-3.5f, pos.y, 1e-6f);
|
||||
Assert.AreEqual(7.5f, pos.z, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMathFunctions()
|
||||
{
|
||||
var v = new float3(3f, 4f, 0f);
|
||||
|
||||
// Test length
|
||||
var length = math.length(v);
|
||||
Assert.AreEqual(5f, length, 1e-6f);
|
||||
|
||||
// Test normalize
|
||||
var normalized = math.normalize(v);
|
||||
var expectedLength = math.length(normalized);
|
||||
Assert.AreEqual(1f, expectedLength, 1e-6f);
|
||||
Assert.AreEqual(0.6f, normalized.x, 1e-6f);
|
||||
Assert.AreEqual(0.8f, normalized.y, 1e-6f);
|
||||
Assert.AreEqual(0f, normalized.z, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestStaticValues()
|
||||
{
|
||||
var zero = float3.zero;
|
||||
Assert.AreEqual(0f, zero.x, 1e-6f);
|
||||
Assert.AreEqual(0f, zero.y, 1e-6f);
|
||||
Assert.AreEqual(0f, zero.z, 1e-6f);
|
||||
|
||||
|
||||
var right = new float3(1f, 0f, 0f);
|
||||
var up = new float3(0f, 1f, 0f);
|
||||
var forward = new float3(0f, 0f, 1f);
|
||||
|
||||
// These are common vector directions
|
||||
Assert.AreEqual(1f, right.x, 1e-6f);
|
||||
Assert.AreEqual(1f, up.y, 1e-6f);
|
||||
Assert.AreEqual(1f, forward.z, 1e-6f);
|
||||
}
|
||||
}
|
||||
200
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestFloat4.cs
Normal file
200
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestFloat4.cs
Normal file
@@ -0,0 +1,200 @@
|
||||
using Misaki.HighPerformance.Mathematics;
|
||||
|
||||
namespace Misaki.HighPerformance.Test.UnitTest.Mathematics;
|
||||
|
||||
[TestClass]
|
||||
public class TestFloat4
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestConstructors()
|
||||
{
|
||||
// Default constructor
|
||||
var v1 = new float4();
|
||||
Assert.AreEqual(0f, v1.x, 1e-6f);
|
||||
Assert.AreEqual(0f, v1.y, 1e-6f);
|
||||
Assert.AreEqual(0f, v1.z, 1e-6f);
|
||||
Assert.AreEqual(0f, v1.w, 1e-6f);
|
||||
|
||||
// Single value constructor
|
||||
var v2 = new float4(5.5f);
|
||||
Assert.AreEqual(5.5f, v2.x, 1e-6f);
|
||||
Assert.AreEqual(5.5f, v2.y, 1e-6f);
|
||||
Assert.AreEqual(5.5f, v2.z, 1e-6f);
|
||||
Assert.AreEqual(5.5f, v2.w, 1e-6f);
|
||||
|
||||
// Component constructor
|
||||
var v3 = new float4(1.5f, 2.5f, 3.5f, 4.5f);
|
||||
Assert.AreEqual(1.5f, v3.x, 1e-6f);
|
||||
Assert.AreEqual(2.5f, v3.y, 1e-6f);
|
||||
Assert.AreEqual(3.5f, v3.z, 1e-6f);
|
||||
Assert.AreEqual(4.5f, v3.w, 1e-6f);
|
||||
|
||||
// Mixed constructors
|
||||
var v4 = new float4(new float2(1.5f, 2.5f), 3.5f, 4.5f);
|
||||
Assert.AreEqual(1.5f, v4.x, 1e-6f);
|
||||
Assert.AreEqual(2.5f, v4.y, 1e-6f);
|
||||
Assert.AreEqual(3.5f, v4.z, 1e-6f);
|
||||
Assert.AreEqual(4.5f, v4.w, 1e-6f);
|
||||
|
||||
var v5 = new float4(new float3(1.5f, 2.5f, 3.5f), 4.5f);
|
||||
Assert.AreEqual(1.5f, v5.x, 1e-6f);
|
||||
Assert.AreEqual(2.5f, v5.y, 1e-6f);
|
||||
Assert.AreEqual(3.5f, v5.z, 1e-6f);
|
||||
Assert.AreEqual(4.5f, v5.w, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestArithmeticOperators()
|
||||
{
|
||||
var a = new float4(10.5f, 20.5f, 30.5f, 40.5f);
|
||||
var b = new float4(5.5f, 4.5f, 6.5f, 8.5f);
|
||||
|
||||
// Addition
|
||||
var add = a + b;
|
||||
Assert.AreEqual(16f, add.x, 1e-6f);
|
||||
Assert.AreEqual(25f, add.y, 1e-6f);
|
||||
Assert.AreEqual(37f, add.z, 1e-6f);
|
||||
Assert.AreEqual(49f, add.w, 1e-6f);
|
||||
|
||||
// Subtraction
|
||||
var sub = a - b;
|
||||
Assert.AreEqual(5f, sub.x, 1e-6f);
|
||||
Assert.AreEqual(16f, sub.y, 1e-6f);
|
||||
Assert.AreEqual(24f, sub.z, 1e-6f);
|
||||
Assert.AreEqual(32f, sub.w, 1e-6f);
|
||||
|
||||
// Multiplication
|
||||
var mul = a * b;
|
||||
Assert.AreEqual(57.75f, mul.x, 1e-6f);
|
||||
Assert.AreEqual(92.25f, mul.y, 1e-6f);
|
||||
Assert.AreEqual(198.25f, mul.z, 1e-6f);
|
||||
Assert.AreEqual(344.25f, mul.w, 1e-6f);
|
||||
|
||||
// Scalar operations
|
||||
var scalarMul = a * 2f;
|
||||
Assert.AreEqual(21f, scalarMul.x, 1e-6f);
|
||||
Assert.AreEqual(41f, scalarMul.y, 1e-6f);
|
||||
Assert.AreEqual(61f, scalarMul.z, 1e-6f);
|
||||
Assert.AreEqual(81f, scalarMul.w, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestVectorOperations()
|
||||
{
|
||||
var a = new float4(1f, 2f, 3f, 4f);
|
||||
var b = new float4(5f, 6f, 7f, 8f);
|
||||
|
||||
// Dot product
|
||||
var dot = math.dot(a, b);
|
||||
Assert.AreEqual(70f, dot, 1e-6f); // 1*5 + 2*6 + 3*7 + 4*8 = 5+12+21+32 = 70
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestComparisonOperators()
|
||||
{
|
||||
var a = new float4(10.5f, 20.5f, 30.5f, 40.5f);
|
||||
var b = new float4(10.5f, 20.5f, 30.5f, 40.5f);
|
||||
var c = new float4(5.5f, 30.5f, 25.5f, 45.5f);
|
||||
|
||||
// Equality (approximate for floating point)
|
||||
Assert.IsTrue(math.all(math.abs(a - b) < 1e-6f));
|
||||
Assert.IsFalse(math.all(math.abs(a - c) < 1e-6f));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestSwizzleProperties()
|
||||
{
|
||||
var v = new float4(1.5f, 2.5f, 3.5f, 4.5f);
|
||||
|
||||
Assert.AreEqual(1.5f, v.x, 1e-6f);
|
||||
Assert.AreEqual(2.5f, v.y, 1e-6f);
|
||||
Assert.AreEqual(3.5f, v.z, 1e-6f);
|
||||
Assert.AreEqual(4.5f, v.w, 1e-6f);
|
||||
|
||||
var xy = v.xy;
|
||||
Assert.AreEqual(1.5f, xy.x, 1e-6f);
|
||||
Assert.AreEqual(2.5f, xy.y, 1e-6f);
|
||||
|
||||
var xyz = v.xyz;
|
||||
Assert.AreEqual(1.5f, xyz.x, 1e-6f);
|
||||
Assert.AreEqual(2.5f, xyz.y, 1e-6f);
|
||||
Assert.AreEqual(3.5f, xyz.z, 1e-6f);
|
||||
|
||||
var xyzw = v.xyzw;
|
||||
Assert.AreEqual(1.5f, xyzw.x, 1e-6f);
|
||||
Assert.AreEqual(2.5f, xyzw.y, 1e-6f);
|
||||
Assert.AreEqual(3.5f, xyzw.z, 1e-6f);
|
||||
Assert.AreEqual(4.5f, xyzw.w, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestUnaryOperators()
|
||||
{
|
||||
var a = new float4(5.5f, -3.5f, 7.5f, -9.5f);
|
||||
|
||||
// Unary minus
|
||||
var neg = -a;
|
||||
Assert.AreEqual(-5.5f, neg.x, 1e-6f);
|
||||
Assert.AreEqual(3.5f, neg.y, 1e-6f);
|
||||
Assert.AreEqual(-7.5f, neg.z, 1e-6f);
|
||||
Assert.AreEqual(9.5f, neg.w, 1e-6f);
|
||||
|
||||
// Unary plus
|
||||
var pos = +a;
|
||||
Assert.AreEqual(5.5f, pos.x, 1e-6f);
|
||||
Assert.AreEqual(-3.5f, pos.y, 1e-6f);
|
||||
Assert.AreEqual(7.5f, pos.z, 1e-6f);
|
||||
Assert.AreEqual(-9.5f, pos.w, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMathFunctions()
|
||||
{
|
||||
var v = new float4(1f, 2f, 2f, 0f);
|
||||
|
||||
// Test length
|
||||
var length = math.length(v);
|
||||
Assert.AreEqual(3f, length, 1e-6f); // sqrt(1+4+4+0) = sqrt(9) = 3
|
||||
|
||||
// Test normalize
|
||||
var normalized = math.normalize(v);
|
||||
var expectedLength = math.length(normalized);
|
||||
Assert.AreEqual(1f, expectedLength, 1e-6f);
|
||||
Assert.AreEqual(1f / 3f, normalized.x, 1e-6f);
|
||||
Assert.AreEqual(2f / 3f, normalized.y, 1e-6f);
|
||||
Assert.AreEqual(2f / 3f, normalized.z, 1e-6f);
|
||||
Assert.AreEqual(0f, normalized.w, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestStaticValues()
|
||||
{
|
||||
var zero = float4.zero;
|
||||
Assert.AreEqual(0f, zero.x, 1e-6f);
|
||||
Assert.AreEqual(0f, zero.y, 1e-6f);
|
||||
Assert.AreEqual(0f, zero.z, 1e-6f);
|
||||
Assert.AreEqual(0f, zero.w, 1e-6f);
|
||||
|
||||
// Test unit vectors
|
||||
var unitX = new float4(1f, 0f, 0f, 0f);
|
||||
var unitY = new float4(0f, 1f, 0f, 0f);
|
||||
var unitZ = new float4(0f, 0f, 1f, 0f);
|
||||
var unitW = new float4(0f, 0f, 0f, 1f);
|
||||
|
||||
Assert.AreEqual(1f, unitX.x, 1e-6f);
|
||||
Assert.AreEqual(1f, unitY.y, 1e-6f);
|
||||
Assert.AreEqual(1f, unitZ.z, 1e-6f);
|
||||
Assert.AreEqual(1f, unitW.w, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestIndexer()
|
||||
{
|
||||
var v = new float4(10.5f, 20.5f, 30.5f, 40.5f);
|
||||
|
||||
Assert.AreEqual(10.5f, v[0], 1e-6f);
|
||||
Assert.AreEqual(20.5f, v[1], 1e-6f);
|
||||
Assert.AreEqual(30.5f, v[2], 1e-6f);
|
||||
Assert.AreEqual(40.5f, v[3], 1e-6f);
|
||||
}
|
||||
}
|
||||
224
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestFloat4x4.cs
Normal file
224
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestFloat4x4.cs
Normal file
@@ -0,0 +1,224 @@
|
||||
using Misaki.HighPerformance.Mathematics;
|
||||
|
||||
namespace Misaki.HighPerformance.Test.UnitTest.Mathematics;
|
||||
|
||||
[TestClass]
|
||||
public class TestFloat4x4
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestConstructors()
|
||||
{
|
||||
// Default constructor
|
||||
var m1 = new float4x4();
|
||||
|
||||
var identity = float4x4.identity;
|
||||
Assert.AreEqual(1f, identity.c0.x, 1e-6f);
|
||||
Assert.AreEqual(0f, identity.c0.y, 1e-6f);
|
||||
Assert.AreEqual(0f, identity.c0.z, 1e-6f);
|
||||
Assert.AreEqual(0f, identity.c0.w, 1e-6f);
|
||||
|
||||
Assert.AreEqual(0f, identity.c1.x, 1e-6f);
|
||||
Assert.AreEqual(1f, identity.c1.y, 1e-6f);
|
||||
Assert.AreEqual(0f, identity.c1.z, 1e-6f);
|
||||
Assert.AreEqual(0f, identity.c1.w, 1e-6f);
|
||||
|
||||
// Column constructor
|
||||
var c0 = new float4(1f, 0f, 0f, 0f);
|
||||
var c1 = new float4(0f, 1f, 0f, 0f);
|
||||
var c2 = new float4(0f, 0f, 1f, 0f);
|
||||
var c3 = new float4(0f, 0f, 0f, 1f);
|
||||
|
||||
var m2 = new float4x4(c0, c1, c2, c3);
|
||||
Assert.AreEqual(1f, m2.c0.x, 1e-6f);
|
||||
Assert.AreEqual(1f, m2.c1.y, 1e-6f);
|
||||
Assert.AreEqual(1f, m2.c2.z, 1e-6f);
|
||||
Assert.AreEqual(1f, m2.c3.w, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestArithmeticOperators()
|
||||
{
|
||||
var a = new float4x4(
|
||||
new float4(1f, 2f, 3f, 4f),
|
||||
new float4(5f, 6f, 7f, 8f),
|
||||
new float4(9f, 10f, 11f, 12f),
|
||||
new float4(13f, 14f, 15f, 16f)
|
||||
);
|
||||
|
||||
var b = new float4x4(
|
||||
new float4(1f, 1f, 1f, 1f),
|
||||
new float4(1f, 1f, 1f, 1f),
|
||||
new float4(1f, 1f, 1f, 1f),
|
||||
new float4(1f, 1f, 1f, 1f)
|
||||
);
|
||||
|
||||
// Addition
|
||||
var add = a + b;
|
||||
Assert.AreEqual(2f, add.c0.x, 1e-6f);
|
||||
Assert.AreEqual(3f, add.c0.y, 1e-6f);
|
||||
Assert.AreEqual(6f, add.c1.x, 1e-6f);
|
||||
Assert.AreEqual(7f, add.c1.y, 1e-6f);
|
||||
|
||||
// Subtraction
|
||||
var sub = a - b;
|
||||
Assert.AreEqual(0f, sub.c0.x, 1e-6f);
|
||||
Assert.AreEqual(1f, sub.c0.y, 1e-6f);
|
||||
Assert.AreEqual(4f, sub.c1.x, 1e-6f);
|
||||
Assert.AreEqual(5f, sub.c1.y, 1e-6f);
|
||||
|
||||
// Scalar multiplication
|
||||
var scalarMul = a * 2f;
|
||||
Assert.AreEqual(2f, scalarMul.c0.x, 1e-6f);
|
||||
Assert.AreEqual(4f, scalarMul.c0.y, 1e-6f);
|
||||
Assert.AreEqual(10f, scalarMul.c1.x, 1e-6f);
|
||||
Assert.AreEqual(12f, scalarMul.c1.y, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMatrixMultiplication()
|
||||
{
|
||||
// Identity matrix multiplication
|
||||
var identity = new float4x4(
|
||||
new float4(1f, 0f, 0f, 0f),
|
||||
new float4(0f, 1f, 0f, 0f),
|
||||
new float4(0f, 0f, 1f, 0f),
|
||||
new float4(0f, 0f, 0f, 1f)
|
||||
);
|
||||
|
||||
var testMatrix = new float4x4(
|
||||
new float4(2f, 3f, 4f, 5f),
|
||||
new float4(6f, 7f, 8f, 9f),
|
||||
new float4(10f, 11f, 12f, 13f),
|
||||
new float4(14f, 15f, 16f, 17f)
|
||||
);
|
||||
|
||||
// Matrix multiplication with identity should return original matrix
|
||||
var result = math.mul(identity, testMatrix);
|
||||
|
||||
Assert.AreEqual(testMatrix.c0.x, result.c0.x, 1e-6f);
|
||||
Assert.AreEqual(testMatrix.c0.y, result.c0.y, 1e-6f);
|
||||
Assert.AreEqual(testMatrix.c1.x, result.c1.x, 1e-6f);
|
||||
Assert.AreEqual(testMatrix.c1.y, result.c1.y, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMatrixVectorMultiplication()
|
||||
{
|
||||
var matrix = new float4x4(
|
||||
new float4(1f, 0f, 0f, 0f),
|
||||
new float4(0f, 1f, 0f, 0f),
|
||||
new float4(0f, 0f, 1f, 0f),
|
||||
new float4(0f, 0f, 0f, 1f)
|
||||
);
|
||||
|
||||
var vector = new float4(1f, 2f, 3f, 1f);
|
||||
|
||||
// Identity matrix multiplication should return original vector
|
||||
var result = math.mul(matrix, vector);
|
||||
|
||||
Assert.AreEqual(1f, result.x, 1e-6f);
|
||||
Assert.AreEqual(2f, result.y, 1e-6f);
|
||||
Assert.AreEqual(3f, result.z, 1e-6f);
|
||||
Assert.AreEqual(1f, result.w, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestTranspose()
|
||||
{
|
||||
var matrix = new float4x4(
|
||||
new float4(1f, 2f, 3f, 4f),
|
||||
new float4(5f, 6f, 7f, 8f),
|
||||
new float4(9f, 10f, 11f, 12f),
|
||||
new float4(13f, 14f, 15f, 16f)
|
||||
);
|
||||
|
||||
var transposed = math.transpose(matrix);
|
||||
|
||||
// Check that rows and columns are swapped
|
||||
Assert.AreEqual(matrix.c0.x, transposed.c0.x, 1e-6f); // (0,0) stays same
|
||||
Assert.AreEqual(matrix.c1.x, transposed.c0.y, 1e-6f); // (1,0) becomes (0,1)
|
||||
Assert.AreEqual(matrix.c2.x, transposed.c0.z, 1e-6f); // (2,0) becomes (0,2)
|
||||
Assert.AreEqual(matrix.c3.x, transposed.c0.w, 1e-6f); // (3,0) becomes (0,3)
|
||||
|
||||
Assert.AreEqual(matrix.c0.y, transposed.c1.x, 1e-6f); // (0,1) becomes (1,0)
|
||||
Assert.AreEqual(matrix.c1.y, transposed.c1.y, 1e-6f); // (1,1) stays same
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestDeterminant()
|
||||
{
|
||||
// Test determinant of identity matrix (should be 1)
|
||||
var identity = new float4x4(
|
||||
new float4(1f, 0f, 0f, 0f),
|
||||
new float4(0f, 1f, 0f, 0f),
|
||||
new float4(0f, 0f, 1f, 0f),
|
||||
new float4(0f, 0f, 0f, 1f)
|
||||
);
|
||||
|
||||
var det = math.determinant(identity);
|
||||
Assert.AreEqual(1f, det, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestInverse()
|
||||
{
|
||||
// Test inverse of identity matrix (should be identity)
|
||||
var identity = new float4x4(
|
||||
new float4(1f, 0f, 0f, 0f),
|
||||
new float4(0f, 1f, 0f, 0f),
|
||||
new float4(0f, 0f, 1f, 0f),
|
||||
new float4(0f, 0f, 0f, 1f)
|
||||
);
|
||||
|
||||
var inverse = math.inverse(identity);
|
||||
|
||||
Assert.AreEqual(1f, inverse.c0.x, 1e-6f);
|
||||
Assert.AreEqual(0f, inverse.c0.y, 1e-6f);
|
||||
Assert.AreEqual(0f, inverse.c1.x, 1e-6f);
|
||||
Assert.AreEqual(1f, inverse.c1.y, 1e-6f);
|
||||
Assert.AreEqual(1f, inverse.c2.z, 1e-6f);
|
||||
Assert.AreEqual(1f, inverse.c3.w, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestComparisonOperators()
|
||||
{
|
||||
var a = new float4x4(
|
||||
new float4(1f, 2f, 3f, 4f),
|
||||
new float4(5f, 6f, 7f, 8f),
|
||||
new float4(9f, 10f, 11f, 12f),
|
||||
new float4(13f, 14f, 15f, 16f)
|
||||
);
|
||||
|
||||
var b = new float4x4(
|
||||
new float4(1f, 2f, 3f, 4f),
|
||||
new float4(5f, 6f, 7f, 8f),
|
||||
new float4(9f, 10f, 11f, 12f),
|
||||
new float4(13f, 14f, 15f, 16f)
|
||||
);
|
||||
|
||||
// Test equality
|
||||
var isEqual = math.all(a.c0 == b.c0) &&
|
||||
math.all(a.c1 == b.c1) &&
|
||||
math.all(a.c2 == b.c2) &&
|
||||
math.all(a.c3 == b.c3);
|
||||
Assert.IsTrue(isEqual);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestIndexer()
|
||||
{
|
||||
var matrix = new float4x4(
|
||||
new float4(1f, 2f, 3f, 4f),
|
||||
new float4(5f, 6f, 7f, 8f),
|
||||
new float4(9f, 10f, 11f, 12f),
|
||||
new float4(13f, 14f, 15f, 16f)
|
||||
);
|
||||
|
||||
// Test column access
|
||||
Assert.AreEqual(1f, matrix[0].x, 1e-6f);
|
||||
Assert.AreEqual(2f, matrix[0].y, 1e-6f);
|
||||
Assert.AreEqual(5f, matrix[1].x, 1e-6f);
|
||||
Assert.AreEqual(6f, matrix[1].y, 1e-6f);
|
||||
}
|
||||
}
|
||||
171
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestInt2.cs
Normal file
171
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestInt2.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
using Misaki.HighPerformance.Mathematics;
|
||||
|
||||
namespace Misaki.HighPerformance.Test.UnitTest.Mathematics;
|
||||
|
||||
[TestClass]
|
||||
public class TestInt2
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestConstructors()
|
||||
{
|
||||
// Default constructor
|
||||
var v1 = new int2();
|
||||
Assert.AreEqual(0, v1.x);
|
||||
Assert.AreEqual(0, v1.y);
|
||||
|
||||
// Single value constructor
|
||||
var v2 = new int2(5);
|
||||
Assert.AreEqual(5, v2.x);
|
||||
Assert.AreEqual(5, v2.y);
|
||||
|
||||
// Component constructor
|
||||
var v3 = new int2(1, 2);
|
||||
Assert.AreEqual(1, v3.x);
|
||||
Assert.AreEqual(2, v3.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestArithmeticOperators()
|
||||
{
|
||||
var a = new int2(10, 20);
|
||||
var b = new int2(5, 4);
|
||||
|
||||
// Addition
|
||||
var add = a + b;
|
||||
Assert.AreEqual(15, add.x);
|
||||
Assert.AreEqual(24, add.y);
|
||||
|
||||
// Subtraction
|
||||
var sub = a - b;
|
||||
Assert.AreEqual(5, sub.x);
|
||||
Assert.AreEqual(16, sub.y);
|
||||
|
||||
// Multiplication
|
||||
var mul = a * b;
|
||||
Assert.AreEqual(50, mul.x);
|
||||
Assert.AreEqual(80, mul.y);
|
||||
|
||||
// Division
|
||||
var div = a / b;
|
||||
Assert.AreEqual(2, div.x);
|
||||
Assert.AreEqual(5, div.y);
|
||||
|
||||
// Scalar operations
|
||||
var scalarMul = a * 2;
|
||||
Assert.AreEqual(20, scalarMul.x);
|
||||
Assert.AreEqual(40, scalarMul.y);
|
||||
|
||||
var scalarDiv = a / 2;
|
||||
Assert.AreEqual(5, scalarDiv.x);
|
||||
Assert.AreEqual(10, scalarDiv.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestBitwiseOperators()
|
||||
{
|
||||
var a = new int2(0b1010, 0b1100);
|
||||
var b = new int2(0b1100, 0b1010);
|
||||
|
||||
// Bitwise AND
|
||||
var and = a & b;
|
||||
Assert.AreEqual(0b1000, and.x);
|
||||
Assert.AreEqual(0b1000, and.y);
|
||||
|
||||
// Bitwise OR
|
||||
var or = a | b;
|
||||
Assert.AreEqual(0b1110, or.x);
|
||||
Assert.AreEqual(0b1110, or.y);
|
||||
|
||||
// Bitwise XOR
|
||||
var xor = a ^ b;
|
||||
Assert.AreEqual(0b0110, xor.x);
|
||||
Assert.AreEqual(0b0110, xor.y);
|
||||
|
||||
// Bitwise NOT
|
||||
var not = ~a;
|
||||
Assert.AreEqual(~0b1010, not.x);
|
||||
Assert.AreEqual(~0b1100, not.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestShiftOperators()
|
||||
{
|
||||
var a = new int2(8, 16);
|
||||
|
||||
// Left shift
|
||||
var leftShift = a << 1;
|
||||
Assert.AreEqual(16, leftShift.x);
|
||||
Assert.AreEqual(32, leftShift.y);
|
||||
|
||||
// Right shift
|
||||
var rightShift = a >> 1;
|
||||
Assert.AreEqual(4, rightShift.x);
|
||||
Assert.AreEqual(8, rightShift.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestComparisonOperators()
|
||||
{
|
||||
var a = new int2(10, 20);
|
||||
var b = new int2(10, 20);
|
||||
var c = new int2(5, 30);
|
||||
|
||||
// Equality
|
||||
Assert.IsTrue(math.all(a == b));
|
||||
Assert.IsFalse(math.all(a == c));
|
||||
|
||||
// Inequality
|
||||
Assert.IsFalse(math.all(a != b));
|
||||
Assert.IsTrue(math.all(a != c));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestSwizzleProperties()
|
||||
{
|
||||
var v = new int2(1, 2);
|
||||
|
||||
// Test common swizzles if they exist
|
||||
Assert.AreEqual(1, v.x);
|
||||
Assert.AreEqual(2, v.y);
|
||||
|
||||
var xy = v.xy;
|
||||
Assert.AreEqual(1, xy.x);
|
||||
Assert.AreEqual(2, xy.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestStaticProperties()
|
||||
{
|
||||
var zero = int2.zero;
|
||||
Assert.AreEqual(0, zero.x);
|
||||
Assert.AreEqual(0, zero.y);
|
||||
var one = int2.one;
|
||||
Assert.AreEqual(1, one.x);
|
||||
Assert.AreEqual(1, one.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestUnaryOperators()
|
||||
{
|
||||
var a = new int2(5, -3);
|
||||
|
||||
// Unary minus
|
||||
var neg = -a;
|
||||
Assert.AreEqual(-5, neg.x);
|
||||
Assert.AreEqual(3, neg.y);
|
||||
|
||||
// Unary plus
|
||||
var pos = +a;
|
||||
Assert.AreEqual(5, pos.x);
|
||||
Assert.AreEqual(-3, pos.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestIndexer()
|
||||
{
|
||||
var v = new int2(10, 20);
|
||||
|
||||
Assert.AreEqual(10, v[0]);
|
||||
Assert.AreEqual(20, v[1]);
|
||||
}
|
||||
}
|
||||
198
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestInt2x2.cs
Normal file
198
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestInt2x2.cs
Normal file
@@ -0,0 +1,198 @@
|
||||
using Misaki.HighPerformance.Mathematics;
|
||||
|
||||
namespace Misaki.HighPerformance.Test.UnitTest.Mathematics;
|
||||
|
||||
[TestClass]
|
||||
public class TestInt2x2
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestConstructors()
|
||||
{
|
||||
// Default constructor
|
||||
var m1 = new int2x2();
|
||||
|
||||
// Column constructor
|
||||
var c0 = new int2(1, 2);
|
||||
var c1 = new int2(3, 4);
|
||||
var m2 = new int2x2(c0, c1);
|
||||
|
||||
Assert.AreEqual(1, m2.c0.x);
|
||||
Assert.AreEqual(2, m2.c0.y);
|
||||
Assert.AreEqual(3, m2.c1.x);
|
||||
Assert.AreEqual(4, m2.c1.y);
|
||||
|
||||
var m3 = new int2x2(1, 2, 3, 4);
|
||||
Assert.AreEqual(1, m3.c0.x);
|
||||
Assert.AreEqual(2, m3.c1.x);
|
||||
Assert.AreEqual(3, m3.c0.y);
|
||||
Assert.AreEqual(4, m3.c1.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestArithmeticOperators()
|
||||
{
|
||||
var a = new int2x2(
|
||||
new int2(1, 2),
|
||||
new int2(3, 4)
|
||||
);
|
||||
|
||||
var b = new int2x2(
|
||||
new int2(5, 6),
|
||||
new int2(7, 8)
|
||||
);
|
||||
|
||||
// Addition
|
||||
var add = a + b;
|
||||
Assert.AreEqual(6, add.c0.x);
|
||||
Assert.AreEqual(8, add.c0.y);
|
||||
Assert.AreEqual(10, add.c1.x);
|
||||
Assert.AreEqual(12, add.c1.y);
|
||||
|
||||
// Subtraction
|
||||
var sub = b - a;
|
||||
Assert.AreEqual(4, sub.c0.x);
|
||||
Assert.AreEqual(4, sub.c0.y);
|
||||
Assert.AreEqual(4, sub.c1.x);
|
||||
Assert.AreEqual(4, sub.c1.y);
|
||||
|
||||
// Scalar multiplication
|
||||
var scalarMul = a * 2;
|
||||
Assert.AreEqual(2, scalarMul.c0.x);
|
||||
Assert.AreEqual(4, scalarMul.c0.y);
|
||||
Assert.AreEqual(6, scalarMul.c1.x);
|
||||
Assert.AreEqual(8, scalarMul.c1.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMatrixMultiplication()
|
||||
{
|
||||
var a = new int2x2(
|
||||
new int2(1, 2),
|
||||
new int2(3, 4)
|
||||
);
|
||||
|
||||
var b = new int2x2(
|
||||
new int2(5, 6),
|
||||
new int2(7, 8)
|
||||
);
|
||||
|
||||
// Matrix multiplication
|
||||
var mul = math.mul(a, b);
|
||||
|
||||
// Expected result: [1 3] * [5 7] = [1*5+3*6 1*7+3*8] = [23 31]
|
||||
// [2 4] [6 8] [2*5+4*6 2*7+4*8] [34 46]
|
||||
Assert.AreEqual(23, mul.c0.x);
|
||||
Assert.AreEqual(34, mul.c0.y);
|
||||
Assert.AreEqual(31, mul.c1.x);
|
||||
Assert.AreEqual(46, mul.c1.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMatrixVectorMultiplication()
|
||||
{
|
||||
var matrix = new int2x2(
|
||||
new int2(1, 2),
|
||||
new int2(3, 4)
|
||||
);
|
||||
|
||||
var vector = new int2(5, 6);
|
||||
|
||||
// Matrix-vector multiplication
|
||||
var result = math.mul(matrix, vector);
|
||||
|
||||
// Expected: [1 3] * [5] = [1*5 + 3*6] = [23]
|
||||
// [2 4] [6] [2*5 + 4*6] [34]
|
||||
Assert.AreEqual(23, result.x);
|
||||
Assert.AreEqual(34, result.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestTranspose()
|
||||
{
|
||||
var matrix = new int2x2(
|
||||
new int2(1, 2),
|
||||
new int2(3, 4)
|
||||
);
|
||||
|
||||
var transposed = math.transpose(matrix);
|
||||
|
||||
// [1 3] -> [1 2]
|
||||
// [2 4] [3 4]
|
||||
Assert.AreEqual(1, transposed.c0.x);
|
||||
Assert.AreEqual(3, transposed.c0.y);
|
||||
Assert.AreEqual(2, transposed.c1.x);
|
||||
Assert.AreEqual(4, transposed.c1.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestDeterminant()
|
||||
{
|
||||
var matrix = new int2x2(
|
||||
new int2(1, 2),
|
||||
new int2(3, 4)
|
||||
);
|
||||
|
||||
var det = math.determinant(matrix);
|
||||
|
||||
// det = 1*4 - 2*3 = 4 - 6 = -2
|
||||
Assert.AreEqual(-2, det);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestIdentityMatrix()
|
||||
{
|
||||
var identity = int2x2.identity;
|
||||
|
||||
var testMatrix = new int2x2(
|
||||
new int2(5, 6),
|
||||
new int2(7, 8)
|
||||
);
|
||||
|
||||
var result = math.mul(identity, testMatrix);
|
||||
|
||||
Assert.AreEqual(testMatrix.c0.x, result.c0.x);
|
||||
Assert.AreEqual(testMatrix.c0.y, result.c0.y);
|
||||
Assert.AreEqual(testMatrix.c1.x, result.c1.x);
|
||||
Assert.AreEqual(testMatrix.c1.y, result.c1.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestIndexer()
|
||||
{
|
||||
var matrix = new int2x2(
|
||||
new int2(1, 2),
|
||||
new int2(3, 4)
|
||||
);
|
||||
|
||||
Assert.AreEqual(1, matrix[0].x);
|
||||
Assert.AreEqual(2, matrix[0].y);
|
||||
Assert.AreEqual(3, matrix[1].x);
|
||||
Assert.AreEqual(4, matrix[1].y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestComparisonOperators()
|
||||
{
|
||||
var a = new int2x2(
|
||||
new int2(1, 2),
|
||||
new int2(3, 4)
|
||||
);
|
||||
|
||||
var b = new int2x2(
|
||||
new int2(1, 2),
|
||||
new int2(3, 4)
|
||||
);
|
||||
|
||||
var c = new int2x2(
|
||||
new int2(5, 6),
|
||||
new int2(7, 8)
|
||||
);
|
||||
|
||||
// Test equality
|
||||
var isEqual = math.all(a.c0 == b.c0) && math.all(a.c1 == b.c1);
|
||||
Assert.IsTrue(isEqual);
|
||||
|
||||
var isDifferent = math.any(a.c0 != c.c0) || math.any(a.c1 != c.c1);
|
||||
Assert.IsTrue(isDifferent);
|
||||
}
|
||||
}
|
||||
167
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestInt3.cs
Normal file
167
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestInt3.cs
Normal file
@@ -0,0 +1,167 @@
|
||||
using Misaki.HighPerformance.Mathematics;
|
||||
|
||||
namespace Misaki.HighPerformance.Test.UnitTest.Mathematics;
|
||||
|
||||
[TestClass]
|
||||
public class TestInt3
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestConstructors()
|
||||
{
|
||||
// Default constructor
|
||||
var v1 = new int3();
|
||||
Assert.AreEqual(0, v1.x);
|
||||
Assert.AreEqual(0, v1.y);
|
||||
Assert.AreEqual(0, v1.z);
|
||||
|
||||
// Single value constructor
|
||||
var v2 = new int3(5);
|
||||
Assert.AreEqual(5, v2.x);
|
||||
Assert.AreEqual(5, v2.y);
|
||||
Assert.AreEqual(5, v2.z);
|
||||
|
||||
// Component constructor
|
||||
var v3 = new int3(1, 2, 3);
|
||||
Assert.AreEqual(1, v3.x);
|
||||
Assert.AreEqual(2, v3.y);
|
||||
Assert.AreEqual(3, v3.z);
|
||||
|
||||
// Mixed constructors
|
||||
var v4 = new int3(new int2(1, 2), 3);
|
||||
Assert.AreEqual(1, v4.x);
|
||||
Assert.AreEqual(2, v4.y);
|
||||
Assert.AreEqual(3, v4.z);
|
||||
|
||||
var v5 = new int3(1, new int2(2, 3));
|
||||
Assert.AreEqual(1, v5.x);
|
||||
Assert.AreEqual(2, v5.y);
|
||||
Assert.AreEqual(3, v5.z);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestArithmeticOperators()
|
||||
{
|
||||
var a = new int3(10, 20, 30);
|
||||
var b = new int3(5, 4, 6);
|
||||
|
||||
// Addition
|
||||
var add = a + b;
|
||||
Assert.AreEqual(15, add.x);
|
||||
Assert.AreEqual(24, add.y);
|
||||
Assert.AreEqual(36, add.z);
|
||||
|
||||
// Subtraction
|
||||
var sub = a - b;
|
||||
Assert.AreEqual(5, sub.x);
|
||||
Assert.AreEqual(16, sub.y);
|
||||
Assert.AreEqual(24, sub.z);
|
||||
|
||||
// Multiplication
|
||||
var mul = a * b;
|
||||
Assert.AreEqual(50, mul.x);
|
||||
Assert.AreEqual(80, mul.y);
|
||||
Assert.AreEqual(180, mul.z);
|
||||
|
||||
// Division
|
||||
var div = a / b;
|
||||
Assert.AreEqual(2, div.x);
|
||||
Assert.AreEqual(5, div.y);
|
||||
Assert.AreEqual(5, div.z);
|
||||
|
||||
// Scalar operations
|
||||
var scalarMul = a * 2;
|
||||
Assert.AreEqual(20, scalarMul.x);
|
||||
Assert.AreEqual(40, scalarMul.y);
|
||||
Assert.AreEqual(60, scalarMul.z);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestBitwiseOperators()
|
||||
{
|
||||
var a = new int3(0b1010, 0b1100, 0b1001);
|
||||
var b = new int3(0b1100, 0b1010, 0b1011);
|
||||
|
||||
// Bitwise AND
|
||||
var and = a & b;
|
||||
Assert.AreEqual(0b1000, and.x);
|
||||
Assert.AreEqual(0b1000, and.y);
|
||||
Assert.AreEqual(0b1001, and.z);
|
||||
|
||||
// Bitwise OR
|
||||
var or = a | b;
|
||||
Assert.AreEqual(0b1110, or.x);
|
||||
Assert.AreEqual(0b1110, or.y);
|
||||
Assert.AreEqual(0b1011, or.z);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestComparisonOperators()
|
||||
{
|
||||
var a = new int3(10, 20, 30);
|
||||
var b = new int3(10, 20, 30);
|
||||
var c = new int3(5, 30, 25);
|
||||
|
||||
// Equality
|
||||
Assert.IsTrue(math.all(a == b));
|
||||
Assert.IsFalse(math.all(a == c));
|
||||
|
||||
// Inequality
|
||||
Assert.IsFalse(math.all(a != b));
|
||||
Assert.IsTrue(math.all(a != c));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestSwizzleProperties()
|
||||
{
|
||||
var v = new int3(1, 2, 3);
|
||||
|
||||
Assert.AreEqual(1, v.x);
|
||||
Assert.AreEqual(2, v.y);
|
||||
Assert.AreEqual(3, v.z);
|
||||
|
||||
// Test common swizzles if they exist
|
||||
try
|
||||
{
|
||||
var xy = v.xy;
|
||||
Assert.AreEqual(1, xy.x);
|
||||
Assert.AreEqual(2, xy.y);
|
||||
|
||||
var xyz = v.xyz;
|
||||
Assert.AreEqual(1, xyz.x);
|
||||
Assert.AreEqual(2, xyz.y);
|
||||
Assert.AreEqual(3, xyz.z);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Swizzles might not be implemented
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestUnaryOperators()
|
||||
{
|
||||
var a = new int3(5, -3, 7);
|
||||
|
||||
// Unary minus
|
||||
var neg = -a;
|
||||
Assert.AreEqual(-5, neg.x);
|
||||
Assert.AreEqual(3, neg.y);
|
||||
Assert.AreEqual(-7, neg.z);
|
||||
|
||||
// Unary plus
|
||||
var pos = +a;
|
||||
Assert.AreEqual(5, pos.x);
|
||||
Assert.AreEqual(-3, pos.y);
|
||||
Assert.AreEqual(7, pos.z);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestIndexer()
|
||||
{
|
||||
var v = new int3(10, 20, 30);
|
||||
|
||||
Assert.AreEqual(10, v[0]);
|
||||
Assert.AreEqual(20, v[1]);
|
||||
Assert.AreEqual(30, v[2]);
|
||||
}
|
||||
}
|
||||
187
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestInt4.cs
Normal file
187
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestInt4.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
using Misaki.HighPerformance.Mathematics;
|
||||
|
||||
namespace Misaki.HighPerformance.Test.UnitTest.Mathematics;
|
||||
|
||||
[TestClass]
|
||||
public class TestInt4
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestConstructors()
|
||||
{
|
||||
// Default constructor
|
||||
var v1 = new int4();
|
||||
Assert.AreEqual(0, v1.x);
|
||||
Assert.AreEqual(0, v1.y);
|
||||
Assert.AreEqual(0, v1.z);
|
||||
Assert.AreEqual(0, v1.w);
|
||||
|
||||
// Single value constructor
|
||||
var v2 = new int4(5);
|
||||
Assert.AreEqual(5, v2.x);
|
||||
Assert.AreEqual(5, v2.y);
|
||||
Assert.AreEqual(5, v2.z);
|
||||
Assert.AreEqual(5, v2.w);
|
||||
|
||||
// Component constructor
|
||||
var v3 = new int4(1, 2, 3, 4);
|
||||
Assert.AreEqual(1, v3.x);
|
||||
Assert.AreEqual(2, v3.y);
|
||||
Assert.AreEqual(3, v3.z);
|
||||
Assert.AreEqual(4, v3.w);
|
||||
|
||||
// Mixed constructors
|
||||
var v4 = new int4(new int2(1, 2), 3, 4);
|
||||
Assert.AreEqual(1, v4.x);
|
||||
Assert.AreEqual(2, v4.y);
|
||||
Assert.AreEqual(3, v4.z);
|
||||
Assert.AreEqual(4, v4.w);
|
||||
|
||||
var v5 = new int4(new int3(1, 2, 3), 4);
|
||||
Assert.AreEqual(1, v5.x);
|
||||
Assert.AreEqual(2, v5.y);
|
||||
Assert.AreEqual(3, v5.z);
|
||||
Assert.AreEqual(4, v5.w);
|
||||
|
||||
var v6 = new int4(new int2(1, 2), new int2(3, 4));
|
||||
Assert.AreEqual(1, v6.x);
|
||||
Assert.AreEqual(2, v6.y);
|
||||
Assert.AreEqual(3, v6.z);
|
||||
Assert.AreEqual(4, v6.w);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestArithmeticOperators()
|
||||
{
|
||||
var a = new int4(10, 20, 30, 40);
|
||||
var b = new int4(5, 4, 6, 8);
|
||||
|
||||
// Addition
|
||||
var add = a + b;
|
||||
Assert.AreEqual(15, add.x);
|
||||
Assert.AreEqual(24, add.y);
|
||||
Assert.AreEqual(36, add.z);
|
||||
Assert.AreEqual(48, add.w);
|
||||
|
||||
// Subtraction
|
||||
var sub = a - b;
|
||||
Assert.AreEqual(5, sub.x);
|
||||
Assert.AreEqual(16, sub.y);
|
||||
Assert.AreEqual(24, sub.z);
|
||||
Assert.AreEqual(32, sub.w);
|
||||
|
||||
// Multiplication
|
||||
var mul = a * b;
|
||||
Assert.AreEqual(50, mul.x);
|
||||
Assert.AreEqual(80, mul.y);
|
||||
Assert.AreEqual(180, mul.z);
|
||||
Assert.AreEqual(320, mul.w);
|
||||
|
||||
// Division
|
||||
var div = a / b;
|
||||
Assert.AreEqual(2, div.x);
|
||||
Assert.AreEqual(5, div.y);
|
||||
Assert.AreEqual(5, div.z);
|
||||
Assert.AreEqual(5, div.w);
|
||||
|
||||
// Scalar operations
|
||||
var scalarMul = a * 2;
|
||||
Assert.AreEqual(20, scalarMul.x);
|
||||
Assert.AreEqual(40, scalarMul.y);
|
||||
Assert.AreEqual(60, scalarMul.z);
|
||||
Assert.AreEqual(80, scalarMul.w);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestBitwiseOperators()
|
||||
{
|
||||
var a = new int4(0b1010, 0b1100, 0b1001, 0b0110);
|
||||
var b = new int4(0b1100, 0b1010, 0b1011, 0b1001);
|
||||
|
||||
// Bitwise AND
|
||||
var and = a & b;
|
||||
Assert.AreEqual(0b1000, and.x);
|
||||
Assert.AreEqual(0b1000, and.y);
|
||||
Assert.AreEqual(0b1001, and.z);
|
||||
Assert.AreEqual(0b0000, and.w);
|
||||
|
||||
// Bitwise OR
|
||||
var or = a | b;
|
||||
Assert.AreEqual(0b1110, or.x);
|
||||
Assert.AreEqual(0b1110, or.y);
|
||||
Assert.AreEqual(0b1011, or.z);
|
||||
Assert.AreEqual(0b1111, or.w);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestComparisonOperators()
|
||||
{
|
||||
var a = new int4(10, 20, 30, 40);
|
||||
var b = new int4(10, 20, 30, 40);
|
||||
var c = new int4(5, 30, 25, 45);
|
||||
|
||||
// Equality
|
||||
Assert.IsTrue(math.all(a == b));
|
||||
Assert.IsFalse(math.all(a == c));
|
||||
|
||||
// Inequality
|
||||
Assert.IsFalse(math.all(a != b));
|
||||
Assert.IsTrue(math.all(a != c));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestSwizzleProperties()
|
||||
{
|
||||
var v = new int4(1, 2, 3, 4);
|
||||
|
||||
Assert.AreEqual(1, v.x);
|
||||
Assert.AreEqual(2, v.y);
|
||||
Assert.AreEqual(3, v.z);
|
||||
Assert.AreEqual(4, v.w);
|
||||
|
||||
var xy = v.xy;
|
||||
Assert.AreEqual(1, xy.x);
|
||||
Assert.AreEqual(2, xy.y);
|
||||
|
||||
var xyz = v.xyz;
|
||||
Assert.AreEqual(1, xyz.x);
|
||||
Assert.AreEqual(2, xyz.y);
|
||||
Assert.AreEqual(3, xyz.z);
|
||||
|
||||
var xyzw = v.xyzw;
|
||||
Assert.AreEqual(1, xyzw.x);
|
||||
Assert.AreEqual(2, xyzw.y);
|
||||
Assert.AreEqual(3, xyzw.z);
|
||||
Assert.AreEqual(4, xyzw.w);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestUnaryOperators()
|
||||
{
|
||||
var a = new int4(5, -3, 7, -9);
|
||||
|
||||
// Unary minus
|
||||
var neg = -a;
|
||||
Assert.AreEqual(-5, neg.x);
|
||||
Assert.AreEqual(3, neg.y);
|
||||
Assert.AreEqual(-7, neg.z);
|
||||
Assert.AreEqual(9, neg.w);
|
||||
|
||||
// Unary plus
|
||||
var pos = +a;
|
||||
Assert.AreEqual(5, pos.x);
|
||||
Assert.AreEqual(-3, pos.y);
|
||||
Assert.AreEqual(7, pos.z);
|
||||
Assert.AreEqual(-9, pos.w);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestIndexer()
|
||||
{
|
||||
var v = new int4(10, 20, 30, 40);
|
||||
|
||||
Assert.AreEqual(10, v[0]);
|
||||
Assert.AreEqual(20, v[1]);
|
||||
Assert.AreEqual(30, v[2]);
|
||||
Assert.AreEqual(40, v[3]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Misaki.HighPerformance.Mathematics;
|
||||
|
||||
namespace Misaki.HighPerformance.Test.UnitTest.Mathematics;
|
||||
|
||||
[TestClass]
|
||||
public class TestMathFunctions
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestTrigonometricFunctions()
|
||||
{
|
||||
// Test sin, cos, tan
|
||||
var angle = math.PI / 4f; // 45 degrees
|
||||
|
||||
var sinValue = math.sin(angle);
|
||||
var cosValue = math.cos(angle);
|
||||
var tanValue = math.tan(angle);
|
||||
|
||||
Assert.AreEqual(math.SQRT2 / 2f, sinValue, 1e-6f);
|
||||
Assert.AreEqual(math.SQRT2 / 2f, cosValue, 1e-6f);
|
||||
Assert.AreEqual(1f, tanValue, 1e-6f);
|
||||
|
||||
// Test vector versions
|
||||
var angles = new float2(0f, math.PI / 2f);
|
||||
var sinValues = math.sin(angles);
|
||||
var cosValues = math.cos(angles);
|
||||
|
||||
Assert.AreEqual(0f, sinValues.x, 1e-6f);
|
||||
Assert.AreEqual(1f, sinValues.y, 1e-6f);
|
||||
Assert.AreEqual(1f, cosValues.x, 1e-6f);
|
||||
Assert.AreEqual(0f, cosValues.y, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestHyperbolicFunctions()
|
||||
{
|
||||
var value = 1f;
|
||||
|
||||
var sinhValue = math.sinh(value);
|
||||
var coshValue = math.cosh(value);
|
||||
var tanhValue = math.tanh(value);
|
||||
|
||||
// sinh(1) ≈ 1.175, cosh(1) ≈ 1.543, tanh(1) ≈ 0.762
|
||||
Assert.AreEqual(1.175201f, sinhValue, 1e-3f);
|
||||
Assert.AreEqual(1.543081f, coshValue, 1e-3f);
|
||||
Assert.AreEqual(0.761594f, tanhValue, 1e-3f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestExponentialAndLogarithmic()
|
||||
{
|
||||
// Test exp, log
|
||||
var value = 2f;
|
||||
|
||||
var expValue = math.exp(value);
|
||||
var logValue = math.log(expValue);
|
||||
|
||||
Assert.AreEqual(value, logValue, 1e-6f);
|
||||
|
||||
// Test exp2, log2
|
||||
var exp2Value = math.exp2(value);
|
||||
var log2Value = math.log2(exp2Value);
|
||||
|
||||
Assert.AreEqual(value, log2Value, 1e-6f);
|
||||
|
||||
// Test exp10, log10
|
||||
var exp10Value = math.exp10(value);
|
||||
var log10Value = math.log10(exp10Value);
|
||||
|
||||
Assert.AreEqual(value, log10Value, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestPowerFunctions()
|
||||
{
|
||||
// Test pow
|
||||
var baseValue = 2f;
|
||||
var exponent = 3f;
|
||||
var powValue = math.pow(baseValue, exponent);
|
||||
|
||||
Assert.AreEqual(8f, powValue, 1e-6f);
|
||||
|
||||
// Test sqrt
|
||||
var sqrtValue = math.sqrt(16f);
|
||||
Assert.AreEqual(4f, sqrtValue, 1e-6f);
|
||||
|
||||
// Test rsqrt (reciprocal square root)
|
||||
var rsqrtValue = math.rsqrt(16f);
|
||||
Assert.AreEqual(0.25f, rsqrtValue, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMinMaxClamp()
|
||||
{
|
||||
// Test min, max
|
||||
var a = 3f;
|
||||
var b = 7f;
|
||||
|
||||
Assert.AreEqual(3f, math.min(a, b));
|
||||
Assert.AreEqual(7f, math.max(a, b));
|
||||
|
||||
// Test clamp
|
||||
var value = 5f;
|
||||
var clamped = math.clamp(value, 2f, 4f);
|
||||
Assert.AreEqual(4f, clamped, 1e-6f);
|
||||
|
||||
var clampedLow = math.clamp(1f, 2f, 4f);
|
||||
Assert.AreEqual(2f, clampedLow, 1e-6f);
|
||||
|
||||
var clampedNormal = math.clamp(3f, 2f, 4f);
|
||||
Assert.AreEqual(3f, clampedNormal, 1e-6f);
|
||||
|
||||
// Test vector versions
|
||||
var va = new float3(1f, 5f, 9f);
|
||||
var vb = new float3(3f, 3f, 3f);
|
||||
var minResult = math.min(va, vb);
|
||||
var maxResult = math.max(va, vb);
|
||||
|
||||
Assert.AreEqual(1f, minResult.x, 1e-6f);
|
||||
Assert.AreEqual(3f, minResult.y, 1e-6f);
|
||||
Assert.AreEqual(3f, minResult.z, 1e-6f);
|
||||
|
||||
Assert.AreEqual(3f, maxResult.x, 1e-6f);
|
||||
Assert.AreEqual(5f, maxResult.y, 1e-6f);
|
||||
Assert.AreEqual(9f, maxResult.z, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestRoundingFunctions()
|
||||
{
|
||||
var value = 3.7f;
|
||||
|
||||
// Test floor, ceil, round, trunc
|
||||
Assert.AreEqual(3f, math.floor(value), 1e-6f);
|
||||
Assert.AreEqual(4f, math.ceil(value), 1e-6f);
|
||||
Assert.AreEqual(4f, math.round(value), 1e-6f);
|
||||
Assert.AreEqual(3f, math.trunc(value), 1e-6f);
|
||||
|
||||
var negativeValue = -3.7f;
|
||||
Assert.AreEqual(-4f, math.floor(negativeValue), 1e-6f);
|
||||
Assert.AreEqual(-3f, math.ceil(negativeValue), 1e-6f);
|
||||
Assert.AreEqual(-4f, math.round(negativeValue), 1e-6f);
|
||||
Assert.AreEqual(-3f, math.trunc(negativeValue), 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestAbsAndSign()
|
||||
{
|
||||
// Test abs
|
||||
Assert.AreEqual(5f, math.abs(-5f), 1e-6f);
|
||||
Assert.AreEqual(5f, math.abs(5f), 1e-6f);
|
||||
Assert.AreEqual(0f, math.abs(0f), 1e-6f);
|
||||
|
||||
// Test sign
|
||||
Assert.AreEqual(-1f, math.sign(-5f), 1e-6f);
|
||||
Assert.AreEqual(1f, math.sign(5f), 1e-6f);
|
||||
Assert.AreEqual(0f, math.sign(0f), 1e-6f);
|
||||
|
||||
// Test vector versions
|
||||
var v = new float3(-2f, 0f, 3f);
|
||||
var absResult = math.abs(v);
|
||||
var signResult = math.sign(v);
|
||||
|
||||
Assert.AreEqual(2f, absResult.x, 1e-6f);
|
||||
Assert.AreEqual(0f, absResult.y, 1e-6f);
|
||||
Assert.AreEqual(3f, absResult.z, 1e-6f);
|
||||
|
||||
Assert.AreEqual(-1f, signResult.x, 1e-6f);
|
||||
Assert.AreEqual(0f, signResult.y, 1e-6f);
|
||||
Assert.AreEqual(1f, signResult.z, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestInterpolation()
|
||||
{
|
||||
// Test lerp (linear interpolation)
|
||||
var a = 0f;
|
||||
var b = 10f;
|
||||
var t = 0.3f;
|
||||
|
||||
var lerped = math.lerp(a, b, t);
|
||||
Assert.AreEqual(3f, lerped, 1e-6f);
|
||||
|
||||
// Test vector lerp
|
||||
var va = new float3(0f, 0f, 0f);
|
||||
var vb = new float3(10f, 20f, 30f);
|
||||
var vLerped = math.lerp(va, vb, t);
|
||||
|
||||
Assert.AreEqual(3f, vLerped.x, 1e-6f);
|
||||
Assert.AreEqual(6f, vLerped.y, 1e-6f);
|
||||
Assert.AreEqual(9f, vLerped.z, 1e-6f);
|
||||
|
||||
// Test unlerp (inverse lerp)
|
||||
var unlerpResult = math.unlerp(a, b, 3f);
|
||||
Assert.AreEqual(0.3f, unlerpResult, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestStep()
|
||||
{
|
||||
// Test step function
|
||||
var edge = 5f;
|
||||
|
||||
Assert.AreEqual(0f, math.step(edge, 3f), 1e-6f);
|
||||
Assert.AreEqual(1f, math.step(edge, 5f), 1e-6f);
|
||||
Assert.AreEqual(1f, math.step(edge, 7f), 1e-6f);
|
||||
|
||||
// Test smoothstep
|
||||
var smoothResult1 = math.smoothstep(0f, 10f, 5f);
|
||||
Assert.AreEqual(0.5f, smoothResult1, 1e-6f);
|
||||
|
||||
var smoothResult2 = math.smoothstep(0f, 10f, 0f);
|
||||
Assert.AreEqual(0f, smoothResult2, 1e-6f);
|
||||
|
||||
var smoothResult3 = math.smoothstep(0f, 10f, 10f);
|
||||
Assert.AreEqual(1f, smoothResult3, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestModAndRemainder()
|
||||
{
|
||||
// Test fmod
|
||||
var fmodResult = math.fmod(7.5f, 3f);
|
||||
Assert.AreEqual(1.5f, fmodResult, 1e-6f);
|
||||
|
||||
// Test remainder functions if available
|
||||
var a = 7f;
|
||||
var b = 3f;
|
||||
var remainder = a % b;
|
||||
Assert.AreEqual(1f, remainder, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestAngleConversions()
|
||||
{
|
||||
var degrees = 180f;
|
||||
var radians = math.radians(degrees);
|
||||
Assert.AreEqual(math.PI, radians, 1e-6f);
|
||||
|
||||
var backToDegrees = math.degrees(radians);
|
||||
Assert.AreEqual(degrees, backToDegrees, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestFloatingPointChecks()
|
||||
{
|
||||
// Test isnan
|
||||
Assert.IsTrue(math.isnan(float.NaN));
|
||||
Assert.IsFalse(math.isnan(1f));
|
||||
|
||||
// Test isinf
|
||||
Assert.IsTrue(math.isinf(float.PositiveInfinity));
|
||||
Assert.IsTrue(math.isinf(float.NegativeInfinity));
|
||||
Assert.IsFalse(math.isinf(1f));
|
||||
|
||||
// Test isfinite
|
||||
Assert.IsFalse(math.isfinite(float.PositiveInfinity));
|
||||
Assert.IsFalse(math.isfinite(float.NaN));
|
||||
Assert.IsTrue(math.isfinite(1f));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestBitOperations()
|
||||
{
|
||||
// Test asfloat, asint, asuint
|
||||
var floatValue = 1.5f;
|
||||
var intBits = math.asint(floatValue);
|
||||
var floatBack = math.asfloat(intBits);
|
||||
|
||||
Assert.AreEqual(floatValue, floatBack, 1e-6f);
|
||||
|
||||
var uintBits = math.asuint(floatValue);
|
||||
var floatFromUint = math.asfloat(uintBits);
|
||||
|
||||
Assert.AreEqual(floatValue, floatFromUint, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestSelectFunction()
|
||||
{
|
||||
// Test select function
|
||||
var condition = new bool3(true, false, true);
|
||||
var a = new float3(1f, 2f, 3f);
|
||||
var b = new float3(4f, 5f, 6f);
|
||||
|
||||
var result = math.select(b, a, condition);
|
||||
|
||||
Assert.AreEqual(1f, result.x, 1e-6f); // condition is true, so select a.x
|
||||
Assert.AreEqual(5f, result.y, 1e-6f); // condition is false, so select b.y
|
||||
Assert.AreEqual(3f, result.z, 1e-6f); // condition is true, so select a.z
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
using Misaki.HighPerformance.Mathematics;
|
||||
|
||||
namespace Misaki.HighPerformance.Test.UnitTest.Mathematics;
|
||||
|
||||
[TestClass]
|
||||
public class TestQuaternion
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestConstructors()
|
||||
{
|
||||
// Default constructor (should be identity)
|
||||
var q1 = new quaternion();
|
||||
|
||||
// Component constructor
|
||||
var q2 = new quaternion(0.5f, 0.5f, 0.5f, 0.5f);
|
||||
Assert.AreEqual(0.5f, q2.value.x, 1e-6f);
|
||||
Assert.AreEqual(0.5f, q2.value.y, 1e-6f);
|
||||
Assert.AreEqual(0.5f, q2.value.z, 1e-6f);
|
||||
Assert.AreEqual(0.5f, q2.value.w, 1e-6f);
|
||||
|
||||
// float4 constructor
|
||||
var q3 = new quaternion(new float4(0.1f, 0.2f, 0.3f, 0.4f));
|
||||
Assert.AreEqual(0.1f, q3.value.x, 1e-6f);
|
||||
Assert.AreEqual(0.2f, q3.value.y, 1e-6f);
|
||||
Assert.AreEqual(0.3f, q3.value.z, 1e-6f);
|
||||
Assert.AreEqual(0.4f, q3.value.w, 1e-6f);
|
||||
|
||||
// Identity quaternion
|
||||
var identity = quaternion.identity;
|
||||
Assert.AreEqual(0f, identity.value.x, 1e-6f);
|
||||
Assert.AreEqual(0f, identity.value.y, 1e-6f);
|
||||
Assert.AreEqual(0f, identity.value.z, 1e-6f);
|
||||
Assert.AreEqual(1f, identity.value.w, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestEulerRotations()
|
||||
{
|
||||
// Test Euler angle constructors
|
||||
var euler = new float3(math.PI / 4f, math.PI / 3f, math.PI / 6f);
|
||||
|
||||
// Test different rotation orders
|
||||
var qXYZ = quaternion.EulerXYZ(euler);
|
||||
var qXZY = quaternion.EulerXZY(euler);
|
||||
var qYXZ = quaternion.EulerYXZ(euler);
|
||||
var qYZX = quaternion.EulerYZX(euler);
|
||||
var qZXY = quaternion.EulerZXY(euler);
|
||||
var qZYX = quaternion.EulerZYX(euler);
|
||||
|
||||
// All should be unit quaternions
|
||||
Assert.AreEqual(1f, math.length(qXYZ.value), 1e-6f);
|
||||
Assert.AreEqual(1f, math.length(qXZY.value), 1e-6f);
|
||||
Assert.AreEqual(1f, math.length(qYXZ.value), 1e-6f);
|
||||
Assert.AreEqual(1f, math.length(qYZX.value), 1e-6f);
|
||||
Assert.AreEqual(1f, math.length(qZXY.value), 1e-6f);
|
||||
Assert.AreEqual(1f, math.length(qZYX.value), 1e-6f);
|
||||
|
||||
// Test generic Euler function with default order (ZXY)
|
||||
var qDefault = quaternion.Euler(euler);
|
||||
var qDefaultExplicit = quaternion.Euler(euler, math.RotationOrder.ZXY);
|
||||
|
||||
// Should be equal
|
||||
Assert.AreEqual(qZXY.value.x, qDefault.value.x, 1e-6f);
|
||||
Assert.AreEqual(qZXY.value.y, qDefault.value.y, 1e-6f);
|
||||
Assert.AreEqual(qZXY.value.z, qDefault.value.z, 1e-6f);
|
||||
Assert.AreEqual(qZXY.value.w, qDefault.value.w, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestAxisAngleRotation()
|
||||
{
|
||||
// Test rotation around Y-axis by 90 degrees
|
||||
var axis = new float3(0f, 1f, 0f);
|
||||
var angle = math.PI / 2f; // 90 degrees
|
||||
|
||||
var q = quaternion.AxisAngle(axis, angle);
|
||||
|
||||
// Should be unit quaternion
|
||||
Assert.AreEqual(1f, math.length(q.value), 1e-6f);
|
||||
|
||||
// For 90-degree rotation around Y-axis, should be (0, sin(45°), 0, cos(45°))
|
||||
var expectedSin = math.sin(angle / 2f);
|
||||
var expectedCos = math.cos(angle / 2f);
|
||||
|
||||
Assert.AreEqual(0f, q.value.x, 1e-6f);
|
||||
Assert.AreEqual(expectedSin, q.value.y, 1e-6f);
|
||||
Assert.AreEqual(0f, q.value.z, 1e-6f);
|
||||
Assert.AreEqual(expectedCos, q.value.w, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestQuaternionMultiplication()
|
||||
{
|
||||
var q1 = quaternion.identity;
|
||||
var q2 = quaternion.AxisAngle(new float3(0f, 1f, 0f), math.PI / 4f);
|
||||
|
||||
// Identity * quaternion = quaternion
|
||||
var result1 = math.mul(q1, q2);
|
||||
Assert.AreEqual(q2.value.x, result1.value.x, 1e-6f);
|
||||
Assert.AreEqual(q2.value.y, result1.value.y, 1e-6f);
|
||||
Assert.AreEqual(q2.value.z, result1.value.z, 1e-6f);
|
||||
Assert.AreEqual(q2.value.w, result1.value.w, 1e-6f);
|
||||
|
||||
// Quaternion * identity = quaternion
|
||||
var result2 = math.mul(q2, q1);
|
||||
Assert.AreEqual(q2.value.x, result2.value.x, 1e-6f);
|
||||
Assert.AreEqual(q2.value.y, result2.value.y, 1e-6f);
|
||||
Assert.AreEqual(q2.value.z, result2.value.z, 1e-6f);
|
||||
Assert.AreEqual(q2.value.w, result2.value.w, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestQuaternionVectorRotation()
|
||||
{
|
||||
// Test rotating a vector with quaternion
|
||||
var vector = new float3(1f, 0f, 0f);
|
||||
var q = quaternion.AxisAngle(new float3(0f, 0f, 1f), math.PI / 2f); // 90° around Z-axis
|
||||
|
||||
var rotated = math.mul(q, vector);
|
||||
|
||||
// Should rotate (1,0,0) to approximately (0,1,0)
|
||||
Assert.AreEqual(0f, rotated.x, 1e-6f);
|
||||
Assert.AreEqual(1f, rotated.y, 1e-6f);
|
||||
Assert.AreEqual(0f, rotated.z, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestQuaternionInverse()
|
||||
{
|
||||
var q = quaternion.AxisAngle(new float3(0f, 1f, 0f), math.PI / 3f);
|
||||
var qInverse = math.inverse(q);
|
||||
|
||||
// q * inverse(q) should equal identity
|
||||
var result = math.mul(q, qInverse);
|
||||
|
||||
Assert.AreEqual(quaternion.identity.value.x, result.value.x, 1e-6f);
|
||||
Assert.AreEqual(quaternion.identity.value.y, result.value.y, 1e-6f);
|
||||
Assert.AreEqual(quaternion.identity.value.z, result.value.z, 1e-6f);
|
||||
Assert.AreEqual(quaternion.identity.value.w, result.value.w, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestQuaternionNormalize()
|
||||
{
|
||||
// Create non-unit quaternion
|
||||
var q = new quaternion(1f, 2f, 3f, 4f);
|
||||
|
||||
var normalized = math.normalize(q);
|
||||
|
||||
// Should have length 1
|
||||
Assert.AreEqual(1f, math.length(normalized.value), 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMatrixFromQuaternion()
|
||||
{
|
||||
// Test conversion from quaternion to rotation matrix
|
||||
var q = quaternion.identity;
|
||||
var matrix = new float3x3(q);
|
||||
|
||||
// Identity quaternion should produce identity matrix
|
||||
Assert.AreEqual(1f, matrix.c0.x, 1e-6f);
|
||||
Assert.AreEqual(0f, matrix.c0.y, 1e-6f);
|
||||
Assert.AreEqual(0f, matrix.c0.z, 1e-6f);
|
||||
|
||||
Assert.AreEqual(0f, matrix.c1.x, 1e-6f);
|
||||
Assert.AreEqual(1f, matrix.c1.y, 1e-6f);
|
||||
Assert.AreEqual(0f, matrix.c1.z, 1e-6f);
|
||||
|
||||
Assert.AreEqual(0f, matrix.c2.x, 1e-6f);
|
||||
Assert.AreEqual(0f, matrix.c2.y, 1e-6f);
|
||||
Assert.AreEqual(1f, matrix.c2.z, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestQuaternionFromMatrix()
|
||||
{
|
||||
// Test conversion from matrix to quaternion
|
||||
var identity3x3 = new float3x3(
|
||||
new float3(1f, 0f, 0f),
|
||||
new float3(0f, 1f, 0f),
|
||||
new float3(0f, 0f, 1f)
|
||||
);
|
||||
|
||||
var q = new quaternion(identity3x3);
|
||||
|
||||
// Should produce identity quaternion
|
||||
Assert.AreEqual(quaternion.identity.value.x, q.value.x, 1e-6f);
|
||||
Assert.AreEqual(quaternion.identity.value.y, q.value.y, 1e-6f);
|
||||
Assert.AreEqual(quaternion.identity.value.z, q.value.z, 1e-6f);
|
||||
Assert.AreEqual(quaternion.identity.value.w, q.value.w, 1e-6f);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestSlerp()
|
||||
{
|
||||
var q1 = quaternion.identity;
|
||||
var q2 = quaternion.AxisAngle(new float3(0f, 1f, 0f), math.PI / 2f);
|
||||
|
||||
// Test interpolation
|
||||
var halfway = math.slerp(q1, q2, 0.5f);
|
||||
|
||||
// Should be unit quaternion
|
||||
Assert.AreEqual(1f, math.length(halfway.value), 1e-6f);
|
||||
|
||||
// At t=0, should equal q1
|
||||
var start = math.slerp(q1, q2, 0f);
|
||||
Assert.AreEqual(q1.value.x, start.value.x, 1e-6f);
|
||||
Assert.AreEqual(q1.value.y, start.value.y, 1e-6f);
|
||||
Assert.AreEqual(q1.value.z, start.value.z, 1e-6f);
|
||||
Assert.AreEqual(q1.value.w, start.value.w, 1e-6f);
|
||||
|
||||
// At t=1, should equal q2
|
||||
var end = math.slerp(q1, q2, 1f);
|
||||
Assert.AreEqual(q2.value.x, end.value.x, 1e-6f);
|
||||
Assert.AreEqual(q2.value.y, end.value.y, 1e-6f);
|
||||
Assert.AreEqual(q2.value.z, end.value.z, 1e-6f);
|
||||
Assert.AreEqual(q2.value.w, end.value.w, 1e-6f);
|
||||
}
|
||||
}
|
||||
147
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestUint2.cs
Normal file
147
Misaki.HighPerformance.Test/UnitTest/Mathematics/TestUint2.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
using Misaki.HighPerformance.Mathematics;
|
||||
|
||||
namespace Misaki.HighPerformance.Test.UnitTest.Mathematics;
|
||||
|
||||
[TestClass]
|
||||
public class TestUint2
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestConstructors()
|
||||
{
|
||||
// Default constructor
|
||||
var v1 = new uint2();
|
||||
Assert.AreEqual(0u, v1.x);
|
||||
Assert.AreEqual(0u, v1.y);
|
||||
|
||||
// Single value constructor
|
||||
var v2 = new uint2(5u);
|
||||
Assert.AreEqual(5u, v2.x);
|
||||
Assert.AreEqual(5u, v2.y);
|
||||
|
||||
// Component constructor
|
||||
var v3 = new uint2(1u, 2u);
|
||||
Assert.AreEqual(1u, v3.x);
|
||||
Assert.AreEqual(2u, v3.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestArithmeticOperators()
|
||||
{
|
||||
var a = new uint2(10u, 20u);
|
||||
var b = new uint2(5u, 4u);
|
||||
|
||||
// Addition
|
||||
var add = a + b;
|
||||
Assert.AreEqual(15u, add.x);
|
||||
Assert.AreEqual(24u, add.y);
|
||||
|
||||
// Subtraction
|
||||
var sub = a - b;
|
||||
Assert.AreEqual(5u, sub.x);
|
||||
Assert.AreEqual(16u, sub.y);
|
||||
|
||||
// Multiplication
|
||||
var mul = a * b;
|
||||
Assert.AreEqual(50u, mul.x);
|
||||
Assert.AreEqual(80u, mul.y);
|
||||
|
||||
// Division
|
||||
var div = a / b;
|
||||
Assert.AreEqual(2u, div.x);
|
||||
Assert.AreEqual(5u, div.y);
|
||||
|
||||
// Modulus
|
||||
var mod = a % b;
|
||||
Assert.AreEqual(0u, mod.x);
|
||||
Assert.AreEqual(0u, mod.y);
|
||||
|
||||
// Scalar operations
|
||||
var scalarMul = a * 2u;
|
||||
Assert.AreEqual(20u, scalarMul.x);
|
||||
Assert.AreEqual(40u, scalarMul.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestBitwiseOperators()
|
||||
{
|
||||
var a = new uint2(0b1010u, 0b1100u);
|
||||
var b = new uint2(0b1100u, 0b1010u);
|
||||
|
||||
// Bitwise AND
|
||||
var and = a & b;
|
||||
Assert.AreEqual(0b1000u, and.x);
|
||||
Assert.AreEqual(0b1000u, and.y);
|
||||
|
||||
// Bitwise OR
|
||||
var or = a | b;
|
||||
Assert.AreEqual(0b1110u, or.x);
|
||||
Assert.AreEqual(0b1110u, or.y);
|
||||
|
||||
// Bitwise XOR
|
||||
var xor = a ^ b;
|
||||
Assert.AreEqual(0b0110u, xor.x);
|
||||
Assert.AreEqual(0b0110u, xor.y);
|
||||
|
||||
// Bitwise NOT
|
||||
var not = ~a;
|
||||
Assert.AreEqual(~0b1010u, not.x);
|
||||
Assert.AreEqual(~0b1100u, not.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestShiftOperators()
|
||||
{
|
||||
var a = new uint2(8u, 16u);
|
||||
|
||||
// Left shift
|
||||
var leftShift = a << 1;
|
||||
Assert.AreEqual(16u, leftShift.x);
|
||||
Assert.AreEqual(32u, leftShift.y);
|
||||
|
||||
// Right shift
|
||||
var rightShift = a >> 1;
|
||||
Assert.AreEqual(4u, rightShift.x);
|
||||
Assert.AreEqual(8u, rightShift.y);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestComparisonOperators()
|
||||
{
|
||||
var a = new uint2(10u, 20u);
|
||||
var b = new uint2(10u, 20u);
|
||||
var c = new uint2(5u, 30u);
|
||||
|
||||
// Equality
|
||||
var isEqual = math.all(a == b);
|
||||
Assert.IsTrue(isEqual);
|
||||
|
||||
var isNotEqual = math.any(a != c);
|
||||
Assert.IsTrue(isNotEqual);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestUnaryOperators()
|
||||
{
|
||||
var a = new uint2(5u, 3u);
|
||||
|
||||
// Unary plus
|
||||
var pos = +a;
|
||||
Assert.AreEqual(5u, pos.x);
|
||||
Assert.AreEqual(3u, pos.y);
|
||||
|
||||
// Note: unary minus doesn't make sense for unsigned types
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestSwizzleProperties()
|
||||
{
|
||||
var v = new uint2(1u, 2u);
|
||||
|
||||
Assert.AreEqual(1u, v.x);
|
||||
Assert.AreEqual(2u, v.y);
|
||||
|
||||
var xy = v.xy;
|
||||
Assert.AreEqual(1u, xy.x);
|
||||
Assert.AreEqual(2u, xy.y);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user