StrToInt на чистом паскале.

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

StrToInt на чистом паскале.

Сообщение Seenkao » 10.01.2022 18:19:54

Всем привет!

Потестируйте! :) Нужно выявлять ошибки в модуле. Чтоб им можно было пользоваться всем.

:idea: fast_StrToInt. :idea:

Внимание! Данная библиотека направлена на скорость работы и по возможности для совместимости с разными архитектурами. :)

Зачем я это сделал? Функция быстрее работает на процессорах x86 чуть менее чем в два раза, на процессорах ARM быстрее, но я не помню насколько. А так как зачастую в программах используется перевод строковых значений в числа, то я думаю это немалый прирост в скорости.

плюсы (+): быстрее скорость работы, сделано на чистом паскале, подойдёт для любой платформы (в данном варианте рассматривается x86/ARM - 32/64 битные. Функция не вылетит с ошибкой! Результат функции булева переменная сообщающая успешен был перевод или нет, сам результат сохраняется в переменной (модуль ge_external_Utils).

минусы (-): возможно не совсем удобная работа с данной функцией, не включён перевод двоичной, восьмеричной и шестнадцатеричной систем (по сути сделать недолго, добавить пару исключений).

примеры использования в программе. Сама функция geStrToInt в соседнем модуле. Пример сделан для разных систем Linux/Windows (возможно и MacOS но не совсем уверен в дефайнах).

Модуль предоставляет 19 (38) пользовательских функций, основанных на трёх (шести) основных:
Код: Выделить всё
(* Rus: Ниже реализованы стандартные функции для перевода строк в число. Их
*      использование будет проще для большинства. Функции отмечены префиксом.
*      s_ - функции возвращают результат (если операция была неудачной, то
*      в результате вернётся ноль, но вы не узнаете, что операция была неудачной).
*      sc_ - результат функций удачная или не удачная была операция. Сам
*      конечный числовой результат считывайте в Value.
*)
// sc_ - speed + check
// s_ - speed (not check)

// Rus: Числа со знаком. Здесь нельзя использовать шестнадцатеричные, восьмеричные
//      и двоичные числа.
{$IfNDef UNICODESTRING_ONLI}
function sc_StrToShortInt(const Str: useString; out Value: ShortInt): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}   // byte
function s_StrToShortInt(const Str: useString): ShortInt; {$IfDef ADD_FAST}inline;{$EndIf}                        // byte
function sc_StrToSmallInt(const Str: useString; out Value: SmallInt): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}   // word
function s_StrToSmallInt(const Str: useString): SmallInt; {$IfDef ADD_FAST}inline;{$EndIf}                        // word
function sc_StrToInt(const Str: useString; out Value: Integer): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToInt(const Str: useString): Integer; {$IfDef ADD_FAST}inline;{$EndIf}
function sc_StrToInt64(const Str: useString; out Value: Int64): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToInt64(const Str: useString): Int64; {$IfDef ADD_FAST}inline;{$EndIf}

{$IfDef USE_UNICODESTRING}
function sc_StrToShortInt(const Str: UnicodeString; out Value: ShortInt): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}   // byte
function s_StrToShortInt(const Str: UnicodeString): ShortInt; {$IfDef ADD_FAST}inline;{$EndIf}                        // byte
function sc_StrToSmallInt(const Str: UnicodeString; out Value: SmallInt): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}   // word
function s_StrToSmallInt(const Str: UnicodeString): SmallInt; {$IfDef ADD_FAST}inline;{$EndIf}                        // word
function sc_StrToInt(const Str: UnicodeString; out Value: Integer): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToInt(const Str: UnicodeString): Integer; {$IfDef ADD_FAST}inline;{$EndIf}
function sc_StrToInt64(const Str: UnicodeString; out Value: Int64): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToInt64(const Str: UnicodeString): Int64; {$IfDef ADD_FAST}inline;{$EndIf}

// Rus: Числа без знака. Эти функции могут использоваться и для шестнадцатеричныи
//      и восьмеричных и двоичных чисел.  Данные функции не должны содержать
//      ведущие нули для десятеричной системы счисления.
{$IfNDef UNICODESTRING_ONLI}
function sc_StrToByte(const Str: useString; out Value: Byte): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToByte(const Str: useString): Byte; {$IfDef ADD_FAST}inline;{$EndIf}
function sc_StrToWord(const Str: useString; out Value: Word): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToWord(const Str: useString): Word; {$IfDef ADD_FAST}inline;{$EndIf}
function sc_StrToLongWord(const Str: useString; out Value: LongWord): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToLongWord(const Str: useString): LongWord; {$IfDef ADD_FAST}inline;{$EndIf}
function sc_StrToQWord(const Str: useString; out Value: QWord): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToQWord(const Str: useString): QWord; {$IfDef ADD_FAST}inline;{$EndIf}

