Skip to content

Commit

Permalink
VectorHelper.ReduceMinMax
Browse files Browse the repository at this point in the history
  • Loading branch information
gfoidl committed Apr 19, 2018
1 parent 3b26dee commit 1a2a603
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 5 deletions.
6 changes: 1 addition & 5 deletions source/gfoidl.Stochastics/Statistics/Sample.MinMax.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,7 @@ private unsafe (double min, double max) GetMinMaxImpl((int start, int end) range
}

// Reduction
for (int j = 0; j < Vector<double>.Count; ++j)
{
if (minVec[j] < min) min = minVec[j];
if (maxVec[j] > max) max = maxVec[j];
}
VectorHelper.ReduceMinMax(minVec, maxVec, ref min, ref max);
}

for (; i < n; ++i)
Expand Down
45 changes: 45 additions & 0 deletions source/gfoidl.Stochastics/VectorHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,50 @@ public static double ReduceSum(this Vector<double> vector)
#endif
return Vector.Dot(Vector<double>.One, vector);
}
//---------------------------------------------------------------------
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ReduceMinMax(Vector<double> minVec, Vector<double> maxVec, ref double min, ref double max)
{
#if NETCOREAPP2_1
if (Avx.IsSupported && Sse2.IsSupported && 256 / 8 == sizeof(double) * Vector<double>.Count)
{
min = MinMaxCore(minVec, true);
max = MinMaxCore(maxVec, false);
return;
}
#endif
for (int j = 0; j < Vector<double>.Count; ++j)
{
if (minVec[j] < min) min = minVec[j];
if (maxVec[j] > max) max = maxVec[j];
}
}
//---------------------------------------------------------------------
#if NETCOREAPP2_1
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double MinMaxCore(Vector<double> vector, bool doMin)
{
Vector256<double> vec256 = Unsafe.As<Vector<double>, Vector256<double>>(ref vector);
Vector128<double> hi128 = Avx.ExtractVector128(vec256, 1);
Vector128<double> lo128 = Avx.ExtractVector128(vec256, 0);
Vector128<double> tmp1 = Avx.Permute(hi128, 0b_01);
Vector128<double> tmp2 = Avx.Permute(lo128, 0b_01);

if (doMin)
{
hi128 = Sse2.Min(hi128, tmp1);
lo128 = Sse2.Min(lo128, tmp2);
lo128 = Sse2.Min(lo128, hi128);
}
else
{
hi128 = Sse2.Max(hi128, tmp1);
lo128 = Sse2.Max(lo128, tmp2);
lo128 = Sse2.Max(lo128, hi128);
}

return Sse2.ConvertToDouble(lo128);
}
#endif
}
}
40 changes: 40 additions & 0 deletions tests/gfoidl.Stochastics.Tests/VectorHelperTests/ReduceMinMax.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Numerics;
using NUnit.Framework;

namespace gfoidl.Stochastics.Tests.VectorHelperTests
{
[TestFixture]
public class ReduceMinMax
{
[Test, Repeat(10)]
public void Min_Max_Vectors_given___correct_Min_Max()
{
var rnd = new Random();
var minArr = new double[Vector<double>.Count];
var maxArr = new double[Vector<double>.Count];
double min = double.MaxValue;
double max = double.MinValue;

for (int j = 0; j < Vector<double>.Count; ++j)
{
minArr[j] = rnd.NextDouble();
maxArr[j] = rnd.NextDouble();

if (minArr[j] < min) min = minArr[j];
if (maxArr[j] > max) max = maxArr[j];
}

double expectedMin = min;
double expectedMax = max;

var minVec = new Vector<double>(minArr);
var maxVec = new Vector<double>(maxArr);

VectorHelper.ReduceMinMax(minVec, maxVec, ref min, ref max);

Assert.AreEqual(expectedMin, min, 1e-10);
Assert.AreEqual(expectedMax, max, 1e-10);
}
}
}

0 comments on commit 1a2a603

Please sign in to comment.