Pull to refresh

Comments 21

Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку

Автор оригинала: Daniel Lemire


Хм.

Использованный в коде union содержит поле as_str. Однако нигде в коде это поле не используется, что говорит о том, что ни это поле никому тут нинафиг не нужно, ни весь union никому тут нинафиг не нужен. Зачем код замусорен всем этим? В чем глубинный смысл?

В комментариях к оригиналу есть версия:

Neat! I have noticed a small mistake:

memcpy(&digits.as_int, str, sizeof(digits));

should be

memcpy(&digits.as_str, str, sizeof(digits));

Это не ошибка, это бессмыслица. Если уж автор воспользовался memcpy, то union ему действительно не нужен. Собственно, потому он и не заметил этой "ошибки", что код прекрасно работает и так. Union с фиктивными полями иногда приходится использовать для, целей выравнивания, но здесь совсем не тот случай. Автор наворотил ненужной фигни с union поверх вполне работоспособной техники и, похоже, до сих пор не понял, что это лишь ненужная фигня.

Понятно, что оно там не нужно, но как-то же автор планировал использовать этот код. Может вот так.

Можно вопрос? Зачем нужен digits.as_str, если он нигде не используется?

memcpy(&digits.as_int, str, sizeof(digits));

По-моему, копировать из строки больше байт, чем там есть - это UB, крэш, эксплойт на слив данных из соседней памяти ... и вообще нехорошо.

Согласно https://en.cppreference.com/w/cpp/types/integer типа uint32_t может не быть: provided if and only if the implementation directly supports the type

Возможно, стоит рассмотреть табличный метод: массив 256 байт на первый символ, далее на второй и третий. В телефонии это считается одним из самых быстрых способов делать фиксированные вычисления.

Я теряюсь в догадках, почему наивное решение настолько быстрее, чем стандартная библиотека

Ну я с таким на C# сталкиваюсь постоянно, недавно статью вот даже написал. И это удручает, так как стандартными методами пользуются весьма охотно.

Результаты from_chars совершенно разочаровывают. Я теряюсь в догадках, почему наивное решение настолько быстрее, чем стандартная библиотека.

Потому что голландец, видимо, середнячок, судя по другим комментариям о ненужном union и незнании о том, что std::from_chars() немного универсальней с четвёртым параметром int base = 10 , и там без произведения с base не обойтись. Ну и всякие ошибки errc::invalid_argument, errc::result_out_of_range.

Насчёт base - если они не догадались оптимизировать самый частый контекст использования...

А кто подсчитывал, что основание 10 для байта самое частое, а не 16? И from_chars не ограничена только диапазоном 0-255, теперь им для каждого целочисленного знакового и беззнакового типа писать оптимизации?

Разумеется, а зачем еще нужна стандартная библиотека? Чтобы самому все писать что ли?

я бы мог поспорить, но не вижу смысла, потому что у функции автора и std::from_chars разные требования, хоть с помощью них и можно решить одну задачу.
Помню пост, где wc на haskell был быстрее gnu имплементации на Си. Ох и споров там было.
Просто это нечестный, в какой-то степени, бенчмарк.

интересно, будет ли какой-то эффект, если убрать проверки на длину и all_digits

Какой смысл от них? Мне кажется это тоже самое, что добавлять проверку в strlen.

Задача взята из проекта simdzone под руководством Йероена Коеккоека (NLnet Labs).

Я тут слегка посмотрел и выяснил:

  1. Что упоминающийся Йероен Коеккоек - это Jeroen Koekkoek (https://imap.nlnetlabs.nl/people/, https://github.com/k0ekk0ek), т.е. явно голландец;

  2. И следовательно тут надо применять правила нидерландско-русской транскрипции;

  3. И он получается скорее Йерун Куккук, там oe передаёт у.

P.S. Прошу меня извинить, просто странный набора знаков в глаза бросился ?

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

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

Впрочем, можете сами изучить.

Ох, как будто Хабр 2000- ых. Спасибо :)

Не понятно, почему эта статья в хабах С и С++.

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

С этого места человек перестаёт писать код на Си/С++. Потому как стандарты Си и С++ ничего не знают ни про границы страниц, ни про что-то еще. Выход за границу массива определяется как UB.

Де факто, человек с этого момента начинает писать на ассемблере, под конкретную аппаратную архитектуру, конкретный аллокатор в конкретной ОС. Это допустимо, если он пишет код под одну конкретную железку, но в остальных случаях - такому коду не место в продакшене.

Я тут ради прикола написал самую дубовую реализацию этой функции через switch-case, вообще не думая.

static int parse_uint8_switch_case(const char *str, size_t len, uint8_t *num) {
    uint8_t hi, mid, lo;

    #define as_u8(x) ((uint8_t)((x) - '0'))

    switch(len) {
        case 1:
            *num = as_u8(str[0]);
            return *num < 10;
        case 2:
            hi = as_u8(str[0]);
            lo = as_u8(str[1]);
            *num = (uint8_t)(hi * 10 + lo);
            return (hi < 10) && (lo < 10);
        case 3:
            hi = as_u8(str[0]);
            mid = as_u8(str[1]);
            lo = as_u8(str[2]);
            *num = (uint8_t)(hi * 100 + mid * 10 + lo);
            return 
              ((hi == 2) && (mid < 6) && (lo < 6))
               || ((hi < 2) && (mid < 10) && (lo < 10));

        default:
            return 0;
    }

    #undef as_u8
}

А потом запустил бенчмарки. Результат довольно-таки занимательный:

Как всегда, кто-то решил что он умнее разработчиков компилятора, и умнее разработчиков предсказателя переходов)

P.S.
Что делает код Боба и почему он такой быстрый - я понятия не имею :) Есть подозрение, что выстрелил UB и код делает ровным счётом нихрена, я не вникал.

Хаха, прям повторение истории с wc на haskell

Да уж, помню как когда я начал изучать микроконтроллеры и С, меня впечатлило преобразование char в int простым вычитанием '0' )

Sign up to leave a comment.

Articles