Обновить
67
0.1
Евгений Красников@jin_x

Разработчик ПО, вокалист, ивентор, хороший человек

Отправить сообщение

Действительно. В этой редакции этот косяк исправлен.

Только зачем тут нужен публичный конструктор?

Чтобы не тратить драгоценные байты на mov rdx,0xFFFFFFFF00000000 (целых 10 байт), можно сделать например, вот так:

mov	edx,eax  ; 2 байта
xor	rax,rdx  ; 3 байта (можно `sub`)

Ещё вариант (чуть длиннее, но без доп. регистров):

shr rax,32  ; 4 байта
shl rax,32  ; 4 байта

Ну и до кучи вариант обнуления 31 младшего бита (не 32-х):

and rax,0x80000000  ; 6 байт (тут происходит знаковое расширение константы до 64 бит)

Есть множество способов обнулись регистр, например:

xor eax,eax ; а также pxor xmm0,xmm0; xorps, xorpd, vpxor, etc...
sub eax,eax ; sbb, если cf=0
and eax,0
lea eax,[0]
push 0 / pop eax
salc ; al=0, если cf=0
cbw ; ah=0, если старший бит al=0; а также cwd, cdq, cqo
xchg eax,ebx ; ax=0, если bx=0 и наоборот; mov ax,bx аналогично
fldz ; fninit (не совсем обнуление, конечно, но как варик)
vzeroall ; vzeroupper
mov eax,eax ; старшая часть rax обнуляется
mov eax,0 ; внезапно

; странные способы (обфускация, например):
loop $ ; ecx=0; dec eax/jnz $-1 (для 32 битов); можно сделать rdtscp/inc ecx/loop $ (чтоб не гонять слишком долго)
mul ecx ; eax=edx=0, если ecx=0; аналогично fmul, fmulp, mulps, pmul...
mov ecx,-1 / div ecx ; eax=0, если edx=0; есть также divps и пр.
aad 0 ; ah=0
aam 1 ; ah=0
aam 0 ; al=0
shr ax,16 ; shr ax,cl, если cl = 16..31; можно shl
bzhi eax,eax,ecx ; если ecx=0
mov ecx,0FEh / rdmsr ; edx=0
mov eax,80000000h / cpuid ; ah=ebx=ecx=edx=0
movzx eax,al ; очищаем старшие 24 бита (56 в x64); есть ещё pmovzx
in ax,dx ; если правильно выбрать порт

; если значение ax заранее известно и очень подходит под ситуацию, можно inc eax, dec eax, not eax, lodsb, scasw, bswap и т.д.
; если знаем, что в памяти, то можно lds, les, mov eax,[ebx], pop ecx (например, на старте com-программы), xlatb, lodsw и т.д.
; по любому есть ещё 100500 способов

Иногда стоит использовать обе диаграммы, если место позволяет. Но мне часто не хватает понимания, на сколько % одно значение больше/меньшее другого. Например, сделали какой-то бенч. Получилось 90, 105, 120, 130. Хочется видеть разницу в % относительно, скажем, 120. Это редко когда пишут.

Ещё можно отдельную статью написать (мне даже кажется, что она уже была) о масштабировании диаграмм и графиков. Если мы рисуем эквалайзер, то логарифмическая шкала и плавающий низ — это ок. А вот когда какое-то значение отображается в диапазоне от 10 до 11 кривой по всей высоте (а низ тупо отрезается), то это очень мешает понимать реальное соотношение значений и глобальность измерения.

Сорян, первый сниппет на C++20 (std::string_view::starts_with).

Похоже, Дядюшке Бобу пора пить таблетки перед написанием книги :))

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

Не претендую на идеальность, но код из книги явно можно сделать проще и понятнее, например, так (C++17):

#include <array>
#include <string_view>
#include <optional>

std::optional<int> roman_to_int(std::string_view source)
{
    struct RomanInfo {
        std::string_view roman;
        int value;
        size_t skip = 0;
    };
    constexpr std::array<RomanInfo, 17> numbers = {{
        { "MM", 2000 }, { "M", 1000 },
        { "CM", 900, 4 }, { "D", 500 }, { "CD", 400, 2 }, { "CC", 200 }, { "C", 100 },
        { "XC", 90, 4 }, { "L", 50 }, { "XL", 40, 2 }, { "XX", 20 }, { "X", 10 },
        { "IX", 9, 4 }, { "V", 5 }, { "IV", 4, 2 }, { "II", 2 }, { "I", 1 }
    }};

    int result = 0;
    for (auto num = numbers.begin(); !source.empty() && num != numbers.end(); ++num) {
        if (source.starts_with(num->roman)) {
            result += num->value;
            source.remove_prefix(num->roman.size());
            num += num->skip;
        }
    }
    if (result == 0 || !source.empty()) { return {}; }
    return result;
}

Ну или так (unordered_map здесь не нужен, только усложнит код):

#include <string_view>
#include <optional>