{$IfDef USE_UNICODESTRING}
function sc_StrToByte(const Str: UnicodeString; out Value: Byte): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToByte(const Str: UnicodeString): Byte; {$IfDef ADD_FAST}inline;{$EndIf}
function sc_StrToWord(const Str: UnicodeString; out Value: Word): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToWord(const Str: UnicodeString): Word; {$IfDef ADD_FAST}inline;{$EndIf}
function sc_StrToLongWord(const Str: UnicodeString; out Value: LongWord): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToLongWord(const Str: UnicodeString): LongWord; {$IfDef ADD_FAST}inline;{$EndIf}
function sc_StrToQWord(const Str: UnicodeString; out Value: QWord): Boolean; {$IfDef ADD_FAST}inline;{$EndIf}
function s_StrToQWord(const Str: UnicodeString): QWord; {$IfDef ADD_FAST}inline;{$EndIf}

В модуле три(шесть) основных процедуры:
[code]{$IfNDef UNICODESTRING_ONLI}
function geCharToInt(const aStr: array of Char; out Value: maxIntVal; Size: maxIntVal = maxSize): Boolean;
function geStrToInt(const Str: useString; out Value: maxIntVal; Size: maxIntVal = maxSize): Boolean; inline;
{$EndIf}
{$IfDef USE_UNICODESTRING}
function geWCharToInt(const aStr: array of WideChar; out Value: maxIntVal; Size: maxIntVal = maxSize): Boolean;
function geStrToInt(const Str: UnicodeString; out Value: maxIntVal; Size: maxIntVal = maxSize): Boolean; inline;
{$EndIf}

