Beispiel #1
0
        public unsafe Tuple <int, int> MinMaxSse()
        {
            var vmin    = Vector128.Create(int.MaxValue);
            var vmax    = Vector128.Create(int.MinValue);
            int vecSize = Vector128 <int> .Count;

            fixed(int *pNumbers = numbers)
            {
                int i;

                for (i = 0; i < numbers.Length; i += vecSize)
                {
                    var d = Sse42.LoadVector128(pNumbers + i);
                    vmin = Sse42.Min(vmin, d);
                    vmax = Sse42.Max(vmax, d);
                }

                // tail is pretty much irrelevant
                int tailLen = (numbers.Length % vecSize);

                for (i = 0; i < tailLen; ++i)
                {
                    var d = Sse42.LoadScalarVector128(pNumbers + numbers.Length - i - 1);
                    vmin = Sse42.Min(vmin, d);
                    vmax = Sse42.Max(vmax, d);
                }
            }

            int min = int.MaxValue, max = int.MinValue;

            for (int i = 0; i < vecSize; ++i)
            {
                min = Math.Min(min, vmin.GetElement(i));
                max = Math.Max(max, vmax.GetElement(i));
            }

            return(new Tuple <int, int>(min, max));
        }
        private static unsafe int CalculateDistance(string sourceString, int sourceLength, string targetString, int targetLength, int startIndex)
        {
            var                 arrayPool   = ArrayPool <ushort> .Shared;
            var                 pooledArray = arrayPool.Rent(targetLength);
            Span <ushort>       previousRow = pooledArray;
            ReadOnlySpan <char> source      = sourceString.AsSpan().Slice(startIndex, sourceLength);
            ReadOnlySpan <char> target      = targetString.AsSpan().Slice(startIndex, targetLength);

            //ArrayPool values are sometimes bigger than allocated, let's trim our span to exactly what we use
            previousRow = previousRow.Slice(0, targetLength);

            fixed(char *targetPtr = target)
            fixed(char *srcPtr           = source)
            fixed(ushort *previousRowPtr = previousRow)
            {
                FillRow(previousRowPtr, targetLength);

                var rowIndex = 0;

                for (; rowIndex < sourceLength - 7; rowIndex += 8)
                {
                    // todo max
                    var temp = Vector128.Create(rowIndex);
                    var diag = Sse42.PackUnsignedSaturate(temp, temp);
                    var one  = Vector128.Create((ushort)1);
                    var left = Sse42.AddSaturate(diag, one);

                    var sourceV = Sse42.LoadVector128((ushort *)(srcPtr + rowIndex));
                    var targetV = Vector128 <ushort> .Zero;

                    var shift = Vector128.CreateScalar(ushort.MaxValue);
                    // First 3  iterations fills the vector
                    for (int columnIndex = 0; columnIndex < 7; columnIndex++)
                    {
                        // Shift in the next character
                        targetV = Sse42.ShiftLeftLogical128BitLane(targetV, 2);
                        targetV = Sse42.Insert(targetV, (ushort)targetPtr[columnIndex], 0);

                        // Insert "(rowIndex + columnIndex + 1)" from the left
                        var leftValue = Vector128.Create(rowIndex + columnIndex + 1);
                        left  = Sse42.Or(Sse42.And(shift, Sse42.PackUnsignedSaturate(leftValue, leftValue)), left);
                        shift = Sse42.ShiftLeftLogical128BitLane(shift, 2);

                        // compare source to target
                        // alternativ, compare equal and OR with One
                        var match = Sse42.CompareEqual(sourceV, targetV);
                        var add   = Sse42.AndNot(match, one);
                        var next  = Sse42.AddSaturate(diag, add);

                        // Create next diag which is current up
                        var up = Sse42.ShiftLeftLogical128BitLane(left, 2);
                        up = Sse42.Insert(up, (ushort)previousRowPtr[columnIndex], 0);

                        var tmp = Sse42.AddSaturate(Sse42.Min(left, up), one);
                        next = Sse42.Min(next, tmp);

                        left = next;
                        diag = up;
                    }

                    previousRowPtr[0] = Sse42.Extract(left, 7);
                    var writePtr = previousRowPtr + 1;
                    for (int columnIndex = 8; columnIndex < targetLength; columnIndex++)
                    {
                        // Shift in the next character
                        targetV = Sse42.ShiftLeftLogical128BitLane(targetV, 2);
                        targetV = Sse42.Insert(targetV, (ushort)targetPtr[columnIndex], 0);

                        // compare source to target
                        // alternativ, compare equal and OR with One
                        var match = Sse42.CompareEqual(sourceV, targetV);
                        var add   = Sse42.AndNot(match, one);
                        var next  = Sse42.AddSaturate(diag, add);

                        // Create next diag which is current up
                        var up = Sse42.ShiftLeftLogical128BitLane(left, 2);
                        up = Sse42.Insert(up, (ushort)previousRowPtr[columnIndex], 0);

                        var tmp = Sse42.AddSaturate(Sse42.Min(left, up), one);
                        next = Sse42.Min(next, tmp);

                        left = next;
                        diag = up;

                        // Store one value
                        *writePtr = Sse42.Extract(next, 7);
                        writePtr = writePtr + 1;

                        // Store one value
                        //previousRowPtr[columnIndex - 7] = Sse42.Extract(next, 7);
                    }

                    // Finish with last 3 items, dont read any more chars just extract them
                    for (int i = targetLength - 7; i < previousRow.Length; i++)
                    {
                        // Shift in the next character
                        targetV = Sse42.ShiftLeftLogical128BitLane(targetV, 2);

                        // compare source to target
                        // alternativ, compare equal and OR with One
                        var match = Sse42.CompareEqual(sourceV, targetV);
                        var add   = Sse42.AndNot(match, one);
                        var next  = Sse42.AddSaturate(diag, add);

                        // Create next diag which is current up
                        var up = Sse42.ShiftLeftLogical128BitLane(left, 2);

                        var tmp = Sse42.AddSaturate(Sse42.Min(left, up), one);
                        next = Sse42.Min(next, tmp);

                        left = next;
                        diag = up;
                        // Store one value
                        previousRowPtr[i] = Sse42.Extract(next, 7);
                    }

#if DEBUG
                    if (true)
                    {
                        Console.Write("prev values for row {0}:", rowIndex);
                        for (int i = 0; i < targetLength; ++i)
                        {
                            Console.Write("{0} ", previousRow[i]);
                        }
                        Console.WriteLine();
                    }
#endif
                }

                //Calculate Single Rows
                for (; rowIndex < sourceLength; rowIndex++)
                {
                    var lastSubstitutionCost = rowIndex;
                    var lastInsertionCost    = rowIndex + 1;
                    var sourcePrevChar       = source[rowIndex];
#if DEBUG
                    Console.Write("prev values for row {0}:", rowIndex);
                    for (int i = 0; i < targetLength; ++i)
                    {
                        Console.Write("{0} ", previousRow[i]);
                    }
                    Console.WriteLine();
#endif

                    CalculateRow(previousRowPtr, targetPtr, targetLength, sourcePrevChar, lastInsertionCost, lastSubstitutionCost);
                }
            }

            var result = previousRow[targetLength - 1];
            arrayPool.Return(pooledArray);
            return(result);
        }