Skip to content

Commit

Permalink
Merge pull request #44 from KoziLord/master
Browse files Browse the repository at this point in the history
Add a Remainder method
  • Loading branch information
john-h-k committed Sep 10, 2019
2 parents b126b51 + 3a2886c commit 75ce8f8
Show file tree
Hide file tree
Showing 8 changed files with 270 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using BenchmarkDotNet.Attributes;
using OpenTK;
using System.Runtime.Intrinsics.X86;

namespace MathSharp.Interactive.Benchmarks.Vector.Double
{
using Vector = MathSharp.Vector;
public class RemainderBenchmark
{
private Vector4d vec;

[GlobalSetup]
public void Setup()
{
vec = new Vector4d(0, 1.2f, 1.6f, 3.2f);
}
[Benchmark]
public void Normal()
{
var result = normal(vec, 2);
}

[Benchmark]
public void MathSharp()
{
var result = mathSharp(vec, 2);
}

//Prevents the JIT from compiling Normal() away.
private unsafe Vector4d mathSharp(Vector4d vector, double divisor)
{
var v = Avx.LoadVector256((double*)&vector);
v = Vector.Remainder(v, divisor);

Vector4d result;
Avx.Store((double*)&result, v);
return result;
}

private Vector4d normal(Vector4d vector, double divisor)
=> new Vector4d(vector.X % divisor, vector.Y % divisor, vector.Z % divisor, vector.W % divisor);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using BenchmarkDotNet.Attributes;
using System.Numerics;
namespace MathSharp.Interactive.Benchmarks.Vector.Single
{
using Vector = MathSharp.Vector;
public class RemainderBenchmark
{
private Vector4 vec;

[GlobalSetup]
public void Setup()
{
vec = new Vector4(0, 1.2f, 1.6f, 3.2f);
}
[Benchmark]
public void Normal()
{
var result = normal(vec, 2);
}

[Benchmark]
public void MathSharp()
{
var result = mathSharp(vec, 2);
}

//Prevents the JIT from compiling Normal() away.
private Vector4 mathSharp(Vector4 vector, float divisor)
{
var v = vector.Load();
v = Vector.Remainder(v, divisor);
Vector.Store(v, out Vector4 result);
return result;
}

private Vector4 normal(Vector4 vector, float divisor)
=> new Vector4(vector.X % divisor, vector.Y % divisor, vector.Z % divisor, vector.W % divisor);
}
}
2 changes: 1 addition & 1 deletion samples/MathSharp.Interactive/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal class Program
{
private static void Main(string[] args)
{
BenchmarkRunner.Run<SinBenchmark>();
BenchmarkRunner.Run<RemainderBenchmark>();
}

private static readonly Vector3 Direction = new Vector3(1, 2, 3);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System.Runtime.CompilerServices;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
using MathSharp.Attributes;
using static MathSharp.Utils.Helpers;
using static MathSharp.SoftwareFallbacks;

namespace MathSharp
Expand All @@ -13,12 +15,12 @@ public static partial class Vector
{
#region Vector


[MethodImpl(MaxOpt)]
public static Vector4D Abs(in Vector4DParam1_3 vector)
public static Vector4D Abs(in Vector4DParam1_3 vector)
=> Max(Subtract(Vector4D.Zero, vector), vector);


[MethodImpl(MaxOpt)]
public static Vector4D HorizontalAdd(in Vector4DParam1_3 left, in Vector4DParam1_3 right)
{
Expand All @@ -30,7 +32,7 @@ public static Vector4D HorizontalAdd(in Vector4DParam1_3 left, in Vector4DParam1
return HorizontalAdd_Software(left, right);
}


[MethodImpl(MaxOpt)]
public static Vector4D Add(in Vector4DParam1_3 left, in Vector4DParam1_3 right)
{
Expand All @@ -42,12 +44,12 @@ public static Vector4D Add(in Vector4DParam1_3 left, in Vector4DParam1_3 right)
return Add_Software(left, right);
}


[MethodImpl(MaxOpt)]
public static Vector4D Add(in Vector4DParam1_3 vector, double scalar)
=> Add(vector, Vector256.Create(scalar));


[MethodImpl(MaxOpt)]
public static Vector4D Subtract(in Vector4DParam1_3 left, in Vector4DParam1_3 right)
{
Expand All @@ -59,12 +61,12 @@ public static Vector4D Subtract(in Vector4DParam1_3 left, in Vector4DParam1_3 ri
return Subtract_Software(left, right);
}


[MethodImpl(MaxOpt)]
public static Vector4D Subtract(in Vector4DParam1_3 vector, double scalar)
=> Subtract(vector, Vector256.Create(scalar));


[MethodImpl(MaxOpt)]
public static Vector4D Multiply(in Vector4DParam1_3 left, in Vector4DParam1_3 right)
{
Expand All @@ -91,16 +93,16 @@ public static Vector4D Divide(in Vector4DParam1_3 dividend, in Vector4DParam1_3
return Divide_Software(dividend, divisor);
}


[MethodImpl(MaxOpt)]
public static Vector4D Divide(in Vector4DParam1_3 dividend, double scalarDivisor)
=> Subtract(dividend, Vector256.Create(scalarDivisor));

public static Vector4D Clamp(in Vector4DParam1_3 vector, in Vector4DParam1_3 low, in Vector4DParam1_3 high)

public static Vector4D Clamp(in Vector4DParam1_3 vector, in Vector4DParam1_3 low, in Vector4DParam1_3 high)
=> Max(Min(vector, high), low);


[MethodImpl(MaxOpt)]
public static Vector4D Sqrt(in Vector4DParam1_3 vector)
{
Expand All @@ -112,7 +114,7 @@ public static Vector4D Sqrt(in Vector4DParam1_3 vector)
return Sqrt_Software(vector);
}


[MethodImpl(MaxOpt)]
public static Vector4D Max(in Vector4DParam1_3 left, in Vector4DParam1_3 right)
{
Expand All @@ -124,7 +126,7 @@ public static Vector4D Max(in Vector4DParam1_3 left, in Vector4DParam1_3 right)
return Max_Software(left, right);
}


[MethodImpl(MaxOpt)]
public static Vector4D Min(in Vector4DParam1_3 left, in Vector4DParam1_3 right)
{
Expand All @@ -145,21 +147,55 @@ public static HwVector3D Negate(HwVector3D vector)
public static HwVector4D Negate(HwVector4D vector)
=> Negate4D(vector);


[MethodImpl(MaxOpt)]
public static Vector4D Negate2D(in Vector4DParam1_3 vector)
public static Vector4D Negate2D(in Vector4DParam1_3 vector)
=> Xor(vector, SignFlip2DDouble);


[MethodImpl(MaxOpt)]
public static Vector4D Negate3D(in Vector4DParam1_3 vector)
=> Xor(vector, SignFlip3DDouble);


[MethodImpl(MaxOpt)]
public static Vector4D Negate4D(in Vector4DParam1_3 vector)
=> Xor(vector, SignFlip4DDouble);

[MethodImpl(MaxOpt)]
public static Vector4D Remainder(in Vector4DParam1_3 left, in Vector4DParam1_3 right)
{
var n = Divide(left, right);
n = Truncate(n);

var y = Multiply(n, right);

return Subtract(left, y);
}

public static Vector4D Remainder(in Vector4DParam1_3 left, double right)
=> Remainder(left, Vector256.Create(right));

[MethodImpl(MaxOpt)]
public static Vector4D Truncate(in Vector4DParam1_3 vector)
{
if (Avx.IsSupported)
{
return Avx.RoundToZero(vector);
}

return SoftwareFallback(vector);

static Vector4D SoftwareFallback(in Vector4DParam1_3 vector)
{
return Vector256.Create(
Math.Truncate(X(vector)),
Math.Truncate(Y(vector)),
Math.Truncate(Z(vector)),
Math.Truncate(W(vector))
);
}
}
#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,20 @@ public static Vector4F Sin(in Vector4FParam1_3 vector)
return result;
}

[MethodImpl(MaxOpt)]
public static Vector4F Remainder(in Vector4FParam1_3 left, in Vector4FParam1_3 right)
{
var n = Divide(left, right);
n = Truncate(n);

var y = Multiply(n, right);

return Subtract(left, y);
}

public static Vector4F Remainder(in Vector4FParam1_3 left, float right)
=> Remainder(left, Vector128.Create(right));

private static readonly Vector4F OneDiv2Pi = Vector128.Create(SingleConstants.OneDiv2Pi);
private static readonly Vector4F Pi2 = Vector128.Create(SingleConstants.Pi2);
private static readonly Vector4F Pi = Vector128.Create(SingleConstants.Pi);
Expand All @@ -285,7 +299,6 @@ public static Vector4F Mod2Pi(in Vector4FParam1_3 vector)

return Subtract(vector, result);
}

[MethodImpl(MaxOpt)]
public static Vector4F Round(in Vector4FParam1_3 vector)
{
Expand All @@ -309,6 +322,27 @@ static Vector4F SoftwareFallback(in Vector4FParam1_3 vector)
}
}

[MethodImpl(MaxOpt)]
public static Vector4F Truncate(in Vector4FParam1_3 vector)
{
if (Sse41.IsSupported)
{
return Sse41.RoundToZero(vector);
}

return SoftwareFallback(vector);

static Vector4F SoftwareFallback(in Vector4FParam1_3 vector)
{
return Vector128.Create(
MathF.Truncate(X(vector)),
MathF.Truncate(Y(vector)),
MathF.Truncate(Z(vector)),
MathF.Truncate(W(vector))
);
}
}

#endregion
}
}
16 changes: 16 additions & 0 deletions tests/MathSharp.UnitTests/Helpers/TestHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
using static MathSharp.Utils.Helpers;
using MathSharp.Utils;
using OpenTK;
using Vec2 = System.Numerics.Vector2;
using Vec3 = System.Numerics.Vector3;
using Vec4 = System.Numerics.Vector4;

namespace MathSharp.UnitTests
{
Expand Down Expand Up @@ -57,10 +60,23 @@ public static bool AreEqual(Vector3 left, Vector128<float> right)
public static bool AreEqual(Vector2 left, Vector128<float> right)
=> left.X.Equals(X(right)) && left.Y.Equals(Y(right));

[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static bool AreEqual(Vec4 left, Vector128<float> right)
=> left.X.Equals(X(right)) && left.Y.Equals(Y(right)) && left.Z.Equals(Z(right)) && left.W.Equals(W(right));

[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static bool AreEqual(Vec3 left, Vector128<float> right)
=> left.X.Equals(X(right)) && left.Y.Equals(Y(right)) && left.Z.Equals(Z(right));

[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static bool AreEqual(Vec2 left, Vector128<float> right)
=> left.X.Equals(X(right)) && left.Y.Equals(Y(right));

[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static bool AreEqual(float left, Vector128<float> right)
=> left.Equals(X(right));


[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static bool AreApproxEqual(float left, float right, float interval = 0.000000001f)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using OpenTK;
using System;
using System.Collections.Generic;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
using System.Text;
using Xunit;
using Xunit.Abstractions;

namespace MathSharp.UnitTests.VectorTests.VectorDouble.BasicMathsTests
{
public class Remainder
{
public static IEnumerable<object[]> Data =>
new[]
{
new object[] { new Vector4d(10.4f), new Vector4d(2f) },
new object[] { new Vector4d(-10.4f), new Vector4d(2f) },
new object[] { new Vector4d(float.NaN, float.MinValue, float.MaxValue, float.PositiveInfinity), new Vector4d(3f) },
new object[] { new Vector4d(float.NaN, float.MinValue, float.MaxValue, float.PositiveInfinity), new Vector4d(2.4f) },
new object[] { new Vector4d(23.45f), new Vector4d(219f) },
new object[] { new Vector4d(12), new Vector4d(float.NaN) },
new object[] { new Vector4d(-10000000f), new Vector4d(2.2f) },
new object[] { new Vector4d(10000000f), new Vector4d(2.2f) },
new object[] { new Vector4d(float.NegativeInfinity), new Vector4d(3f) }
};

[Theory]
[MemberData(nameof(Data))]
public unsafe void Remainder_Theory(Vector4d left, Vector4d right)
{
var l = Avx.LoadAlignedVector256((double*)&left);
var r = Avx.LoadAlignedVector256((double*)&right);

var remainder = Vector.Remainder(l, r);
var expected = new Vector4d(left.X % right.X, left.Y % right.Y, left.Z % right.Z, left.W % right.W);

TestHelpers.AreEqual(expected, remainder);
}
}
}

0 comments on commit 75ce8f8

Please sign in to comment.