LINUX.ORG.RU

быстрый парсинг целочисленных значений

 


3

10

https://github.com/dzidzitop/libafc/blob/master/src/afc/number.h#L264

Сабж. Работает в 2-3 раза быстрее std::stroul от GCC. Pure C такую скорость выдать не сможет никогда - в этом сила «плюсов». У кого есть идеи что можно ускорить - предлагайте.

★★

Последнее исправление: dzidzitop (всего исправлений: 1)

Pure C такую скорость выдать не сможет никогда - в этом сила «плюсов».

Раскройте, пожалуйста, эту мысль, страницы на 3-4.

t184256 ★★★★★
()
Ответ на: комментарий от t184256

Раскройте, пожалуйста, эту мысль, страницы на 3-4.

«Комментарии срачерам. Избранное.» том 1

shty ★★★★★
()

Pure C такую скорость выдать не сможет никогда

ты ошибся,вместо «Pure C»-твои руки

программировать научись,а не писать на языке

anonymous
()
Ответ на: комментарий от t184256

Большинство оптимизаций в коде по ссылке - compile-time. Основание передаётся как параметр шаблона - код генерируется под конкретную базу. Код построен на итераторах - не нужно думать как получить char * из своих структур (например, при чтении файла). Функция инлайнится - меньше жонглирования с регистрами.

Как-то так.

dzidzitop ★★
() автор топика
Ответ на: комментарий от t184256

Лучше с кодом приходите. Будет интересно сравнить.

dzidzitop ★★
() автор топика
Ответ на: комментарий от dzidzitop

делаю проект на гитхабе прям щас,где делаю реализачию твоей логики на Си и java обе реализации будут рабоатть быстрее

стоимость 1000$,время 10 дней,оплата по факту

ты готов оплатить мою работу?

anonymous
()
Ответ на: комментарий от endeneu13

я работаю с UTF-8. Это переносимый способ задать UTF-8 char literal в сорцах. На случай non-ASCII кодировок.

dzidzitop ★★
() автор топика

А можешь сформулировать задачу словами, плиз, со всеми существенными условиями? И привести тест-программу, которой меряться?

Kroz ★★★★★
()
Ответ на: комментарий от Kroz

задача - распарсить int из текста в int value.

код, которым я мерял - вот:

#include <afc/number.h>

int main(const int argc, char ** const argv)
{
	unsigned long int strtoul (const char* str, char** endptr, int base);
	const std::size_t n = 1000000;
	unsigned long result = 0;
	char *end;
	long p;
	char str[] = "123456789012345678901234567890";
	for (int j = 0; j < 100; ++j)
	for (std::size_t i = 0; i < n; ++i) {
		result += strtol("123", &end, 10);
		//afc::parseNumber<10>(str, str+3, p, [](const char *){exit(1);});
		//result += p;
	}
	return result;
}
dzidzitop ★★
() автор топика

Pure C такую скорость выдать не сможет никогда

Тот же алгоритм, что и у вас, с одной заинлайненной функцией на C будет работать ровно с той же скоростью.

Sorcerer ★★★★★
()

студентик заделал лабу и пришел хвастаться на лор?

или это жалкая попытка создать срач и вызвать Дурачка?

unt1tled ★★★★
()
Ответ на: комментарий от Sorcerer

и да и нет: - да, если использовать только const char * как входные данные + надеяться на компилятор - нет, если функцию нужно будет делать не inline. (в случае плюсов все compile-time оптимизации будут сделаны для каждого инстанса шаблона) - нет, если учесть что это не одна функция, а семейство функций для парсинга всех видов целочисленных значений.

dzidzitop ★★
() автор топика
Ответ на: комментарий от Sorcerer

макросы также скорее всего понадобятся для подсчёта лимитов на overflow & underflow. в предложенной версии они делаются в compile-time. но нужно смотреть на то, что выдаст компилятор.

dzidzitop ★★
() автор топика
Ответ на: комментарий от unt1tled

ему любой может предложить хоть на питоне переписать его алгоритм

он не готов оплачивать

пустослов обучный

anonymous
()
Ответ на: комментарий от annulen

не знаю как это запускать. анализ кода, показывает, что там

- нет inline

- максимальная база - 16, поддерживаются только lowercase letters

- используется ассемблерная вставка (не переносимый код)

- поддерживается только long.

без inline производительность будет не очень точно. с inline - точно будет близкой. скомпилить это всё чтобы запустить хз как (ассемблерные вставки выгребать нужно искать откуда).

dzidzitop ★★
() автор топика

Тема обещает быть годной. Подпишусь ка я :-D

FIL ★★★★
()

Pure C такую скорость выдать не сможет никогда - в этом сила «плюсов».

Вот и пятница пришла

Gvidon ★★★★
()
Ответ на: комментарий от annulen

ошибся, поддерживаются и uppercase A-F. но ценой конверсии через tolower. нужно будет попробовать - может игры с битами будут лучше работать чем явные if-else.