{$IfNDef UNICODESTRING_ONLI}
function geCharToUInt(const aStr: array of Char; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean;
function geStrToUInt(const Str: useString; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean; inline;
{$EndIf}
{$IfDef USE_UNICODESTRING}
function geWCharToUInt(const aStr: array of WideChar; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean;
function geStrToUInt(const Str: UnicodeString; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean; inline;
{$EndIf}

{$IfNDef UNICODESTRING_ONLI}
function geHOBCharToUInt(const aStr: array of Char; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean;
function geHOBStrToUInt(const Str: useString; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean; inline;
{$EndIf}
{$IfDef USE_UNICODESTRING}
function geHOBWCharToUInt(const aStr: array of WideChar; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean;
function geHOBStrToUInt(const Str: UnicodeString; out Value: maxUIntVal; Size: maxIntVal = maxSize): Boolean; inline;
{$EndIf}  [/code]

Модуль редактирован для разных архитектур. Проверялось только на 64-х битной системе, на 32-х битной не должно вызвать проблем. Для 16-ти и 8-ми битных надо проверять.
В модуле можно поднять уровень текущей архитектуры (UP_CPU в начале модуля). Но вы должны знать, что компилятор это позволяет и система под которую вы это делает (в основном от компилятора зависит). Для 64-х битной системы поднять уровень нельзя на данный момент. При сильном желании (если так хотите) можно, объявите свои данные и работайте с ними. Процедуры вообще не должны зависеть от разрядности системы, поэтому можно поднимать хоть до бесконечности. :)

Добавлен файл конфигурации. В файле конфигурации добавил возможность выбора "вида строки", на выбор:[code]{$DEFINE USE_STRING} // String
{$DEFINE USE_ANSISTRING} // AnsiString
{$DEFINE USE_UTF8STRING} //UTF8String

Если в своём коде вы используете какой-то из видов строк, то лучше переключать дефайны. Иначе можно потерять в скорости из-за перевода строки из одного вида в другой.
Дефайны действуют в порядке приоритета сверху вниз. Нижние отключаться, если какой-то из верхних включен.

Можно отключать часть функций, если вы их не используете. Если включить {$DEFINE USE_UNICODESTRING} и {$DEFINE UNICODESTRING_ONLI}, то можно будет использовать только юникод. Если вылючить первый дефайн, то это отключит использование функций на основе WideChar (юникод), будут использоватьсятолько функции на основе Char.

Все функции работают быстрее стандартных (в 2-3 раза), использующих функцию Val. :oops:

Модуль идёт под свободной лицензией Zlib.

Проблему с переполнением вроде решил, требуется проверка.

P. S. хоть какую-то мелочь доделал... правда опять не до конца, надо будет ещё и шестнадцатеричные значения обрабатывать и восьмеричные и двоичные... но тут совсем малость останется. :roll:
P.P.S. хоть шестнадцатеричные, восьмеричные и двоичные числа сейчас можно обработать, но по сути ещё не всё доделано. Осталось ещё числа с плавающей запятой обработать... :idea: :mrgreen:
Последний раз редактировалось Seenkao 03.02.2022 19:29:25, всего редактировалось 8 раз(а).
Seenkao
энтузиаст
 
Сообщения: 502
Зарегистрирован: 01.04.2020 03:37:12

Re: StrToInt на чистом паскале.

Сообщение zub » 10.01.2022 18:40:41

приложи хоть какойнить тест производительности чтоли
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: StrToInt на чистом паскале.

Сообщение Seenkao » 10.01.2022 20:02:46

всё внутри. Там и тест и как использовать.
у меня примерно так на 100000 итераций :
стандартный StrToInt: 7.7 (7.9)мс
обновлённый StrToInt: 5.0 (5.2)мс
Seenkao
энтузиаст
 
Сообщения: 502
Зарегистрирован: 01.04.2020 03:37:12

Re: StrToInt на чистом паскале.

Сообщение zub » 10.01.2022 21:24:56

т.е. ты предлагаешь брать результат из глобальной переменной? это же неюзабельно имхо.
кроме того, на скорость гораздо больше влияет работа с строками чем сам IntToStr, вариант умеющий работать подстрокой в строке будет гораздо эффективнее
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: StrToInt на чистом паскале.

Сообщение Seenkao » 10.01.2022 22:14:45

глобальную переменную можно заменить на локальную, для определённого модуля и запрашивать значение оттуда (вообще не понимаю этого, но для библиотек других методов не существует). Можно объявить свою переменную и записывать значения туда, хоть по ссылке. Это уже кто как захочет.

StrToInt хотел написать? ))) Было бы хорошо переписать IntToStr, но в данном случае я упираюсь в проверки строк в FPC. И скорости я не добьюсь. Возможность ускориться будет только в том случае, когда уйдём от строки используемой в FPC, а значит и уйдём от всех необязательных проверок, которые навязаны компилятором (это для меня не обязательные, но люди пользуются не так как я, значит проверки нужны).
Это тот вариант подстроки? Когда со строкой работать как с обычными данными? А как вернуть это обратно в строку, чтоб FPC рассматривал это как строку?

По сути можно сделать свою систему работы со строкой (вероятнее всего уже есть), где работа идёт с данными напрямую, но об многом используемом в FPC/Lazarus можно тогда будет забыть. Потому что для них нужно будет вернуть именно их строку, а не подмену, а это означает что мы всё равно потеряем в переводе строки в строку (данных в строку).
Seenkao
энтузиаст
 
Сообщения: 502
Зарегистрирован: 01.04.2020 03:37:12

Re: StrToInt на чистом паскале.

Сообщение zub » 10.01.2022 22:35:09

да, StrToInt конечно
я имею ввиду чтото типа
geStrToInt(const Str: String; Start,Len:Integer; Size: LongWord = isInteger)
при парсинге основное время какраз уходит на выдирание подстрок из строк, можно хорошо сэкономить передавая не подстроки а их адрес в большой строке.

ну и кроме того, конечно нужно отказаться от гото и заюзать генерики))
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: StrToInt на чистом паскале.

Сообщение Seenkao » 10.01.2022 22:53:06

точно ведь, я забываю о некоторых вещах... Ну значит можно ещё ускорить код. )))

zub писал(а):ну и кроме того, конечно нужно отказаться от гото и заюзать генерики))

когда-нибудь гляну и посмотрю конечный код. Если выползет по коду фигня какая-нибудь, точно пользоваться не буду. :)

Добавлено спустя 2 минуты 48 секунд:
zub писал(а):const Str: String;

офигеть... "про слона-то я и забыл..." :mrgreen: :mrgreen: :mrgreen:
ещё ускорение в полтора раза.

Премногоблагодарствую! :D
Seenkao
энтузиаст
 
Сообщения: 502
Зарегистрирован: 01.04.2020 03:37:12

Re: StrToInt на чистом паскале.

Сообщение скалогрыз » 11.01.2022 21:07:16

погоди, ты парсер сравниваешь с конвертатором? как-то не шибко честный тест?!

стандартная узнаёт "+"
Код: Выделить всё
writeln(strToIntDef('+1',0));


Seenkao писал(а):Функция не вылетит с ошибкой!