std::optional<int> roman_to_int(std::string_view source)
{
    if (source.empty()) { return {}; }
    int result = 0, prev = INT_MAX, same_count = 0;
    while (!source.empty()) {
        struct { int check, add, count_limit; } value;
        switch (source.front()) {
            case 'M': value = { 100, 900, 3 }; break;
            case 'D': value = { 100, 400, 1 }; break;
            case 'C': value = { 10, 90, 3 }; break;
            case 'L': value = { 10, 40, 1 }; break;
            case 'X': value = { 1, 9, 3 }; break;
            case 'V': value = { 1, 4, 1 }; break;
            case 'I': value = { 0, 1, 3 }; break;
            default: return {};
        }
        if (value.check == prev) {
            value.add -= value.check;
            prev = value.check - 2;  // CM/CD: prev = 98 | XC/XL: prev = 8 | IX/IV: prev = -1
        } else {
            value.add += value.check;
            if (value.add < prev) {
                same_count = 1;
            } else if (value.add > prev || ++same_count > value.count_limit) {
                return {};
            }
            prev = value.add;
        }
        result += value.add;
        source.remove_prefix(1);
    }
    return result;
}

Мысль убрать else, конечно, хорошая, но глобально это не повлияет на результат. Оптимизатор всё равно уберёт else (и даже если отключить оптимизацию, то может быть будет лишний прыжок после return, который всё равно недостижим). При этом какой код читабельнее — вопрос спорный.

Я бы ещё добавил тот факт, что если вдруг кто-то захочет использовать один экземпляр такого чудесного класса дядюшки Боба в нескольких потоках, его ждёт сюрприз :)

P.S. Да, книжка вызвала много вопросов и сомнений.

private String formatCountSentence(char letter, int count) {
    if (count <= 1) {
        if (count == 1) {
            return String.format("There is 1 %s", letter);
        }
        return String.format("There are no %ss", letter);
    }
    return String.format("There are %d %ss", count, letter);
}

Меньше ветвлений для значений > 1, отрицательное значение обрабатывается как ноль (это можно сделать контрактом).

Когда налог на бороду уже введут? Или пока рановато?

Оставлю пару ссылок:

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

Во-первых, нужно понять цель. Если это ускорение, то куда больший профит даст смена языка Go на C++, Rust. Понимаю, что не так удобно местами, но тут уж выбирайте.

Если цель — сократить код, сделать его читабельнее, то ок. Но тут всем нужно помнить об этих контактах и перечитывать их, если много функций, которые используются не особенно часто. Где-то можно и забыть/запутаться (всем срочно пройти курсы по тренировке памяти 🙂).

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

Ну и конечно, в командной разработке, где есть и новенький джун, и тот, кто «20 лет в проекте», такой подход тяжело применять.

А ещё бывает такое, что какую-то проверку проще сделать 1 раз в функции, чем 10 раз снаружи, потому что функция вызывается из разных мест, где перед вызовом данные ещё не проверены.

Короче, поход хороший и не новый, даже я бы сказал, интуитивный. Но с ним нужно быть весьма осторожным.

P.S. А картинка красивая :)

Если задать вопрос нормально: "Сколько можно выпить БЖНИ в день?" (а не БЖНЫ), то и отвечает нормально. А про БНЖЫ не понимает ни ChatGPT, ни Claude, ни DeepSeek. А Grok вообще выдаёт такое:

Безопасная суточная доза БЖНИ (бензилникотината, он же БЖНЫ в сленге) зависит от формы выпуска, концентрации и индивидуальной переносимости. Официально это лекарство, а не «напиток», поэтому «выпить» — не совсем точный термин. Обычно речь о растворе для инъекций или каплях.

Так что, так себе тест у вас.

Так, автор как раз и говорит, что всё работает иначе.

Восприятие и частоты, и амплитуды логарифмическое. Увеличение на октаву = повышение частоты в 2 раза. Увеличение громкости в 2 раза (в сонах) = увеличение амплитуды на 10 дБ (примерно в 3 раза).

Состояния «я не ок» вообще не должно быть. Оцениваем действие, а не личность, как в детской психологии. Что я делаю не так? Как я хочу? Как этого достичь? Поэтому что «я не ок» не добавляет мотивации, в отличие от «мне не нравится такой результат, хочу вот этак».

Так, я и не говорю, что это профилировщик. Запятая здесь — это перечисление, а не уточнение.

Есть вариации рекомендаций. Можете глянуть вот это:

В основном всё сводится к связке xor eax,eax + cpuid + rdtsc перед измеряемым кодом и rdtscp + сохранение eax/edx + xor eax,eax + cpuid после. Если процессор поддерживает serialize, думаю, xor+cpuid стоит заменить им.

Ну и ещё можно использовать профилировщики, Intel Architecture Code Analyzer (последняя версия 2019 года).

1
23 ...

Информация

В рейтинге
3 646-й
Откуда
Самарская обл., Россия
Дата рождения
Зарегистрирован
Активность

Специализация

Десктоп разработчик, Бэкенд разработчик