From 3fdcb690455020d9f995ef9718ed8ee4ee839f72 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 26 May 2026 13:20:12 +0000
Subject: [PATCH 1/3] Initial plan
From b24186f2c8f84771aa6ae75a82f858a7d01e5ff6 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 26 May 2026 13:49:56 +0000
Subject: [PATCH 2/3] Add new math function tests (in-progress)
---
Tests/TestAsinhAcoshNew.cs | 133 +++++++++++++++++++++++++++++++++++++
Tests/TestExpNew.cs | 129 +++++++++++++++++++++++++++++++++++
Tests/TestPowNew.cs | 57 ++++++++++++++++
Tests/TestSinCosNew.cs | 93 ++++++++++++++++++++++++++
Tests/TestSinhCoshNew.cs | 93 ++++++++++++++++++++++++++
Tests/TestTanNew.cs | 53 +++++++++++++++
Tests/TestTanhNew.cs | 53 +++++++++++++++
7 files changed, 611 insertions(+)
create mode 100644 Tests/TestAsinhAcoshNew.cs
create mode 100644 Tests/TestExpNew.cs
create mode 100644 Tests/TestPowNew.cs
create mode 100644 Tests/TestSinCosNew.cs
create mode 100644 Tests/TestSinhCoshNew.cs
create mode 100644 Tests/TestTanNew.cs
create mode 100644 Tests/TestTanhNew.cs
diff --git a/Tests/TestAsinhAcoshNew.cs b/Tests/TestAsinhAcoshNew.cs
new file mode 100644
index 0000000..b2a4723
--- /dev/null
+++ b/Tests/TestAsinhAcoshNew.cs
@@ -0,0 +1,133 @@
+using System.Runtime.Intrinsics;
+using Coplt.Mathematics;
+
+#if NET8_0_OR_GREATER
+using Coplt.Mathematics.Simd;
+
+namespace Tests;
+
+[Parallelizable]
+public class TestAsinhAcoshNew
+{
+ [Test]
+ [Parallelizable]
+ public void FloatTestAsinh()
+ {
+ Utils.AssertUlpRate(nameof(FloatTestAsinh), 1000, 0.9, 100,
+ (-10f, 10f),
+ x => simd_math.Asinh(new float4(x).UnsafeGetInner()).GetElement(0),
+ MathF.Asinh
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestAsinh_vec_2_4([Random(-10f, 10.0f, 1000)] float v)
+ {
+ var a = simd_math.Asinh(new float4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Asinh(new float2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestAsinh()
+ {
+ Utils.AssertUlpRate(nameof(DoubleTestAsinh), 1000, 0.9, 700,
+ (-10.0, 10.0),
+ x => simd_math.Asinh(new double4(x).UnsafeGetInner()).GetElement(0),
+ Math.Asinh
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestAsinh_vec_2_4([Random(-10.0, 10.0, 1000)] double v)
+ {
+ var a = simd_math.Asinh(new double4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Asinh(new double2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestAcosh()
+ {
+ Utils.AssertUlpRate(nameof(FloatTestAcosh), 1000, 0.9, 2,
+ (1f, 10f),
+ x => simd_math.Acosh(new float4(x).UnsafeGetInner()).GetElement(0),
+ MathF.Acosh
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestAcosh_vec_2_4([Random(1f, 10.0f, 1000)] float v)
+ {
+ var a = simd_math.Acosh(new float4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Acosh(new float2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestAcosh()
+ {
+ Utils.AssertUlpRate(nameof(DoubleTestAcosh), 1000, 0.9, 16,
+ (1.0, 10.0),
+ x => simd_math.Acosh(new double4(x).UnsafeGetInner()).GetElement(0),
+ Math.Acosh
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestAcosh_vec_2_4([Random(1.0, 10.0, 1000)] double v)
+ {
+ var a = simd_math.Acosh(new double4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Acosh(new double2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestAtanh()
+ {
+ Utils.AssertUlpRate(nameof(FloatTestAtanh), 1000, 0.9, 4,
+ (-1f, 1f),
+ x => simd_math.Atanh(new float4(x).UnsafeGetInner()).GetElement(0),
+ MathF.Atanh
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestAtanh_vec_2_4([Random(-1f, 1.0f, 1000)] float v)
+ {
+ var a = simd_math.Atanh(new float4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Atanh(new float2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestAtanh()
+ {
+ Utils.AssertUlpRate(nameof(DoubleTestAtanh), 1000, 0.9, 4,
+ (-1.0, 1.0),
+ x => simd_math.Atanh(new double4(x).UnsafeGetInner()).GetElement(0),
+ Math.Atanh
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestAtanh_vec_2_4([Random(-1.0, 1.0, 1000)] double v)
+ {
+ var a = simd_math.Atanh(new double4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Atanh(new double2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+}
+
+#endif
diff --git a/Tests/TestExpNew.cs b/Tests/TestExpNew.cs
new file mode 100644
index 0000000..9dce6e6
--- /dev/null
+++ b/Tests/TestExpNew.cs
@@ -0,0 +1,129 @@
+using System.Runtime.Intrinsics;
+using Coplt.Mathematics;
+
+#if NET8_0_OR_GREATER
+using Coplt.Mathematics.Simd;
+
+namespace Tests;
+
+[Parallelizable]
+public class TestExpNew
+{
+ [Test]
+ [Parallelizable]
+ public void FloatTestExp()
+ {
+ Utils.AssertUlpRate(nameof(FloatTestExp), 1000, 0.9, 64,
+ (-60f, 60f),
+ x => simd_math.Exp(new float4(x).UnsafeGetInner()).GetElement(0),
+ MathF.Exp
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestExp_vec_2_4([Random(-60f, 60.0f, 1000)] float v)
+ {
+ var a = simd_math.Exp(new float4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Exp(new float2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestExpErr([Values(0f, float.NaN, float.NegativeInfinity, float.PositiveInfinity)] float v)
+ {
+ var a = simd_math.Exp(new float4(v).UnsafeGetInner()).GetElement(0);
+ var b = MathF.Exp(v);
+ Assert.That(b, Is.EqualTo(a));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestExp2()
+ {
+ Utils.AssertUlpRate(nameof(FloatTestExp2), 1000, 0.9, 2,
+ (-60f, 60f),
+ x => simd_math.Exp2(new float4(x).UnsafeGetInner()).GetElement(0),
+ x => MathF.Pow(2, x)
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestExp2_vec_2_4([Random(-60f, 60.0f, 1000)] float v)
+ {
+ var a = simd_math.Exp2(new float4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Exp2(new float2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestExp2Err([Values(0f, float.NaN, float.NegativeInfinity, float.PositiveInfinity)] float v)
+ {
+ var a = simd_math.Exp2(new float4(v).UnsafeGetInner()).GetElement(0);
+ var b = MathF.Pow(2, v);
+ Assert.That(b, Is.EqualTo(a));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestExp()
+ {
+ Utils.AssertUlpRate(nameof(DoubleTestExp), 1000, 0.9, 300,
+ (-600.0, 600.0),
+ x => simd_math.Exp(new double4(x).UnsafeGetInner()).GetElement(0),
+ Math.Exp
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestExp_vec_2_4([Random(-600.0, 600.0, 1000)] double v)
+ {
+ var a = simd_math.Exp(new double4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Exp(new double2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestExpErr([Values(0.0, double.NaN, double.NegativeInfinity, double.PositiveInfinity)] double v)
+ {
+ var a = simd_math.Exp(new double4(v).UnsafeGetInner()).GetElement(0);
+ var b = Math.Exp(v);
+ Assert.That(b, Is.EqualTo(a));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestExp2()
+ {
+ Utils.AssertUlpRate(nameof(DoubleTestExp2), 1000, 0.9, 300,
+ (-600.0, 600.0),
+ x => simd_math.Exp2(new double4(x).UnsafeGetInner()).GetElement(0),
+ x => Math.Pow(2, x)
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestExp2_vec_2_4([Random(-600.0, 600.0, 1000)] double v)
+ {
+ var a = simd_math.Exp2(new double4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Exp2(new double2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestExp2Err([Values(0.0, double.NaN, double.NegativeInfinity, double.PositiveInfinity)] double v)
+ {
+ var a = simd_math.Exp2(new double4(v).UnsafeGetInner()).GetElement(0);
+ var b = Math.Pow(2, v);
+ Assert.That(b, Is.EqualTo(a));
+ }
+}
+
+#endif
diff --git a/Tests/TestPowNew.cs b/Tests/TestPowNew.cs
new file mode 100644
index 0000000..ca53204
--- /dev/null
+++ b/Tests/TestPowNew.cs
@@ -0,0 +1,57 @@
+using System.Runtime.Intrinsics;
+using Coplt.Mathematics;
+
+#if NET8_0_OR_GREATER
+using Coplt.Mathematics.Simd;
+
+namespace Tests;
+
+[Parallelizable]
+public class TestPowNew
+{
+ [Test]
+ [Parallelizable]
+ public void FloatTestPow()
+ {
+ Utils.AssertUlpRate(nameof(FloatTestPow), 1000, 0.9, 16,
+ (0.001f, 10f), (-10f, 10f),
+ (x, y) => simd_math.Pow(new float4(x).UnsafeGetInner(), new float4(y).UnsafeGetInner()).GetElement(0),
+ MathF.Pow
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestPowOf2()
+ {
+ Utils.AssertUlpRate(nameof(FloatTestPowOf2), 1000, 0.9, 2,
+ (0f, 32f),
+ x => simd_math.Pow(new float4(2).UnsafeGetInner(), new float4(x).UnsafeGetInner()).GetElement(0),
+ x => MathF.Pow(2, x)
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestPow()
+ {
+ Utils.AssertUlpRate(nameof(DoubleTestPow), 1000, 0.9, 16,
+ (0.001, 10.0), (-10.0, 10.0),
+ (x, y) => simd_math.Pow(new double4(x).UnsafeGetInner(), new double4(y).UnsafeGetInner()).GetElement(0),
+ Math.Pow
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestPowOf2()
+ {
+ Utils.AssertUlpRate(nameof(DoubleTestPowOf2), 1000, 0.9, 700,
+ (0.0, 32.0),
+ x => simd_math.Pow(new double4(2).UnsafeGetInner(), new double4(x).UnsafeGetInner()).GetElement(0),
+ x => Math.Pow(2, x)
+ );
+ }
+}
+
+#endif
diff --git a/Tests/TestSinCosNew.cs b/Tests/TestSinCosNew.cs
new file mode 100644
index 0000000..371b3a4
--- /dev/null
+++ b/Tests/TestSinCosNew.cs
@@ -0,0 +1,93 @@
+using System.Runtime.Intrinsics;
+using Coplt.Mathematics;
+
+#if NET8_0_OR_GREATER
+using Coplt.Mathematics.Simd;
+
+namespace Tests;
+
+[Parallelizable]
+public class TestSinCosNew
+{
+ [Test]
+ [Parallelizable]
+ public void FloatTestSin()
+ {
+ Utils.AssertUlpRate(nameof(FloatTestSin), 1000, 0.9, 500,
+ (-10f, 10f),
+ x => simd_math.Sin(new float4(x).UnsafeGetInner()).GetElement(0),
+ MathF.Sin
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestSin_vec_2_4([Random(-10f, 10.0f, 1000)] float v)
+ {
+ var a = simd_math.Sin(new float4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Sin(new float2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestSin()
+ {
+ Utils.AssertUlpRate(nameof(DoubleTestSin), 1000, 0.9, 200,
+ (-10.0, 10.0),
+ x => simd_math.Sin(new double4(x).UnsafeGetInner()).GetElement(0),
+ Math.Sin
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestSin_vec_2_4([Random(-10.0, 10.0, 1000)] double v)
+ {
+ var a = simd_math.Sin(new double4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Sin(new double2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestCos()
+ {
+ Utils.AssertUlpRate(nameof(FloatTestCos), 1000, 0.9, 700,
+ (-10f, 10f),
+ x => simd_math.Cos(new float4(x).UnsafeGetInner()).GetElement(0),
+ MathF.Cos
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestCos_vec_2_4([Random(-10f, 10.0f, 1000)] float v)
+ {
+ var a = simd_math.Cos(new float4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Cos(new float2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestCos()
+ {
+ Utils.AssertUlpRate(nameof(DoubleTestCos), 1000, 0.9, 1500,
+ (-10.0, 10.0),
+ x => simd_math.Cos(new double4(x).UnsafeGetInner()).GetElement(0),
+ Math.Cos
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestCos_vec_2_4([Random(-10.0, 10.0, 1000)] double v)
+ {
+ var a = simd_math.Cos(new double4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Cos(new double2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+}
+
+#endif
diff --git a/Tests/TestSinhCoshNew.cs b/Tests/TestSinhCoshNew.cs
new file mode 100644
index 0000000..40ad1e3
--- /dev/null
+++ b/Tests/TestSinhCoshNew.cs
@@ -0,0 +1,93 @@
+using System.Runtime.Intrinsics;
+using Coplt.Mathematics;
+
+#if NET8_0_OR_GREATER
+using Coplt.Mathematics.Simd;
+
+namespace Tests;
+
+[Parallelizable]
+public class TestSinhCoshNew
+{
+ [Test]
+ [Parallelizable]
+ public void FloatTestSinh()
+ {
+ Utils.AssertUlpRate(nameof(FloatTestSinh), 1000, 0.9, 64,
+ (-10f, 10f),
+ x => simd_math.Sinh(new float4(x).UnsafeGetInner()).GetElement(0),
+ MathF.Sinh
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestSinh_vec_2_4([Random(-10f, 10.0f, 1000)] float v)
+ {
+ var a = simd_math.Sinh(new float4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Sinh(new float2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestSinh()
+ {
+ Utils.AssertUlpRate(nameof(DoubleTestSinh), 1000, 0.9, 256,
+ (-10.0, 10.0),
+ x => simd_math.Sinh(new double4(x).UnsafeGetInner()).GetElement(0),
+ Math.Sinh
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestSinh_vec_2_4([Random(-10.0, 10.0, 1000)] double v)
+ {
+ var a = simd_math.Sinh(new double4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Sinh(new double2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestCosh()
+ {
+ Utils.AssertUlpRate(nameof(FloatTestCosh), 1000, 0.9, 16,
+ (-10f, 10f),
+ x => simd_math.Cosh(new float4(x).UnsafeGetInner()).GetElement(0),
+ MathF.Cosh
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestCosh_vec_2_4([Random(-10f, 10.0f, 1000)] float v)
+ {
+ var a = simd_math.Cosh(new float4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Cosh(new float2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestCosh()
+ {
+ Utils.AssertUlpRate(nameof(DoubleTestCosh), 1000, 0.9, 16,
+ (-10.0, 10.0),
+ x => simd_math.Cosh(new double4(x).UnsafeGetInner()).GetElement(0),
+ Math.Cosh
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestCosh_vec_2_4([Random(-10.0, 10.0, 1000)] double v)
+ {
+ var a = simd_math.Cosh(new double4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Cosh(new double2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+}
+
+#endif
diff --git a/Tests/TestTanNew.cs b/Tests/TestTanNew.cs
new file mode 100644
index 0000000..067717c
--- /dev/null
+++ b/Tests/TestTanNew.cs
@@ -0,0 +1,53 @@
+using System.Runtime.Intrinsics;
+using Coplt.Mathematics;
+
+#if NET8_0_OR_GREATER
+using Coplt.Mathematics.Simd;
+
+namespace Tests;
+
+[Parallelizable]
+public class TestTanNew
+{
+ [Test]
+ [Parallelizable]
+ public void FloatTestTan()
+ {
+ Utils.AssertUlpRate(nameof(FloatTestTan), 1000, 0.9, 3000,
+ (-10f, 10f),
+ x => simd_math.Tan(new float4(x).UnsafeGetInner()).GetElement(0),
+ MathF.Tan
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestTan_vec_2_4([Random(-10f, 10.0f, 1000)] float v)
+ {
+ var a = simd_math.Tan(new float4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Tan(new float2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestTan()
+ {
+ Utils.AssertUlpRate(nameof(DoubleTestTan), 1000, 0.9, 8000,
+ (-10.0, 10.0),
+ x => simd_math.Tan(new double4(x).UnsafeGetInner()).GetElement(0),
+ Math.Tan
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestTan_vec_2_4([Random(-10.0, 10.0, 1000)] double v)
+ {
+ var a = simd_math.Tan(new double4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Tan(new double2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+}
+
+#endif
diff --git a/Tests/TestTanhNew.cs b/Tests/TestTanhNew.cs
new file mode 100644
index 0000000..c4c3b1e
--- /dev/null
+++ b/Tests/TestTanhNew.cs
@@ -0,0 +1,53 @@
+using System.Runtime.Intrinsics;
+using Coplt.Mathematics;
+
+#if NET8_0_OR_GREATER
+using Coplt.Mathematics.Simd;
+
+namespace Tests;
+
+[Parallelizable]
+public class TestTanhNew
+{
+ [Test]
+ [Parallelizable]
+ public void FloatTestTanh()
+ {
+ Utils.AssertUlpRate(nameof(FloatTestTanh), 1000, 0.9, 4,
+ (-10f, 10f),
+ x => simd_math.Tanh(new float4(x).UnsafeGetInner()).GetElement(0),
+ MathF.Tanh
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void FloatTestTanh_vec_2_4([Random(-10f, 10.0f, 1000)] float v)
+ {
+ var a = simd_math.Tanh(new float4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Tanh(new float2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestTanh()
+ {
+ Utils.AssertUlpRate(nameof(DoubleTestTanh), 1000, 0.9, 4,
+ (-10.0, 10.0),
+ x => simd_math.Tanh(new double4(x).UnsafeGetInner()).GetElement(0),
+ Math.Tanh
+ );
+ }
+
+ [Test]
+ [Parallelizable]
+ public void DoubleTestTanh_vec_2_4([Random(-10.0, 10.0, 1000)] double v)
+ {
+ var a = simd_math.Tanh(new double4(v).UnsafeGetInner()).GetElement(0);
+ var b = simd_math.Tanh(new double2(v).UnsafeGetInner()).GetElement(0);
+ Assert.That(a, Is.EqualTo(b));
+ }
+}
+
+#endif
From 78007922fa7eefb3b95d5aa6d550e99de3854c4a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 26 May 2026 14:13:52 +0000
Subject: [PATCH 3/3] Add Benchmarks project and TestExp2Accuracy tests
(Within(2).Ulps)
---
Benchmarks/BenchExp2.cs | 124 +++++++++++++++++++++++++++++++++++
Benchmarks/Benchmarks.csproj | 28 ++++++++
Benchmarks/Program.cs | 3 +
Coplt.Mathematics.sln | 61 +++++++++++++++++
Tests/TestExp2Accuracy.cs | 87 ++++++++++++++++++++++++
5 files changed, 303 insertions(+)
create mode 100644 Benchmarks/BenchExp2.cs
create mode 100644 Benchmarks/Benchmarks.csproj
create mode 100644 Benchmarks/Program.cs
create mode 100644 Tests/TestExp2Accuracy.cs
diff --git a/Benchmarks/BenchExp2.cs b/Benchmarks/BenchExp2.cs
new file mode 100644
index 0000000..33b09a2
--- /dev/null
+++ b/Benchmarks/BenchExp2.cs
@@ -0,0 +1,124 @@
+namespace Benchmarks;
+
+/// Benchmarks for simd_math.Exp2 — float and double, all SIMD widths.
+[DisassemblyDiagnoser]
+public class BenchExp2
+{
+ // 1 024 random-ish floats in [-60, 60]
+ private static readonly float[] _f32 = GenerateF32();
+ private static readonly double[] _f64 = GenerateF64();
+
+ private static float[] GenerateF32()
+ {
+ const int n = 1024;
+ var a = new float[n];
+ for (var i = 0; i < n; i++)
+ a[i] = (i - n / 2) * (120f / n); // spans [-60, 60]
+ return a;
+ }
+
+ private static double[] GenerateF64()
+ {
+ const int n = 1024;
+ var a = new double[n];
+ for (var i = 0; i < n; i++)
+ a[i] = (i - n / 2) * (1200.0 / n); // spans [-600, 600]
+ return a;
+ }
+
+ // ── float ──────────────────────────────────────────────────────────────
+
+ [Benchmark(Description = "Exp2 float×2 (Vector64)")]
+ public float Exp2_f32x2()
+ {
+ var acc = Vector64.Zero;
+ for (var i = 0; i < _f32.Length - 1; i += 2)
+ {
+ var v = Vector64.Create(_f32[i], _f32[i + 1]);
+ acc += simd_math.Exp2(v);
+ }
+ return acc.GetElement(0);
+ }
+
+ [Benchmark(Description = "Exp2 float×4 (Vector128)", Baseline = true)]
+ public float Exp2_f32x4()
+ {
+ var acc = Vector128.Zero;
+ for (var i = 0; i < _f32.Length - 3; i += 4)
+ {
+ var v = Vector128.Create(_f32[i], _f32[i + 1], _f32[i + 2], _f32[i + 3]);
+ acc += simd_math.Exp2(v);
+ }
+ return acc.GetElement(0);
+ }
+
+ [Benchmark(Description = "Exp2 float×8 (Vector256)")]
+ public float Exp2_f32x8()
+ {
+ var acc = Vector256.Zero;
+ for (var i = 0; i < _f32.Length - 7; i += 8)
+ {
+ var v = Vector256.Create(
+ _f32[i], _f32[i + 1], _f32[i + 2], _f32[i + 3],
+ _f32[i + 4], _f32[i + 5], _f32[i + 6], _f32[i + 7]);
+ acc += simd_math.Exp2(v);
+ }
+ return acc.GetElement(0);
+ }
+
+ [Benchmark(Description = "Exp2 float×16 (Vector512)")]
+ public float Exp2_f32x16()
+ {
+ var acc = Vector512.Zero;
+ for (var i = 0; i < _f32.Length - 15; i += 16)
+ {
+ var v = Vector512.Create(
+ _f32[i], _f32[i + 1], _f32[i + 2], _f32[i + 3],
+ _f32[i + 4], _f32[i + 5], _f32[i + 6], _f32[i + 7],
+ _f32[i + 8], _f32[i + 9], _f32[i + 10], _f32[i + 11],
+ _f32[i + 12], _f32[i + 13], _f32[i + 14], _f32[i + 15]);
+ acc += simd_math.Exp2(v);
+ }
+ return acc.GetElement(0);
+ }
+
+ // ── double ─────────────────────────────────────────────────────────────
+
+ [Benchmark(Description = "Exp2 double×2 (Vector128)")]
+ public double Exp2_f64x2()
+ {
+ var acc = Vector128.Zero;
+ for (var i = 0; i < _f64.Length - 1; i += 2)
+ {
+ var v = Vector128.Create(_f64[i], _f64[i + 1]);
+ acc += simd_math.Exp2(v);
+ }
+ return acc.GetElement(0);
+ }
+
+ [Benchmark(Description = "Exp2 double×4 (Vector256)")]
+ public double Exp2_f64x4()
+ {
+ var acc = Vector256.Zero;
+ for (var i = 0; i < _f64.Length - 3; i += 4)
+ {
+ var v = Vector256.Create(_f64[i], _f64[i + 1], _f64[i + 2], _f64[i + 3]);
+ acc += simd_math.Exp2(v);
+ }
+ return acc.GetElement(0);
+ }
+
+ [Benchmark(Description = "Exp2 double×8 (Vector512)")]
+ public double Exp2_f64x8()
+ {
+ var acc = Vector512.Zero;
+ for (var i = 0; i < _f64.Length - 7; i += 8)
+ {
+ var v = Vector512.Create(
+ _f64[i], _f64[i + 1], _f64[i + 2], _f64[i + 3],
+ _f64[i + 4], _f64[i + 5], _f64[i + 6], _f64[i + 7]);
+ acc += simd_math.Exp2(v);
+ }
+ return acc.GetElement(0);
+ }
+}
diff --git a/Benchmarks/Benchmarks.csproj b/Benchmarks/Benchmarks.csproj
new file mode 100644
index 0000000..07c58f1
--- /dev/null
+++ b/Benchmarks/Benchmarks.csproj
@@ -0,0 +1,28 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+ 13.0
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Benchmarks/Program.cs b/Benchmarks/Program.cs
new file mode 100644
index 0000000..b986d99
--- /dev/null
+++ b/Benchmarks/Program.cs
@@ -0,0 +1,3 @@
+using BenchmarkDotNet.Running;
+
+BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
diff --git a/Coplt.Mathematics.sln b/Coplt.Mathematics.sln
index 6f0389b..367a767 100644
--- a/Coplt.Mathematics.sln
+++ b/Coplt.Mathematics.sln
@@ -10,31 +10,92 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceGenerator", "SourceGe
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Coplt.Mathematics.Simt", "Coplt.Mathematics.Simt\Coplt.Mathematics.Simt.csproj", "{18B7AA4D-1D2F-406F-9C77-5FA06A592895}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "Benchmarks\Benchmarks.csproj", "{98399753-5721-4E8E-BB2C-53A4F9E79A80}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5745D85D-B9C1-43B8-90A0-D820184CBBBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5745D85D-B9C1-43B8-90A0-D820184CBBBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5745D85D-B9C1-43B8-90A0-D820184CBBBB}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5745D85D-B9C1-43B8-90A0-D820184CBBBB}.Debug|x64.Build.0 = Debug|Any CPU
+ {5745D85D-B9C1-43B8-90A0-D820184CBBBB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5745D85D-B9C1-43B8-90A0-D820184CBBBB}.Debug|x86.Build.0 = Debug|Any CPU
{5745D85D-B9C1-43B8-90A0-D820184CBBBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5745D85D-B9C1-43B8-90A0-D820184CBBBB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5745D85D-B9C1-43B8-90A0-D820184CBBBB}.Release|x64.ActiveCfg = Release|Any CPU
+ {5745D85D-B9C1-43B8-90A0-D820184CBBBB}.Release|x64.Build.0 = Release|Any CPU
+ {5745D85D-B9C1-43B8-90A0-D820184CBBBB}.Release|x86.ActiveCfg = Release|Any CPU
+ {5745D85D-B9C1-43B8-90A0-D820184CBBBB}.Release|x86.Build.0 = Release|Any CPU
{EAEDC447-AA5D-48D6-B285-425C5E8D52B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EAEDC447-AA5D-48D6-B285-425C5E8D52B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EAEDC447-AA5D-48D6-B285-425C5E8D52B6}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {EAEDC447-AA5D-48D6-B285-425C5E8D52B6}.Debug|x64.Build.0 = Debug|Any CPU
+ {EAEDC447-AA5D-48D6-B285-425C5E8D52B6}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {EAEDC447-AA5D-48D6-B285-425C5E8D52B6}.Debug|x86.Build.0 = Debug|Any CPU
{EAEDC447-AA5D-48D6-B285-425C5E8D52B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EAEDC447-AA5D-48D6-B285-425C5E8D52B6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EAEDC447-AA5D-48D6-B285-425C5E8D52B6}.Release|x64.ActiveCfg = Release|Any CPU
+ {EAEDC447-AA5D-48D6-B285-425C5E8D52B6}.Release|x64.Build.0 = Release|Any CPU
+ {EAEDC447-AA5D-48D6-B285-425C5E8D52B6}.Release|x86.ActiveCfg = Release|Any CPU
+ {EAEDC447-AA5D-48D6-B285-425C5E8D52B6}.Release|x86.Build.0 = Release|Any CPU
{A8E41063-557E-4421-88A4-4DE59E49295B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A8E41063-557E-4421-88A4-4DE59E49295B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A8E41063-557E-4421-88A4-4DE59E49295B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {A8E41063-557E-4421-88A4-4DE59E49295B}.Debug|x64.Build.0 = Debug|Any CPU
+ {A8E41063-557E-4421-88A4-4DE59E49295B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A8E41063-557E-4421-88A4-4DE59E49295B}.Debug|x86.Build.0 = Debug|Any CPU
{A8E41063-557E-4421-88A4-4DE59E49295B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A8E41063-557E-4421-88A4-4DE59E49295B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A8E41063-557E-4421-88A4-4DE59E49295B}.Release|x64.ActiveCfg = Release|Any CPU
+ {A8E41063-557E-4421-88A4-4DE59E49295B}.Release|x64.Build.0 = Release|Any CPU
+ {A8E41063-557E-4421-88A4-4DE59E49295B}.Release|x86.ActiveCfg = Release|Any CPU
+ {A8E41063-557E-4421-88A4-4DE59E49295B}.Release|x86.Build.0 = Release|Any CPU
{D7F6B482-EFD3-46E0-964E-4E2CC53CCE0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D7F6B482-EFD3-46E0-964E-4E2CC53CCE0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D7F6B482-EFD3-46E0-964E-4E2CC53CCE0B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D7F6B482-EFD3-46E0-964E-4E2CC53CCE0B}.Debug|x64.Build.0 = Debug|Any CPU
+ {D7F6B482-EFD3-46E0-964E-4E2CC53CCE0B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D7F6B482-EFD3-46E0-964E-4E2CC53CCE0B}.Debug|x86.Build.0 = Debug|Any CPU
{D7F6B482-EFD3-46E0-964E-4E2CC53CCE0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D7F6B482-EFD3-46E0-964E-4E2CC53CCE0B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D7F6B482-EFD3-46E0-964E-4E2CC53CCE0B}.Release|x64.ActiveCfg = Release|Any CPU
+ {D7F6B482-EFD3-46E0-964E-4E2CC53CCE0B}.Release|x64.Build.0 = Release|Any CPU
+ {D7F6B482-EFD3-46E0-964E-4E2CC53CCE0B}.Release|x86.ActiveCfg = Release|Any CPU
+ {D7F6B482-EFD3-46E0-964E-4E2CC53CCE0B}.Release|x86.Build.0 = Release|Any CPU
{18B7AA4D-1D2F-406F-9C77-5FA06A592895}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{18B7AA4D-1D2F-406F-9C77-5FA06A592895}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {18B7AA4D-1D2F-406F-9C77-5FA06A592895}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {18B7AA4D-1D2F-406F-9C77-5FA06A592895}.Debug|x64.Build.0 = Debug|Any CPU
+ {18B7AA4D-1D2F-406F-9C77-5FA06A592895}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {18B7AA4D-1D2F-406F-9C77-5FA06A592895}.Debug|x86.Build.0 = Debug|Any CPU
{18B7AA4D-1D2F-406F-9C77-5FA06A592895}.Release|Any CPU.ActiveCfg = Release|Any CPU
{18B7AA4D-1D2F-406F-9C77-5FA06A592895}.Release|Any CPU.Build.0 = Release|Any CPU
+ {18B7AA4D-1D2F-406F-9C77-5FA06A592895}.Release|x64.ActiveCfg = Release|Any CPU
+ {18B7AA4D-1D2F-406F-9C77-5FA06A592895}.Release|x64.Build.0 = Release|Any CPU
+ {18B7AA4D-1D2F-406F-9C77-5FA06A592895}.Release|x86.ActiveCfg = Release|Any CPU
+ {18B7AA4D-1D2F-406F-9C77-5FA06A592895}.Release|x86.Build.0 = Release|Any CPU
+ {98399753-5721-4E8E-BB2C-53A4F9E79A80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {98399753-5721-4E8E-BB2C-53A4F9E79A80}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {98399753-5721-4E8E-BB2C-53A4F9E79A80}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {98399753-5721-4E8E-BB2C-53A4F9E79A80}.Debug|x64.Build.0 = Debug|Any CPU
+ {98399753-5721-4E8E-BB2C-53A4F9E79A80}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {98399753-5721-4E8E-BB2C-53A4F9E79A80}.Debug|x86.Build.0 = Debug|Any CPU
+ {98399753-5721-4E8E-BB2C-53A4F9E79A80}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {98399753-5721-4E8E-BB2C-53A4F9E79A80}.Release|Any CPU.Build.0 = Release|Any CPU
+ {98399753-5721-4E8E-BB2C-53A4F9E79A80}.Release|x64.ActiveCfg = Release|Any CPU
+ {98399753-5721-4E8E-BB2C-53A4F9E79A80}.Release|x64.Build.0 = Release|Any CPU
+ {98399753-5721-4E8E-BB2C-53A4F9E79A80}.Release|x86.ActiveCfg = Release|Any CPU
+ {98399753-5721-4E8E-BB2C-53A4F9E79A80}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
diff --git a/Tests/TestExp2Accuracy.cs b/Tests/TestExp2Accuracy.cs
new file mode 100644
index 0000000..4b3f53c
--- /dev/null
+++ b/Tests/TestExp2Accuracy.cs
@@ -0,0 +1,87 @@
+using System.Runtime.Intrinsics;
+using Coplt.Mathematics;
+
+#if NET8_0_OR_GREATER
+using Coplt.Mathematics.Simd;
+
+namespace Tests;
+
+/// Accuracy tests for simd_math.Exp2 — float and double, all SIMD widths.
+[Parallelizable]
+public class TestExp2Accuracy
+{
+ // ── float Exp2 ─────────────────────────────────────────────────────────
+
+ [Test, Parallelizable]
+ public void Float_Exp2_Vector128([Random(-60f, 60f, 1000)] float x)
+ {
+ var result = simd_math.Exp2(new float4(x).UnsafeGetInner()).GetElement(0);
+ Assert.That(result, Is.EqualTo(MathF.Pow(2f, x)).Within(2).Ulps);
+ }
+
+ [Test, Parallelizable]
+ public void Float_Exp2_Vector64([Random(-60f, 60f, 1000)] float x)
+ {
+ var result = simd_math.Exp2(new float2(x).UnsafeGetInner()).GetElement(0);
+ Assert.That(result, Is.EqualTo(MathF.Pow(2f, x)).Within(2).Ulps);
+ }
+
+ [Test, Parallelizable]
+ public void Float_Exp2_ConsistentAcrossWidths([Random(-60f, 60f, 500)] float x)
+ {
+ var r64 = simd_math.Exp2(new float2(x).UnsafeGetInner()).GetElement(0);
+ var r128 = simd_math.Exp2(new float4(x).UnsafeGetInner()).GetElement(0);
+ Assert.That(r64, Is.EqualTo(r128));
+ }
+
+ [Test, Parallelizable]
+ public void Float_Exp2_SpecialValues(
+ [Values(0f, 1f, -1f, float.NaN, float.NegativeInfinity, float.PositiveInfinity)] float x)
+ {
+ var result = simd_math.Exp2(new float4(x).UnsafeGetInner()).GetElement(0);
+ var expected = MathF.Pow(2f, x);
+ // NaN: both must be NaN; Infinity: must match exactly; others: within 2 ULP
+ if (float.IsNaN(expected))
+ Assert.That(result, Is.NaN);
+ else
+ Assert.That(result, Is.EqualTo(expected).Within(2).Ulps);
+ }
+
+ // ── double Exp2 ────────────────────────────────────────────────────────
+
+ [Test, Parallelizable]
+ public void Double_Exp2_Vector128([Random(-600.0, 600.0, 1000)] double x)
+ {
+ var result = simd_math.Exp2(new double2(x).UnsafeGetInner()).GetElement(0);
+ Assert.That(result, Is.EqualTo(Math.Pow(2.0, x)).Within(2).Ulps);
+ }
+
+ [Test, Parallelizable]
+ public void Double_Exp2_Vector256([Random(-600.0, 600.0, 1000)] double x)
+ {
+ var result = simd_math.Exp2(new double4(x).UnsafeGetInner()).GetElement(0);
+ Assert.That(result, Is.EqualTo(Math.Pow(2.0, x)).Within(2).Ulps);
+ }
+
+ [Test, Parallelizable]
+ public void Double_Exp2_ConsistentAcrossWidths([Random(-600.0, 600.0, 500)] double x)
+ {
+ var r128 = simd_math.Exp2(new double2(x).UnsafeGetInner()).GetElement(0);
+ var r256 = simd_math.Exp2(new double4(x).UnsafeGetInner()).GetElement(0);
+ Assert.That(r128, Is.EqualTo(r256));
+ }
+
+ [Test, Parallelizable]
+ public void Double_Exp2_SpecialValues(
+ [Values(0.0, 1.0, -1.0, double.NaN, double.NegativeInfinity, double.PositiveInfinity)] double x)
+ {
+ var result = simd_math.Exp2(new double4(x).UnsafeGetInner()).GetElement(0);
+ var expected = Math.Pow(2.0, x);
+ if (double.IsNaN(expected))
+ Assert.That(result, Is.NaN);
+ else
+ Assert.That(result, Is.EqualTo(expected).Within(2).Ulps);
+ }
+}
+
+#endif