Ответ 1
Я думаю, что ваша реализация довольно приличная. Я сделал небезопасную версию, используя математику указателя, которая действительно быстрее, но, по-моему, более грязная.
Результаты (выполняется 30 выборок 10 М случайных целых строк):
Int32.Parse 1766.17 ms (stddev: 1.83 ms)
Numbers.Int32.ParseTrusted 262.07 ms (stddev: 0.44 ms)
ParseTrustedUnsafe 146.13 ms (stddev: 0.43 ms)
вот моя небезопасная реализация:
public static unsafe int ParseTrustedUnsafe(string str, int start, int end)
{
unsafe
{
Int32 result = 0;
Int32 length = end - start;
Boolean isNegative = false;
fixed (Char* startChar = str)
{
Byte* currentChar = ((Byte*)startChar) + (start * 2);
if (*currentChar == 0x2D)
{
isNegative = true;
currentChar += 2;
length--;
}
else if (*currentChar == 0x2B)
{
currentChar += 2;
length--;
}
while (length >= 4)
{
result = (result * 10) + (*currentChar - 0x30);
result = (result * 10) + (*(currentChar + 2) - 0x30);
result = (result * 10) + (*(currentChar + 4) - 0x30);
result = (result * 10) + (*(currentChar + 6) - 0x30);
currentChar += 8;
length -= 4;
}
while (length > 0)
{
result = (result * 10) + (*currentChar - 0x30);
currentChar += 2;
length -= 1;
}
}
return isNegative ? -result : result;
}
}
Ниже приведена моя программа проверки и проверки:
static void Main(string[] args)
{
String[] testValues = new String[10 * 100 * 100 * 100];
Random rand = new Random();
for (int i = 0; i < testValues.Length; i++)
{
testValues[i] = rand.Next().ToString();
}
// validate
for (int i = 0; i < testValues.Length; i++)
{
Debug.Assert(String.CompareOrdinal(testValues[i], ParseTrustedUnsafe(testValues[i], 0, testValues[i].Length).ToString()) == 0, "ParseTrustedUnsafe failed on " + testValues[i]);
Debug.Assert(String.CompareOrdinal(testValues[i], Numbers.Int32.ParseTrusted(testValues[i], 0, testValues[i].Length).ToString()) == 0, "Numbers.Int32.ParseTrusted failed on " + testValues[i]);
}
#if DEBUG
return;
#endif
List<List<Double>> results = new List<List<double>>();
for (int i = 0; i < 3; i++)
{
results.Add(new List<double>());
}
Thread.CurrentThread.Priority = ThreadPriority.Highest;
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime;
if (Environment.ProcessorCount > 1)
{
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1 << (Environment.ProcessorCount - 1)); // use last core only
}
Stopwatch sw = new Stopwatch();
for (int testrun = 0; testrun < 30; testrun++)
{
sw.Reset();
sw.Start();
for (int i = 0; i < testValues.Length; i++)
{
Int32.Parse(testValues[i]);
}
sw.Stop();
results[0].Add(sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
for (int i = 0; i < testValues.Length; i++)
{
Numbers.Int32.ParseTrusted(testValues[i]);
}
sw.Stop();
results[1].Add(sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
for (int i = 0; i < testValues.Length; i++)
{
ParseTrustedUnsafe(testValues[i], 0, testValues[0].Length);
}
sw.Stop();
results[2].Add(sw.ElapsedMilliseconds);
}
Console.WriteLine("Int32.Parse \t\t\t {0:0.00}ms (stddev: {1:0.00}ms)", results[0].Average(), StandardDeviation(results[0]));
Console.WriteLine("Numbers.Int32.ParseTrusted \t {0:0.00}ms (stddev: {1:0.00}ms)", results[1].Average(), StandardDeviation(results[1]));
Console.WriteLine("ParseTrustedUnsafe \t\t {0:0.00}ms (stddev: {1:0.00}ms)", results[2].Average(), StandardDeviation(results[2]));
}
private static double StandardDeviation(IEnumerable<double> doubleList)
{
double average = doubleList.Average();
double sumOfDerivation = 0;
foreach (double value in doubleList)
{
sumOfDerivation += (value) * (value);
}
double sumOfDerivationAverage = sumOfDerivation / doubleList.Count();
return Math.Sqrt(sumOfDerivationAverage - (average * average));
}