dzidzitop ★★
() автор топика
Ответ на: комментарий от annulen
--- a/src/afc/number.h
+++ b/src/afc/number.h
@@ -296,13 +296,14 @@ Iterator afc::parseNumber(Iterator begin, Iterator end, T &result, ErrorHandler
        result = 0;
        do {
                T digit;
-               const char c = *p;
+               char c = *p;
                if (c >= u8"0"[0] && c <= afc::math::min<char>(u8"9"[0], u8"0"[0] + base)) {
                        digit = c - u8"0"[0];
-               } else if (base > 10 && c >= u8"a"[0] && c <= afc::math::min<char>(u8"z"[0], u8"a"[0] + base - 10)) {
+               } else if (base > 10 &&
+                               (c |= 0x20, // approximate lower-casing
+                                               c >= u8"a"[0] && c <= afc::math::min<char>(u8"z"[0], u8"a"[0] + base - 10)
+                               )) {
                        digit = c - u8"a"[0] + 10;
-               } else if (base > 10 && c >= u8"A"[0] && c <= afc::math::min<char>(u8"Z"[0], u8"A"[0] + base - 10)) {
-                       digit = c - u8"A"[0] + 10;
                } else {



приблизительный lower-casing работает значительно быстрее. спасибо за наводку. это вероятно не совсем то, что было в kstrtox.c, но для случая parse number работает идеально.
dzidzitop ★★
() автор топика

где кейс с использованием вашего кода (или как это назвать)..

ps/ вы потратили чтобы написать фигню подряд 4 часа. Ещё часов 8 отожралось при ловле багов в течении недели-двух. Итого вы просрали (4+8)*10 (среднечасовая оплата)=120 баксов.

pps/ затраты не отобьются. Потому как это как минимум 1) не быстрее 2) не удобнее

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

моё время стоит дороже. быстрее. удобнее (я использую не только char *, могу в ErrorHandler кидать исключения). работает со всеми типами, которые мне понадобятся.

и в целом - это just for fun.

dzidzitop ★★
() автор топика
Ответ на: комментарий от MKuznetsov

работает автоматически для radix=2,10,16. остальное мне без надобности. оно там есть просто так - «бесплатно». причём каши не просит.

dzidzitop ★★
() автор топика
Ответ на: комментарий от dzidzitop

работает автоматически для radix=2,10,16

для этих значений есть CPU - у него специальные команды для этого..:-) Будете спорить - тут положат на обе лопатки

ps/ ни разу не встречал задачу где преобразование ascii->uint было критично по времени. Так что ваш just-for-fun можно рассмотреть как «гляньте как я познаю плюсы» :-)

MKuznetsov ★★★★★
()

На вот держи два варианта. Выкрвыривает по 8 цифр и преобразовывает в число от 0 до 99999999. Проверку «является ли переданная фигня числом» оно не проводит. Всегда лопает по 8 цифр, так что обязательно должны быть ведущие нули. Что из них быстрее я не проверял

#include <stdint.h>
#include <string.h>
#include <inttypes.h>
#include <stdio.h>

uint64_t parse1(char *str)
{
  uint64_t a;
  memcpy( &a, str, 8);


a = ((a & 0x0F000F000F000F00)>>8) +
    ((a & 0x000F000F000F000F)*10);

a = 1000000 * ((a >> 0 ) & 0xFF) +
      10000 * ((a >> 16) & 0xFF) +
        100 * ((a >> 32) & 0xFF) +
              ((a >> 48) & 0xFF);

return a;
}

