Забавный но досадный глюк

Вопросы программирования и использования среды Lazarus.

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

Re: Забавный но досадный глюк

Сообщение runewalsh » 13.04.2013 15:50:07

Господа, я понимаю, что оптимальные алгоритмы — не конёк дельфистов, а, возможно, англоцентризм UTF-8 и задевает чьи-то чувства, но зачем усложнять? Вот более оптимальный и простой код, не вызывающий в цикле Copy и т. п.:
Код: Выделить всё
StartBytePos:=@utf8[1];
for j:=1 to UTF8Length(utf8) do
begin
  if UTF8CharacterToUnicode(StartBytePos, CharLen) = 32 then
    Inc(TestCount);
  StartBytePos := StartBytePos + CharLen;
end;

Разница со сгенерированным файлом — 5 раз. На той же "Божественной комедии" — 1.5. Где мои 3000% или хотя бы 1000? Я с вас угораю.
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 579
Зарегистрирован: 27.04.2010 00:15:25

Re: Забавный но досадный глюк

Сообщение debi12345 » 13.04.2013 15:55:49

Спасение для UTF8 - аппаратная (на уровне CPU/GPU) акселерация строковых манипуляций, эдакие строковые MMX/SSE/шэйдеры

Продолжая разговор сам с собой, предположу, что если бы UTF8 была внедрена MicroSoft-ом, то такая акселерация давно бы уже была в процах :) Но опять-таки скорее всего вместе с акселерацией для UTF16.
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Забавный но досадный глюк

Сообщение alexey38 » 13.04.2013 15:56:30

runewalsh писал(а):Я с вас угораю.

Я над Вами уже давно так делаю. Тугодумство конечно не великий недостаток, но в программировании не есть козырь.
alexey38
долгожитель
 
Сообщения: 1627
Зарегистрирован: 27.04.2011 19:42:31

Re: Забавный но досадный глюк

Сообщение debi12345 » 13.04.2013 15:56:53

Разница со сгенерированным файлом — 5 раз.

Даже эта разница не просто огромна, а чудовищна :)
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Забавный но досадный глюк

Сообщение runewalsh » 13.04.2013 15:59:23

debi12345 писал(а):Даже эта разница не просто огромна, а чудовищна

Смотри на реальный текст, ок. Нагенерировать много чего можно.
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 579
Зарегистрирован: 27.04.2010 00:15:25

Re: Забавный но досадный глюк

Сообщение debi12345 » 13.04.2013 16:11:19

По части конверсии строк FPC впереди планеты всей. В "С" коверсия в UCS-2 превращается в полный кошмар, единственно надежно рабочий код ниже :
Код: Выделить всё
wchar_t* mb2wstr(const char* inval) {
    size_t size = strlen(inval);
#define OUTSZ (size+1)*sizeof(wchar_t)
    wchar_t* buf = (wchar_t*)malloc(OUTSZ);
    memset(buf, 0, OUTSZ);
    setlocale(LC_CTYPE,""); //  REQUIRED!
    size = mbstowcs(buf, inval, size);
    if ( size == (size_t)(-1) ) {
     free(buf);
     buf = NULL;
    } else {
      buf = (wchar_t*)realloc(buf,OUTSZ);
    }
    return buf;
#undef OUTSZ
}
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Забавный но досадный глюк

Сообщение alexey38 » 13.04.2013 16:15:54

runewalsh писал(а):if UTF8CharacterToUnicode(StartBytePos, CharLen) = 32 then

Приведенный Вами алгоритм является наглядным примером подлога. Во-первых, он строго адаптирован к конкретному тесту, и сравнение с кодом пробела - это частный, а не общий случай, так что не везде применишь. Но самое главное, Вы выполнили преобразование из UTF8, в UTF32. Таким образом, Вы не смогли решить задачу в постановке UTF8. Возникает вопрос, а на кой нужен UTF8, если он без UTF32 замедляет в 30 раз, а в комбинации с UTF32 замедляет в 5 раз?
Сравнил i7 3770K c Atom N270, последний всего в 3 раза медленнее. То есть за счет аппаратуры проблему не решить.

Упертость отдельных личностей вызывает только смех. Можно биться головой об стену, можно в каждом частном случае выискивать оптимальные алгоритмы, можно переписать весь наследуемый код. Вопрос зачем это, кроме как для мазахистских извращений?
В любом случае лаконичнее код:
Код: Выделить всё
if utf32[j]=32 then
  Inc(TestCount);

По сравнению с кодом:
Код: Выделить всё
  if UTF8CharacterToUnicode(StartBytePos, CharLen) = 32 then
    Inc(TestCount);
  StartBytePos := StartBytePos + CharLen;
alexey38
долгожитель
 
Сообщения: 1627
Зарегистрирован: 27.04.2011 19:42:31

Re: Забавный но досадный глюк

Сообщение SeZuka » 13.04.2013 16:21:22

runewalsh писал(а):Разница со сгенерированным файлом — 5 раз. На той же "Божественной комедии" — 1.5.

Те преувеличивай, я для такого же кода и привел 15 раз. Для реального текста так же это вряд ли будет 1.5 раза. Для чистой латиницы выходит 5 раз.
SeZuka
постоялец
 
Сообщения: 209
Зарегистрирован: 05.09.2012 14:58:05

Re: Забавный но досадный глюк

Сообщение debi12345 » 13.04.2013 16:25:32

Самый прикол здесь
strlen
и
sizeof(wchar_t)
,
что подразумевает промежуточное до-выделение памяти 2...4 раза, то есть для конверсии строки 1 Мсимволов в может понадобиться 5Мбайт памяти - потому что "strlen" для UTF8 возвращает не количество символов (его нельзя просто так - без посимвольной итерации, узнать), а число байт - которое может быть в 4 раза больше чем число символов. И только после вызова API-функции узнается и выставляется реальная длина (размер в памяти) результата. Трудно придумать что либо более неэффективное.
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Забавный но досадный глюк

