Я все еще пытаюсь найти быстрый способ преобразования универсального массива типа TOutput в другой массив типа TInput. Все мои массивы всегда имеют числовой тип данных, но, поскольку C# не имеет ограничения типа Numeric, как часто требуется, мне в настоящее время приходится жить с этим ограничением. Предлагаемые методы, такие как приведение к объекту ранее, похоже, сильно замедляют приведение. В настоящее время у меня есть большая конструкция if/else, которая проверяет тип и приводит к определенному типу, используя арифметику указателя, но это слишком большой способ для обработки в будущем. Parallel.For кажется хорошим способом избавиться от указателей и ускорить работу, но все же общие ограничения C # кажутся проблемой, но Tout в приведенном ниже коде все же является проблемой. Вот мой код:
public static OutputType[] Cast<InputType, OutputType>(InputType[] inputArray_in)
{
var aRange = Partitioner.Create(0, inputArray_in.Length);
OutputType[] aResult = new OutputType[inputArray_in.Length];
Parallel.ForEach(aRange, (r) =>
{
for (int i = r.Item1; i < r.Item2; i++)
{
aResult[i] = (OutputType)(inputArray_in[i]);
}
});
return aResult;
}
Пример:
float[] A = { 0.1f, 0.2f, 0.6f };
int []B = Cast<float, int>(A);
Во всех случаях мои типы массивов представляют собой числовые значения (с плавающей запятой, короткие, двойные,...), и в большинстве случаев массивы представляют собой изображения размером 512x512, но в стеке около 1000 ломтиков в объеме. Видите ли вы какой-либо шанс иметь простой способ выполнить это?
Тестовый код
public static class CastTest
{
delegate double[] CastMethod(int[] input);
public static unsafe double[] Cast1(int[] input)
{
int N = input.Length;
double[] output = new double[N];
for (int i = 0; i < N; i++) output[i] = (double)(input[i]);
return output;
}
public static unsafe double[] Cast2(int[] input)
{
int N = input.Length;
double[] output = new double[N];
fixed (double* output_pinned = output)
{
double* outp = output_pinned;
fixed (int* input_pinned = input)
{
int* inp = input_pinned;
for (int i = 0; i < N; i++, inp++, outp++) *outp = (double)(*inp);
}
return output;
}
}
public static unsafe double[] Cast3(int[] input)
{
int N = input.Length;
double[] output = new double[N];
fixed (double* output_pinned = output)
{
double* outp = output_pinned;
fixed (int* input_pinned = input)
{
int* inp = input_pinned;
for (int i = 0; i < N; i++) outp[i] = (double)(inp[i]);
}
return output;
}
}
public static unsafe double[] Cast4(int[] input)
{
int N = input.Length;
double[] output = new double[N];
fixed (double* output_pinned = output)
{
fixed (int* input_pinned = input)
{
for (int i = 0; i < N; i++) output_pinned[i] = (double)(input_pinned[i]);
}
}
return output;
}
public static unsafe double[] Cast5(int[] input)
{
return Array.ConvertAll<int, double>(input, x => (double)x);
}
public static double[] Cast6(int[] input)
{
var aRange = Partitioner.Create(0, input.Length);
int N = input.Length;
double[] output = new double[N];
Parallel.ForEach(aRange, (r) =>
{
for (int i = r.Item1; i < r.Item2; i++) output[i] = (double)(input[i]);
});
return output;
}
public unsafe static double[] Cast7(int[] input)
{
var aRange = Partitioner.Create(0, input.Length);
int N = input.Length;
double[] output = new double[N];
Parallel.ForEach(aRange, (r) =>
{
fixed (double* output_pinned = output)
{
double* outp = output_pinned + r.Item1;
fixed (int* input_pinned = input)
{
int* inp = input_pinned + r.Item1;
for (int i = r.Item1; i < r.Item2; i++, outp++, inp++) *outp = (double)(*inp);
}
}
});
return output;
}
public unsafe static double[] Cast8(int[] input)
{
var result = (from m in input.AsParallel() select (double)m).ToArray();
return result;
}
public static double[] Cast9(int[] input)
{
return (from m in input select (double)m).ToArray();
}
public static double[] Cast10(int[] input)
{
return (from m in input.AsParallel() select (double)m).ToArray();
}
public static double[] Cast11(int[] input)
{
return new List<double>(input.Select(p => (double)p)).ToArray();
}
static int[] A = new int[100000];
const int runs = 10000;
public static void StartTest()
{
TestMethod("1", Cast1);
TestMethod("2", Cast2);
TestMethod("3", Cast3);
TestMethod("4", Cast4);
TestMethod("5", Cast5);
TestMethod("6", Cast6);
TestMethod("7", Cast7);
TestMethod("8", Cast8);
TestMethod("9", Cast9);
TestMethod("10", Cast10);
TestMethod("11", Cast11);
}
static void TestMethod(string Name, CastMethod method)
{
var timer = Stopwatch.StartNew();
for (int i = 0; i < runs; i++) { double[] res = method(A); }
timer.Stop();
Console.WriteLine(String.Format("{0}: {1}ms", Name, timer.ElapsedMilliseconds));
}
}
Спасибо. Мартин