Согласен. Есть такое.
Проблема еще и в том, что я вначале выучил Ассемблер x86 и очень хорошо его знаю, а потом остальные языки, 6 профессионально и еще больше 20 понимаю и могу кодить. Но Ассемблер собака всё определяет. Почитал теорию компиляторов для практики и опять Ассемблер внёс свое. Что-то новое постоянно протряхивается через Ассемблер. Но какой код не мечтает стать Ассемблером (инструкциями процессора)?
На том свете отосплюсь. И -3/3*3 тестировал. Мне понравилось. И компилятору тоже. А вот -3/3u*3 компилятор плохо переварил, но многим вижу и это понравилось. Вот и не сплю спокойно с тех пор.
Кстати, чем тип -3 меньше типа 3?
И делить можно только то, что разрешил Стандарт?
Вы остерегайтесь UINT_MAX! Оно коварное!!! И близко не подходите к нему!
Только подошли к нему:
— шаг влево и теряете его
— шаг вправо и летите на самое дно самого глубокого ущелья, прямо в пасть UINT_MIN! И оно коварное также!!!
Ну да, инструкцию обычно читаем после того как что-то сломалось. И если в инструкции Стандарта сказано, что пациента в морг, значит в морг. Без базара.
А то что в Ассемблере такого и близко нет — это проблемы Ассемблера, хоть С++ и транслируется в него и вынужден следовать правилам Ассемблера.
Если представить небольшое отрицательное число, например -1 (0xFF) как 0x100-0x1 и обозначим 0x100 как Т, то перемножение двух небольших отрицательных чисел A и B представится в виде: A * B = (T-a)*(T-b) = T^2 - T*a - T*b - a*b = T*(T-a-b) + a*b => a*b
, здесь a = abs(A), b = abs(B)
При сохранении ответа в той же разрядности, что и A и B, останется только a*b, так как умножение на Т сдвигает результат за пределы разрядности.
Так что умножение знаковых чисел с MUL и беззнаковых IMUL даст правильный результат.
Компилятор транслирует код из С++ через несколько представлений в код процессора (читай Ассемблера). А у Ассемблера правил меньше, но они чёткие и ясные. И делить -3 на 3u командой DIV сразу вылезет боком.
Есть еще теория компиляторов. Там за такие преобразования сразу с экзамена долой.
Есть еще и другие языки программирования. На них такого поведения не наблюдается.
Хорошо задокументированная бага становится фичей! Многие не видят уже багу, а видят фигу фичу.
— Шеф! У нас убыток 3 ляма! Что делать?
— Раскидай его на троих. Скажи бухгалтеру, пусть посчитает доли, он в ИТ шарит.
Бухгалтер:
#include <iostream>
int main()
{
std::cout << -3/3u;
}
1431655764
— Шеф! Ура! Вы в выигрыше! Каждый из учредителей, по расчетам убытков, заработал 1431655764 ляма! Мы СуперМультиБиллионеры! Слава С++! Да здравствует Стандарт!
Представьте, что вы написали выражение, в которое вовлечены одни константы, представленные по разному, constexpr, define, const auto и так далее. Не вами они написаны, но вы их используете. И используете его в разных местах кода, которые требуют разные типы char, short, int, long, int64_t, int128_t, и -3 запросто может быть приведена к этим типам. Вот ответьте: Вы будете вводить 6 одинаковых констант с разными требуемыми типами, или введете одну, но будете доверять компилятору, что он сам выведет правильный тип и будет использовать правильные операции приведения? Без танцев с явным приведением типов.
Проблема еще и в том, что я вначале выучил Ассемблер x86 и очень хорошо его знаю, а потом остальные языки, 6 профессионально и еще больше 20 понимаю и могу кодить. Но Ассемблер собака всё определяет. Почитал теорию компиляторов для практики и опять Ассемблер внёс свое. Что-то новое постоянно протряхивается через Ассемблер. Но какой код не мечтает стать Ассемблером (инструкциями процессора)?
mov dword ptr [rbp - 8], 3 // int i = 3;
mov dword ptr [rbp - 12], 3 // unsigned u = 3;
mov eax, dword ptr [rbp - 8]
imul eax, dword ptr [rbp - 12] // eax = 9
mov ecx, 4294967293
xor edx, edx
div ecx // 9 / 4294967293 = 0
cmp eax, 0
Этот DIV, он такой DIVный!!!
-3/3*3
тестировал. Мне понравилось. И компилятору тоже. А вот-3/3u*3
компилятор плохо переварил, но многим вижу и это понравилось. Вот и не сплю спокойно с тех пор.Кстати, чем тип -3 меньше типа 3?
И делить можно только то, что разрешил Стандарт?
UINT_MAX
! Оно коварное!!! И близко не подходите к нему!Только подошли к нему:
— шаг влево и теряете его
— шаг вправо и летите на самое дно самого глубокого ущелья, прямо в пасть
UINT_MIN
! И оно коварное также!!!А этот опасен?:
А то что в Ассемблере такого и близко нет — это проблемы Ассемблера, хоть С++ и транслируется в него и вынужден следовать правилам Ассемблера.
A * B = (T-a)*(T-b) = T^2 - T*a - T*b - a*b = T*(T-a-b) + a*b => a*b
, здесь
a = abs(A), b = abs(B)
При сохранении ответа в той же разрядности, что и A и B, останется только a*b, так как умножение на Т сдвигает результат за пределы разрядности.
Так что умножение знаковых чисел с MUL и беззнаковых IMUL даст правильный результат.
Но деление — НЕТ!
(T-a)/(T-b) = ?
Есть еще теория компиляторов. Там за такие преобразования сразу с экзамена долой.
Есть еще и другие языки программирования. На них такого поведения не наблюдается.
Хорошо задокументированная бага становится фичей! Многие не видят уже багу, а видят
фигуфичу.— Раскидай его на троих. Скажи бухгалтеру, пусть посчитает доли, он в ИТ шарит.
Бухгалтер:
1431655764
— Шеф! Ура! Вы в выигрыше! Каждый из учредителей, по расчетам убытков, заработал 1431655764 ляма! Мы СуперМультиБиллионеры! Слава С++! Да здравствует Стандарт!