выше уже написал. Используй StrToIntDef или TryStrToInt
(StrToInt с exception-ом это веенье тогдашней моды... ну как сейчас шаблонами обмазываться)

PS: если Val() и тормозит, то похоже из-за того, что пытается перевести AnsiString в ShortString... как бы лишнее копирование.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: StrToInt на чистом паскале.

Сообщение Seenkao » 11.01.2022 23:02:57

скалогрыз писал(а):ты парсер сравниваешь с конвертатором?

разве я виноват в том, что вместо обычного перевода, они решили конвертировать данные?

Я ищу конкретный рабочий способ перевода данных, с минимальными затратами, и по возможности безглючный.

скалогрыз писал(а):Используй StrToIntDef или TryStrToInt


а скорость? С помощью zub-а я увеличил скорость в два с лишним раза (а я ещё не брался за шестнадцатеричные, восьмеричные и двоичные значения, где можно просто сдвигом всё делать).

скалогрыз писал(а):если Val() и тормозит

fpcVal - как бы обновляют. По быстрому просматривая код, вижу кучу вызовов, с кучей данных... мне уже это не нравится. Но пока не тестировал.
обсуждение на багтрекере. (лучше бы не читал... он будет ещё медленнее).
Последний раз редактировалось Seenkao 11.01.2022 23:11:08, всего редактировалось 1 раз.
Seenkao
энтузиаст
 
Сообщения: 502
Зарегистрирован: 01.04.2020 03:37:12

Re: StrToInt на чистом паскале.

Сообщение zub » 11.01.2022 23:09:16

>>я увеличил скорость в два с лишним раза
это синтетическое увеличение. производительность жрут перегоны строк туда-сюда
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: StrToInt на чистом паскале.

Сообщение Seenkao » 11.01.2022 23:12:10

при работе с цифрами (а многие как раз работают с цифрами), это даст значительное ускорение.
Понятно дело, что это не ускорит работу со строками в принципе, если их не надо будет переводить. :)
Seenkao
энтузиаст
 
Сообщения: 502
Зарегистрирован: 01.04.2020 03:37:12

Re: StrToInt на чистом паскале.

Сообщение Alexander » 12.01.2022 12:53:46

А если её доделать до совместимого с FPC вызова и заменить в основной ветке FPC ? Ускорение всегда нужно.
Аватара пользователя
Alexander
энтузиаст
 
Сообщения: 690
Зарегистрирован: 18.12.2005 19:10:00
Откуда: оттуда

Re: StrToInt на чистом паскале.

Сообщение Seenkao » 12.01.2022 13:29:46

Доделать то, доделаю, только боюсь не протолкнуть будет это.
У меня такое ощущение, что там просто упираются против улучшения. Хотя я даже не предлагал на замену, предложил как вариант использования.
Seenkao
энтузиаст
 
Сообщения: 502
Зарегистрирован: 01.04.2020 03:37:12

Re: StrToInt на чистом паскале.

Сообщение Alexander » 12.01.2022 15:28:14

У меня сложилось такое же ощущение. Но на замену ещё лучше. Можно оформить и как патч, если не захотят включать.

Добавлено спустя 3 часа 29 минут 20 секунд:
Протестировал. У меня он выдаёт:

Код: Выделить всё
first@my:~/mysites/smfg/soft/GORG64/geStrToInt$ ./project1
Wait...

Test begin.
StrToInt standard     1.2764969929610148E+001
StrToInt made by me  7.0074765044863865E+000
Test Speed Single and Integer  6.9267239712252477E+000
Test Speed Single all          9.9219571859529712E+000
Test end.

255027633

Numbers:
1884041200
-1884041200
0
188404120
0
18840412
0
-188404120
0
-18840412
231158691
-231158691
1
23115869
91
2311586
-1
-23115869

QWord
0

Int64
9223372036854775807

Byte
250
Аватара пользователя
Alexander
энтузиаст
 
Сообщения: 690
Зарегистрирован: 18.12.2005 19:10:00
Откуда: оттуда

Re: StrToInt на чистом паскале.

Сообщение скалогрыз » 12.01.2022 21:47:54

Seenkao писал(а):Я ищу конкретный рабочий способ перевода данных, с минимальными затратами, и по возможности безглючный

ты может и ищешь способ перевода данных.
но у тебя его нет. У тебя пока есть только проверка данных.

вот когда твоя функция вмето bool будет возвращать соответствующий int значение, ну тогда - да.
тогда можно будет сравнивать по времени.

а сейчас ты делаешь только половину работы.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

След.

Вернуться в Общее

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 7

Рейтинг@Mail.ru