Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
unsafe public static int ToInt(string s)
{
if (s == null)
{
throw new ArgumentException();
}
int sign = 1, n = 0;
fixed(char * p = s)
{
char * pS = p;
while (*pS < ' ') pS++;
switch(*pS)
{
case '-':
sign = -1;
case '+':
ps++;
}
while (*pS >= '0' && *pS <= '9')
n = 10 * n + *(pS++) - '0';
}
return sign * n;
}
unsafe public static int ToIntNotMy(string s)
{
if (s == null)
{
throw new ArgumentException();
}
int sign = 1, n = 0;
fixed (char* p = s)
{
char* pS = p;
while (*pS == ' ') pS++;
switch (*pS)
{
case '-':
sign = -1;
pS++;
break;
case '+':
pS++;
break;
case '\0':
throw new ArgumentException();
}
while (*pS >= '0' && *pS <= '9')
n = 10 * n + *(pS++) - '0';
if (*pS != '\0') throw new ArgumentException();
}
return sign * n;
}
unsafe public static int ToIntNotMy(string s)
{
if (s == null)
throw new ArgumentException();
int sign = 1, n = 0;
fixed (char* p = s)
{
char* pS = p;
switch (*pS)
{
case '-':
sign = -1;
case '+':
pS++;
}
while (*pS >= '0' && *pS <= '9')
n = 10 * n + *(pS++) - '0';
if (*pS != '\0') throw new ArgumentException();
}
return sign * n;
}
if (*pS != '\0')
Помогал на днях одной своей знакомой разобраться в программировании
Я считал, что компилятор (или же CLR) сможет понять, что так как внутри цикла мы не изменяем переменную s, то значение s.Length будет получено только один раз.
А на самом деле строка может быть изменена(к примеру StringBuilder изменяет строки).
т.е. это вполне «нормальная» конструкция к сишарпе, а не «еще и unsafe».
internal static unsafe void wstrcpy(char* dmem, char* smem, int charCount)
а вот ссылка может внезапно начать указывать на другой объект
CLR не знает, что String — immutable
CLR именно для строк должна поддерживать специальную оптимизацию
MyConvert.ToInt( int.MinValue.ToString() )
unsafe public static int ToInt(string s)
{
....
result = result * 10 - (ch - '0');
.....
return (isNegative) ? result : -result;
}
using System;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
const int count = 100000000;
var test = int.MinValue.ToString();
var res = default(int);
res = int.Parse(test, NumberStyles.Integer);
Console.WriteLine(res);
var stopwatch = Stopwatch.StartNew();
foreach (var _ in Enumerable.Range(0, count))
{
res = int.Parse(test);
}
stopwatch.Stop();
Console.WriteLine(res);
Console.WriteLine("int.Parse: {0} ms", stopwatch.ElapsedMilliseconds);
res = ToInt(test);
Console.WriteLine(res);
stopwatch = Stopwatch.StartNew();
foreach (var _ in Enumerable.Range(0, count))
{
res = ToInt(test);
}
stopwatch.Stop();
Console.WriteLine(res);
Console.WriteLine("ToInt: {0} ms", stopwatch.ElapsedMilliseconds);
Console.ReadKey();
}
unsafe public static int ToInt(string s)
{
if (s == null)
{
throw new ArgumentException();
}
int result = 0;
bool isNegative = false;
fixed (char* p = s)
{
char* chPtr = p;
char ch = *(chPtr++);
switch (ch)
{
case '-':
isNegative = true;
ch = *(chPtr++);
break;
case '+':
ch = *(chPtr++);
break;
}
do
{
if (ch < '0' || ch > '9')
{
throw new ArgumentException();
}
result = result * 10 + (ch - '0');
ch = *(chPtr++);
} while (ch != '\0');
}
return (isNegative) ? -result : result;
}
}
}
using System;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main()
{
string test = -2147483648.ToString();
int res = 0;
res = int.Parse(test, NumberStyles.Integer);
Console.WriteLine(res);
Stopwatch stopwatch = Stopwatch.StartNew();
foreach (int arg_3F_0 in Enumerable.Range(0, 100000000))
{
res = int.Parse(test);
}
stopwatch.Stop();
Console.WriteLine(res);
Console.WriteLine("int.Parse: {0} ms", stopwatch.ElapsedMilliseconds);
res = Program.ToInt(test);
Console.WriteLine(res);
stopwatch = Stopwatch.StartNew();
foreach (int arg_AD_0 in Enumerable.Range(0, 100000000))
{
res = Program.ToInt(test);
}
stopwatch.Stop();
Console.WriteLine(res);
Console.WriteLine("ToInt: {0} ms", stopwatch.ElapsedMilliseconds);
Console.ReadKey();
}
public unsafe static int ToInt(string s)
{
if (s == null)
{
throw new ArgumentException();
}
int result = 0;
bool isNegative = false;
fixed (char* p = s)
{
char* chPtr = p;
char* expr_20 = chPtr;
chPtr = expr_20 + (IntPtr)2 / 2;
char ch = *expr_20;
switch (ch)
{
case '+':
{
char* expr_52 = chPtr;
chPtr = expr_52 + (IntPtr)2 / 2;
ch = *expr_52;
break;
}
case '-':
{
isNegative = true;
char* expr_47 = chPtr;
chPtr = expr_47 + (IntPtr)2 / 2;
ch = *expr_47;
break;
}
}
while (ch >= '0' && ch <= '9')
{
result = result * 10 + (int)(ch - '0');
char* expr_78 = chPtr;
chPtr = expr_78 + (IntPtr)2 / 2;
ch = *expr_78;
if (ch == '\0')
{
string text = null;
if (!isNegative)
{
return result;
}
return -result;
}
}
throw new ArgumentException();
}
}
}
}
Все равно для серьезных целей, вроде парсинга языка программирования, разборщики чисел из стандартной библиотеки плохо подходят. Они капризные, их поведение меняется от версии к версии и стандартом жестко не задано; отсутствует диагностика ошибок.
Один знакомый программист, который разрабатывает серверное п/о, рассказывал, что ему приходится оптимизировать парсеры текста вплоть до перевода их на ассемблер с использованием SIMD-инструкций. Что такая оптимизация дает существенный прирост быстродействия, и для серверного п/о это важно.
Вдобавок, когда ввели интернационализацию формата чисел в стандартных библиотеках — это сломало мои программы загрузки данных из текстовых файлов или разбора командной строки. Пришлось все перекомпилировать, вставляя где надо инициализацию национального формата чисел.
static int ToInt(string x) {
bool qd=true;
int n=0,s=-5,qs=1;
foreach(char c in x) {
int m=c-'0';
if((uint)m<10) {
n=(n*10+m);
qd=false;
} else s=m*qs;
qs=0;
}
if(qd || (s!=-3 && s!=-5)) throw new ArgumentException();
return (-4-s)*n;
}
Конвертация строки в число