uint64_t parse2(char *str)
{
  uint64_t a;
  memcpy( &a, str, 8);


  a = (a & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
  a = (a & 0x00FF00FF00FF00FF) * 6553601 >> 16;
  a = (a & 0x0000FFFF0000FFFF) * 42949672960001 >> 32;
  return a;
}



int main(void)
{
    printf("%" PRIu64 " ""%" PRIu64 "\n", parse1("999999999"), parse2("999999999"));
    printf("%" PRIu64 " ""%" PRIu64 "\n", parse1("000000000"), parse2("000000000"));
    printf("%" PRIu64 " ""%" PRIu64 "\n", parse1("123456789"), parse2("123456789"));
    return 0;
}

SZT ★★★★★
()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от MKuznetsov

мне всё равно как это выглядит.

функция создавалась под конкретные цели, для которых stroul не подходил по определённым причинам. я буду рад увидеть код, который работает эффективнее. предложенное API также может экономить memory allocations на временные буферы.

dzidzitop ★★
() автор топика
Ответ на: комментарий от dzidzitop

может экономить memory allocations на временные буферы.

what?? где вы наковыряли временные буферы и их allocation в такой фигне, чтобы их экономить ??

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

повторю: я использую не только char * C++ не C - там набор типов немного богаче.

dzidzitop ★★
() автор топика
Ответ на: комментарий от dzidzitop

Только прошу обратить внимание, что код будет правильно работать только на little-endian машинах. Но переделать его под big-endian несложно

SZT ★★★★★
()

Вот еще

static inline uint64_t parse_hex_uint64(const char *s) {
    const uint64_t m1 = 0x4040404040404040ll;
    const uint64_t m2 = 0x000F000F000F000Fll;
    const uint64_t m3 = 0x0F000F000F000F00ll;
    const uint64_t *p = (const uint64_t*)s;
    uint64_t a = p[0], b = p[1];
    a += ((a & m1) >> 6) * 9;
    b += ((b & m1) >> 6) * 9;
    a = (a & m2) << 12 | (a & m3);
    b = (b & m2) << 12 | (b & m3);
    a |= a >> 24;
    b = b >> 8 | b << 16;
    return (a & 0x0000FFFF00000000ll) | (a & 0xFFFF) << 48 | b >> 48 | (b & 0xFFFF0000);
}

SZT ★★★★★
()
Ответ на: комментарий от dzidzitop

afc::parseNumber...(..., str+3, ...);

кул стори, а strtol пусть считает длину как лох

strtol(«123»

char str[] = «123...
afc::parseNumber...(str

кул стори, можешь писать в строку, а strtol пусть работает с const как лох

unsigned long int strtoul (const char* str, char** endptr, int base);

какого х вместо включения хедера ручное определение

и тд

anonymous
()
Ответ на: комментарий от MKuznetsov

а еще кучу времени потратил на ЛОР... даже если все люди, всю жизнь постоянно будут использовать этот код на с++, эта дельта времени между плюсами и си не окупится «никогда»...

rgB
()
Ответ на: комментарий от anonymous

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

dzidzitop ★★
() автор топика
Ответ на: комментарий от rgB

а зачем ему окупаться? это open source. ну и свою жизнь каждый тратит так, как ему надо.

dzidzitop ★★
() автор топика
Ответ на: комментарий от anonymous

и да - я не виноват что std::strtol лох, который может быть считает длину (хотя там такого нет, есть только проверка на '\0')

dzidzitop ★★
() автор топика
Ответ на: комментарий от SZT

есть версия что GCC строковый литерал во время компиляции преобразует сразу в uint64_t значение. нужно будет проверить. но да - если этот код работает, то это близко к идеалу для спецслучая.

dzidzitop ★★
() автор топика
Ответ на: комментарий от SZT

Для 32-х битного arm gcc с -O2 сделает так:

	mov	r3, r0
	movw	ip, #16960
	push	{r4, r5, r6, r7, r8, r9, r10, fp, lr}
	sub	sp, sp, #28
	ldr	r1, [r3, #4]	@ unaligned
	add	r4, sp, #16
	ldr	r0, [r0]	@ unaligned
	mov	lr, #10
	movt	ip, 15
	stmia	r4!, {r0, r1}
	ldrd	r4, [sp, #16]
	and	r10, r4, #983055
	and	fp, r5, #983055
	and	r4, r4, #251662080
	and	r5, r5, #251662080
	umull	r0, r1, r10, lr
	lsrs	r2, r4, #8
	orr	r2, r2, r5, lsl #24
	lsrs	r3, r5, #8
	adds	r2, r2, r0
	mov	r5, #0
	lsr	r8, r2, #16
	and	r10, r2, #255
	mla	r1, lr, fp, r1
	mov	lr, #100
	umull	r6, r7, r10, ip
	adcs	r3, r3, r1
	and	r0, r3, #255
	movs	r1, #0
	orr	r8, r8, r3, lsl #16
	strd	r0, [sp, #8]
	and	r0, r8, #255
	movs	r1, #0
	strd	r0, [sp]
	lsr	r9, r3, #16
	ldr	r2, [sp]
	movw	r3, #10000
	ldr	r8, [sp, #8]
	mov	fp, #0
	mla	r7, ip, fp, r7
	movw	ip, #10000
	umull	r0, r1, r2, r3
	adds	r4, r9, r6
	umull	r2, r3, r8, lr
	ldr	r8, [sp, #4]
	adcs	r5, r5, r7
	adds	r0, r0, r4
	mla	r1, ip, r8, r1
	ldr	r8, [sp, #12]
	mla	r3, lr, r8, r3
	adcs	r1, r1, r5
	adds	r0, r0, r2
	adcs	r1, r1, r3
	add	sp, sp, #28
	pop	{r4, r5, r6, r7, r8, r9, r10, fp, pc}

Не очень подходит для мобилок. Нужно аналогичное но с uint32_t.

andreyu ★★★★★
()

вот зачем ты ляпнул про Pure C? а то у меня много замечаний по коду, но желание их излагать почему-то отпало.
в целом, по плюсам у тебя пока довольно много минусов. потому что ты плЮсы плюсОв пока не освоил. есть много умных заметок в инете про передачу параметов, например. рекомендую почитать.

Iron_Bug ★★★★★
()
Ответ на: комментарий от Iron_Bug

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

зачем ляпнул? потому что без шаблонов этот самый Pure C как-то не тянет там, где нужно выжимать из кода всё.

dzidzitop ★★
() автор топика

Интересно, кому может понадобиться парсинг числа в базе отличной от 10 и 16?

Legioner ★★★★★
()
Ответ на: комментарий от CatsCantFly

сорцы есть под рукой (именно где идёт парсинг)? из заголовков выхода на реализацию что-то не нашёл.

dzidzitop ★★
() автор топика

быстро

парсит текст, вместо работы сразу с бинарными данными

класика

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.