Сообщение runewalsh » 13.04.2013 16:26:17

alexey38 писал(а):Во-первых, он строго адаптирован к конкретному тесту, и сравнение с кодом проблема - это частный, а не общий случай, так что не везде применишь.

Кот бы говорил про упёртость, везде тестировалось сравнение с #32.
alexey38 писал(а):Но самое главное, Вы выполнили преобразование из UTF8, в UTF32.

Не подменяй понятия. UTF-8 — представление исходной строки в памяти. Идея не в том, чтобы нагло считерить, прочитав UTF-32, а в вычленении символа, чтобы с ним можно было работать. Всё равно что прочитать в регистр. Или предлагаешь наложить искусственные ограничения на реализацию?

debi12345, в C таким мазохизмом занимаются редко, в крестах же есть boost::locale::conv::utf_to_utf и http://utfcpp.sourceforge.net/.
SeZuka, я ж не с потолка 1.5 взял, можете проверить сами на любой книжке. Русский текст — 1.5x, английский — 1.25x, японский — ок, таки 4x (UPD: чуть меньше, ~3.5), но для меня загадка, почему тормозит рандомный текст.
Последний раз редактировалось runewalsh 13.04.2013 16:41:28, всего редактировалось 2 раз(а).
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 579
Зарегистрирован: 27.04.2010 00:15:25

Re: Забавный но досадный глюк

Сообщение debi12345 » 13.04.2013 16:40:28

в C таким мазохизмом не занимаются

В Линуксе в С-программе ? Это единственно рабочий способ - например прочитать нелатинский аргумент из консоли и получить его в юникодовом представлении. Подразумеваю, что и FPC внутри проделывает нечто подобное с UTF8 (ведь для нее нельзя быстро, без итераций - получить длину строки до начала операций с этой строкой) - оттого и разница в разЫ, а то и порядки.
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Забавный но досадный глюк

Сообщение runewalsh » 13.04.2013 16:43:44

debi12345 писал(а):В Линуксе в С-программе ?

Не все ж фанатики. :D
И в вашем примере выделение памяти подразумевается интерфейсом, хотя можно обойтись входным-выходным буферами и итерированием.
debi12345 писал(а):Подразумеваю, что и FPC внутри проделывает нечто подобное с UTF8

Ничего сложного в преобразовании между UTF'ами нет, вы можете сами по спекам написать близкое к оптимальному на коленке минут за 20. Другое дело — между юникодом и локальными кодировками. Но о них речи не идёт, да и с консоли (не stdin, а именно из терминала) больших объёмов информации можно не ожидать.
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 579
Зарегистрирован: 27.04.2010 00:15:25

Re: Забавный но досадный глюк

Сообщение debi12345 » 13.04.2013 16:47:34

но для меня загадка, почему тормозит рандомный текст.

Возможно из-за промахов кэша. То есть, вопрпеки ожиданием - UTF8 использует кэш наихудшим образом. Может быть как раз из-за 2..4 завышенной потребности в памяти при конверсиях.

Добавлено спустя 4 минуты 5 секунд:
Не все ж фанатики.

ПисАть на С в Линусе = фанатизм ? "С" = база "Линя" :) 95% процентов линуксового софта написано на "pure C".

И в вашем примере выделение памяти подразумевается интерфейсом, хотя можно обойтись входным-выходным буферами и итерированием.

Напишите кокретно рабочий код (загурзки в юникод из консоли - однобайтной или UTF8 - проиведенный тормуознутый пример это умеет) - нелатинские линуксоиды Вам огроооооомное спасибо скажут :)
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Забавный но досадный глюк

Сообщение runewalsh » 13.04.2013 17:02:18

debi12345 писал(а):Может быть как раз из-за 2..4 завышенной потребности в памяти при конверсиях.

НЕТ. ТАМ. НИКАКИХ. АЛЛОКАЦИЙ. >_<
debi12345 писал(а):ПисАть на С в Линусе = фанатизм ?

Работать с юникодом — да, отчасти. Ну и количество не значит качество; согласитесь сишные строки — убожество и источник ошибок. Даже GCC уже на кресты перешёл.
debi12345 писал(а):Напишите кокретно рабочий код

Просто посмотрите на дизайн "низкоуровневых" паскалевских UTF8ToUnicode и иже с ней. Собственно, достаточно mbstowcs, а смысл портянки в распределении строки, тормозить может только setlocale, выносимая в инициализацию приложения.
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 579
Зарегистрирован: 27.04.2010 00:15:25

Re: Забавный но досадный глюк

Сообщение debi12345 » 13.04.2013 17:19:06

НЕТ. ТАМ. НИКАКИХ. АЛЛОКАЦИЙ

???
Код: Выделить всё
function UTF8ToUnicode(const Src:TUTF8String):TString;
var
  lp, vp:Integer;
  c:TUTF8Char;
begin
  lp := 1;
  vp := 0;
  SetLength(Result, Length(Src));
  while lp <= Length(Src) do
  begin
    vp := vp + 1;
    c := LCharOf(Src, lp);
    Result[vp] := WideChar(UTF8ToUCS16(c));
    lp := lp + Length(c);
  end;
  SetLength(Result, vp);
end;

Дважды вызывается SetLength - один раз как ALLOC с кратным запасом по размеру (количество байт вместо количесва символов), другой - как финальный REALLOC под реальное количество символов. По ходу практически ничем не отличается от С-ого вырианта.
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Пред.След.

Вернуться в Lazarus

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

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

Рейтинг@Mail.ru
cron