Здравствуйте, CreatorCray, Вы писали:
CC>Здравствуйте, netch80, Вы писали:
N>>Судя по принципиальному непониманию проблемы, кое-кто полетит одним из первых CC>Куда проще заменять нейросеткой пейсателей на памперсных языках, где памперсы примут в себя все косяки нейросетки, чем там, где надо чётко понимать что ты делаешь.
Сколько раз вас, кулхацкеров, надо ударить головой, чтоб вы поняли, что есть такое явление как случайные опечатки по невнимательности?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
хъ
N>Да, и вдогонку — а действительно, почему у тебя они в u8? Это же тип скорее для упаковки в структуру, чем для манипулирования. Во всех современных ABI всё равно будет один регистр занят, так что u8 или i32 — одномайственно.
Хм, я что-то пропустил и (в x86-64 например) из RAX куда-то исчезли AL/AX/EAX и команды умеющие с ними работать?
Здравствуйте, netch80, Вы писали:
N>А вот безразмерный int это уже ближе к вопросу.
Не ну всегда можно сделать язык в котором int будет подкапотно реализован через BigInteger а не POD типом, замапленным на платформенный тип.
С производительностью будут некоторые вопросы, но зато говнокодеру не надо будет думать.
CC>>Кстати интересно, осилит ли нейросетка написать double linked list на rust? N>Текущие — скорее нет, а зачем?
Просто интересно. Впрочем они "умеют" то, примеры чего уже есть в интернетах, так что скорее всего оно просто выдаст "переизобретение" уже написанного ранее.
N>А декомпозицию перекладываешь на человека? Читер.
А дизайном и декомпозицией должен заниматься инженер, больше некому.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, T4r4sB, Вы писали:
TB>Сколько раз вас, кулхацкеров, надо ударить головой, чтоб вы поняли, что есть такое явление как случайные опечатки по невнимательности?
Я уже достаточно долго живу чтоб воспринимать отмазку про подобные случайные очепятки это в стиле "хотел сказать "дорогая, передай пожалуйста соль" а сказал "что ж ты сука мне всю жизнь испортила!" "
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, Patalog, Вы писали:
N>>Да, и вдогонку — а действительно, почему у тебя они в u8? Это же тип скорее для упаковки в структуру, чем для манипулирования. Во всех современных ABI всё равно будет один регистр занят, так что u8 или i32 — одномайственно.
P>Хм, я что-то пропустил и (в x86-64 например) из RAX куда-то исчезли AL/AX/EAX и команды умеющие с ними работать?
Команды — есть. Упаковка разных параметров в один регистр в ABI — нет (с редкими особыми исключениями). Хранение в процессе использования внутри функции разных параметров, например, рядом в AL и AH — тоже нет, компиляторы такое не делают — им это ломает логику распределения регистров.
В ARM/32 регистры векторов и плавучки устроены так, что, например, D0 состоит из S0 и S1. В MIPS/64 регистры для 64-битных значений это пара 32-битных. Количество и кривость костылей для поддержки этого оказались такими, что повторять этот гимор никто не хочет. В ARM/64, RISC-V это тоже не повторили.
Преимущества манипулирования 8-битным значением в AL вместо 32-битного в EAX или 64-битного в RAX давно нет. Скорее наоборот — из-за проблемы, что комбинирование со старым значением сокращает возможности параллеления на переименовании регистров.
Здравствуйте, netch80, Вы писали:
N>А почему ты тут думаешь именно про i32? А вдруг и его переполнит, тогда оно должно было святым духом догадаться, что надо было конвертить всё к i64? Или как?
В идеале — ограничивать операнды, чтобы компилятор знал, что результат впишется в i32.
N>Перемножаем. Первое произведение int64_t, второе int96_t, третье int128_t... Астанавитесь(c), Вите надо выйти!
Перемножение в цикле — это проблема, да, тут увы приходится задать одно ограничение на результат и в каждой итерации следить что вписываемся.
N>Да, и вдогонку — а действительно, почему у тебя они в u8? Это же тип скорее для упаковки в структуру, чем для манипулирования. Во всех современных ABI всё равно будет один регистр занят, так что u8 или i32 — одномайственно.
Ещё раз с самого начала — если у тебя шахматная доска 256х256, то для координат фигуры нормальный человек конечно же будет использовать int. Но с точки зрения хипстера, обдолбавшегося доменно-ориентированной хренотой, использовать int это неправильно, надо использовать тип, который в принципе не может содержать некорректных значений. Не знаю зачем ему это надо, но он считает, что это круто. Ну типа в функции figure.place(u8 x, u8 y) мы на этапе компиляции знаем что значения валидны! При этом хипстеру насрать, что код валидации просто будет вынесен из сеттера во все места, где мы вычисляем эти координаты и никакого выигрыша мы не получим, более того, мы создаём грабли, если напишем figure1.x — figure2.y, случайно забыв скастовать в инт. Кулхацкеры конечно же никогда (на словах) не забывают сделать лишний каст, ведь они думают, что забыть сделать каст можно только если человек не знает, что u8 не позволяет вычитать большее из меньшего, но я сомневаюсь, что у них есть хоть какой-то опыт.
N>Но тут другое. С какой именно эпохи? Юниксовой (начало 1970 года) или виндовой (1601)? N>А может, с "юлианского дня" номер 1, как сделали в Delphi?
Да чесс слово — наплевать. Если в той же либе будет nanoseconds_to_year, которая консистентна с выбором начала эпохи.
N>Чем дальше в лес, тем толще партизаны код, тем сложнее следить за его качеством, включая 100500 аспектов, которые могут на него повлиять, и тем дороже каждое изменение. Поэтому средства поддержки в виде запрета некорректных операций — бесценны.
А вот и нет. Лишние запреты со стороны компилятора почему-то воспринимаются как абсолютное добро, но это не так. Во-первых, не все пишут прошивки для ядерных реакторов, я б сказал, что подавляющее большинство пишет код, в котором не требуется абсолютная надёжность. От падения программы просто завершится один процесс и в документ не попадут изменения за последнюю минуту. Память других программ не попортится, это не ДОС с убогим реальным режимом. Ещё со времён 386 процессора с его менеджером памяти уже есть абстракция, в которой любая программа, работающая с правами пользователя, уже является безопасной.
И если время, затрачиваемое на борьбу с компилятором больше, чем время, затрачиваемое на обнаружение и устранение бага — то лишние сложности в написании кода не только создают лишний гемор при написании и особенно рефакторинге, но и просто увеличат время создания работающего продукта. К сожалению, эпоха, когда средства повышения надёжности кода повышали и удобство программера, прошла. Да, придумали типы, структуры, функции, контрольные блоки, ифы, циклы всякие, гото стал не нужен, потом шаблоны, деструкторы. Это всё реально повышало и надёжность, и удобство. Но потенциал удобных способов повысить надёжность уже исчерпался. Теперь всё так: по умолчанию бери С++, если нужно чуть больше надёжности, бери Руст или жабошарп, если прямо угораешь по 100%-доказанности, то бери Идрис, но что-то полезное на них написать сложно.
Во-вторых, не все, что якобы повышает надёжность, действительно её повышает.
Вот те же вектора-точки. Допустим, я использую старпёрскую идеологически невыдержанную библиотеку, где вектор и точка это одно и то же.
Есть точка V. А есть плоскость, заданная уравнением V*N+C=0. И чтоб понять, с какой стороны точка находится от плоскости, я блин беру, и смотрю на знак этого самого V*N+C.
Как выглядит эта ситуация, если векторы и точки это разные сущности?! Я вижу два варианта:
1. Плоскость задаётся уравнением (P-C)*N=0, где P,C это точки, а N это вектор. Но тогда вычисление этой фигни как минимум требует лишние два вычитания.
2. Плоскость задаётся уравнением V*N+C=0, а чтоб понять, с какой стороны от этой плоскости находится точка, надо вычислить
(P-ZeroPoint)*N+C. И тут я боюсь, что любая мало-мальски сложная формула сведётся к бесконечным (P-ZeroPoint) вместо V, ну и в итоге формула будет содержать те же самые выражения, и при этом ошибиться в наборе формулы можно будет ровно в тех же местах. Более того, из-за ухудшившейся читаемости пропустить опечатку станет даже проще, и компилятор ничего не скажет.
Поэтому я просто не понимаю, от каких ошибок меня защитит разделение на точку и вектор, кроме опечаток вида (a+b)*0.6, которые легко обнаруживаются и исправляются. Из моих знакомых все, кто реально пользовался такой либой, отмечают крайнее неудобство, ну и обычно характеризуют их авторов как "сумасшедших фанатиков, оторванных от реальности".
> Для архива оставлю ссылку. (ты там активно участвовал)
Спасибо, добавлю ещё это: https://internals.rust-lang.org/t/subscripts-and-sizes-should-be-signed/17699
К сожалению, мой низкий уровень инглиша и фанатизм сообщества не позволили обратить внимание на проблему(
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, CreatorCray, Вы писали:
CC>Я уже достаточно долго живу чтоб воспринимать отмазку про подобные случайные очепятки это в стиле "хотел сказать "дорогая, передай пожалуйста соль" а сказал "что ж ты сука мне всю жизнь испортила!" "
Я достаточно долго работаю, чтоб видеть, как люди, в квалификации которых я не сомневаюсь, иногда выдают в код полнейшую дичь, которая проходит тесты, но при определённых условиях заполняет память мусором. Просто по запарке. А вот с тобой есть сомнения.
И если компилятор ничего не скажет, то всегда есть шанс, что программист с любым уровнем квалификации чисто случайно вместо
((a as i32 + b as i32) / 2).try_into().unwrap()
напишет
(a+b)/2
А идеология руста с ограничениями на типы требует постоянно писать хрень как в первом коде. И не дай бог забудешь про каст в широкий тип — компилятор ничего не скажет, а программа упадёт. Руст умеет сделать безопасный код опасным.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
хъ
P>>Хм, я что-то пропустил и (в x86-64 например) из RAX куда-то исчезли AL/AX/EAX и команды умеющие с ними работать?
N>Команды — есть. Упаковка разных параметров в один регистр в ABI — нет (с редкими особыми исключениями).
Ну, это явно не наш случай, коль речь про сложении двух чисел или забег по массиву.
N>Хранение в процессе использования внутри функции разных параметров, например, рядом в AL и AH — тоже нет, компиляторы такое не делают — им это ломает логику распределения регистров.
Тут не буду спорить, но когда я последний раз глядел в эту сторону (году этак в 12-13м) — вполне себе видел код со всеми этими прелестями EAXов уж точно, насчет AH/AL в свеже сгенеренном коде врать не буду, не помню, а вот в каких-то из системных библиотек 7-ки, в котором приходилось ковырятся отладчиком (была тема самопального PE загрузчика) — точно были.
Здравствуйте, T4r4sB, Вы писали:
TB>Я достаточно долго работаю, чтоб видеть, как люди, в квалификации которых я не сомневаюсь, иногда выдают в код полнейшую дичь, которая проходит тесты, но при определённых условиях заполняет память мусором. Просто по запарке.
За последние 20+ лет я ни разу не видел чтоб квалифицированные люди спороли что нить подобное "по запарке"
TB>А идеология руста с ограничениями на типы требует постоянно писать хрень как в первом коде.
Печальный язык.
TB> И не дай бог забудешь про каст в широкий тип — компилятор ничего не скажет, а программа упадёт.
Когда программа откровенно делает то, что от неё не ждали — программе лучше упасть чем спрятать какашку в памперс. Были моменты когда приходилось откровенные panic в кернеловский код вставлять вместо сообщения об ошибке, когда QA попытались заметать найденные баги под коврик.
TB>Руст умеет сделать безопасный код опасным.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, CreatorCray, Вы писали:
N>>А вот безразмерный int это уже ближе к вопросу. CC>Не ну всегда можно сделать язык в котором int будет подкапотно реализован через BigInteger а не POD типом, замапленным на платформенный тип. CC>С производительностью будут некоторые вопросы, но зато говнокодеру не надо будет думать.
И чё? (tm)
Для ~95% кода типичного приложения это нормально, от него высокой производительности не требуется. Зато то, как его пишут, вынуждает использовать защищённые средства по максимуму, чтобы работало.
И как минимум в половине случаев это не "говнокодер", а говноменеджмент с говнопроцедурами, услужливо выгибающийся под давлением говнодиректоров, реализующих планы на основании говнотребований говноинвесторов и не обеспечивающий минимальных ресурсов на качественную разработку. Кодеры тут последние, кто виноват.
Ты часом не менеджер? А то только и слышу от тебя наезды на "говнокодеров".
N>>А декомпозицию перекладываешь на человека? Читер. CC>А дизайном и декомпозицией должен заниматься инженер, больше некому.
Здравствуйте, T4r4sB, Вы писали:
N>>Перемножаем. Первое произведение int64_t, второе int96_t, третье int128_t... Астанавитесь(c), Вите надо выйти! TB>Перемножение в цикле — это проблема, да, тут увы приходится задать одно ограничение на результат и в каждой итерации следить что вписываемся.
Так нет принципиальной разницы со сложением или вычитанием. Сложил два int32_t, получил int33_t. Прибавил к нему int32_t, можешь формально получить int34_t. И так далее.
Даже если транслятор не оперирует напрямую такими типами (LLVM — может, там любая битность допустима почти до самой зашкальной), то подсчёт диапазонов значений может к такому привести.
Потому возвращаемся к исходному — или своевременный контроль, или наплевательство, или явное разрешение усечения (а местами — насыщения, saturating mode), или, как в С для знаковых, доверие программисту. Но на чём-то надо остановиться.
Почему я постоянно и говорю — кто лучше знает, что именно тут надо, кроме автора кода? А раз он знает — может и должен явно указать. А компилятор должен позволять такие указания и правильно их отрабатывать.
N>>А почему ты тут думаешь именно про i32? А вдруг и его переполнит, тогда оно должно было святым духом догадаться, что надо было конвертить всё к i64? Или как? TB>В идеале — ограничивать операнды, чтобы компилятор знал, что результат впишется в i32.
Не будет такого идеала. В общем случае ты можешь просто не знать заранее, впишутся они или нет.
Исключения (паника) в рантайме — простой, надёжный, хоть и дорогой, метод получить тут гарантии вместе со стандартизованной (а часто и структурированной) обработкой ошибок.
Они сами по себе не проблема. Проблема — когда забывают обрабатывать ошибки, или административно не дают на это ресурсов, или когда (как ты описываешь) неудобно и громоздко всё конвертировать к адекватным типам.
Но именно в последнем случае — удобно или использовать стандартное "продвижение" целого (integral promotion), как в C/C++/много_где, или самим предварительно расширить все рабочие значения. Иногда этого расширения не хватает, увы. Но по крайней мере в твоём примере с u8 должно хватить.
N>>Да, и вдогонку — а действительно, почему у тебя они в u8? Это же тип скорее для упаковки в структуру, чем для манипулирования. Во всех современных ABI всё равно будет один регистр занят, так что u8 или i32 — одномайственно. TB>Ещё раз с самого начала — если у тебя шахматная доска 256х256, то для координат фигуры нормальный человек конечно же будет использовать int. Но с точки зрения хипстера, обдолбавшегося доменно-ориентированной хренотой, использовать int это неправильно, надо использовать тип, который в принципе не может содержать некорректных значений. Не знаю зачем ему это надо, но он считает, что это круто.
У тебя тут принципиально проблемные переходы:
1. От типа, который содержит только корректные значения (что правильно) — к конкретным вариантам типа u8. Какое твоё нафиг дело на этом уровне, сколько в нём бит? Может, у него вообще два корректных значения +238 и -245. Сколько ты на него бит выделишь — 1, 9, 16, 32? Пусть компилятор думает об этом, у него голова большая быстрее считает.
2. От диапазона значений конкретного базового типа вроде i32 ты переходишь к тому, как выполняются операции с ним. И вот тут, предполагая, что i32+i32 даёт i32, ты почему-то пытаешься получить, что 0..255 + 0..255 должен дать 0..510, а из этого — что i8+i8 даёт i9. Но почему тогда i32+i32 не должно дать i33? (см. выше)
Посмотри в этом смысле на Ada. Там можно определять типы в стиле
type chess_coord = Integer range 0..255;
После этого, насколько помню, в вычислениях используется продвижение целых до Integer (или, если сказано явно, до LongInt), контролируется переполнение согласно этому размеру, но при укладке в переменную проверяется диапазон (ну кроме если компилятор уверен, что выхода за его пределы не будет). Выглядит удобно и средне-разумно, позволяя отрабатывать максимум типовых ситуаций безболезненно и контролируемо.
(А для нужд всяких кольцевых счётчиков там есть типы целых в стиле "modulo 2**32". Вот с ними операции выполняются в модульной арифметике, как беззнаковые в C/C++.)
TB> Ну типа в функции figure.place(u8 x, u8 y) мы на этапе компиляции знаем что значения валидны! При этом хипстеру насрать, что код валидации просто будет вынесен из сеттера во все места, где мы вычисляем эти координаты и никакого выигрыша мы не получим,
Меняю мысленно u8 на "integer range 0..255". Вообще-то получим выигрыш: точно не будет молчаливого усечения значения. А какая цена проверок — зависит от компилятора. Во многих случаях он может их просто выкинуть.
TB> более того, мы создаём грабли, если напишем figure1.x — figure2.y, случайно забыв скастовать в инт.
Вполне себе аргумент в пользу удобства integral promotion для типовых операций. Но, с другой стороны, операция получения разности координат это особая операция, при которой меняется тип. Это было ещё в C: можно вычитать два однотипных указателя, получим разность между ними (причём разность адресов делится на размер указуемого). Почему не сделать такое же?
Причём это надо делать (в синтаксисе C++/GCC) так:
using coord_t = uint_t<8>;
using coord_diff_t = int_t<9>;
inline coord_diff_t operator-(coord_t a, coord_t b) {
coord_diff_t ret;
__builtin_sub_overflow(a, b, &ret); // No overflow happensreturn ret;
}
Ну а дальше у тебя будет просто figure1.x — figure2.y которое молча под капотом правильно выполнится.
TB> Кулхацкеры конечно же никогда (на словах) не забывают сделать лишний каст,
"Кулхацкеры" — да, возможно.
Нормальные хакеры сделают, как я описал выше, и забудут про проблему.
Rust это позволяет, но я не хочу выгибаться вспоминать, как в нём это делается. Но концептуально это 1:1 описанный подход C++.
N>>Чем дальше в лес, тем толще партизаны код, тем сложнее следить за его качеством, включая 100500 аспектов, которые могут на него повлиять, и тем дороже каждое изменение. Поэтому средства поддержки в виде запрета некорректных операций — бесценны.
TB>А вот и нет. Лишние запреты со стороны компилятора почему-то воспринимаются как абсолютное добро, но это не так. Во-первых, не все пишут прошивки для ядерных реакторов, я б сказал, что подавляющее большинство пишет код, в котором не требуется абсолютная надёжность.
Подавляющее большинство пишет код, в котором проверки надёжности несущественно влияют на скорость и объём. А те 1-5%, которые пишут критичный к этому код в отдельных местах, заинтересованы в специальных опциях ради этого ровно в этих отдельных местах.
Я недавно с одним проектом работал, в котором принципиально -O0 во всех компиляциях. Ничего, ресурсов хватало (управляющий слой над железкой). Создатели решили, что это лучше, чем бодаться с возможными проблемами даже от простого -O (не знаю, было ли тогда -Og, но они и его не включили).
А вот диагностика ситуации "процесс X не отработал запрос потому, что в этот момент упал процесс Y, а проверка криво сделана в промежуточном процессе Z, который выдал неполные данные" может обойтись на порядки дороже, чем однократное корректное написание. Особенно если это у субкастомера кастомера в пределах концерна-клиента.
Лучше пусть оно диагностируемо упадёт, чем выдаст неправильные данные.
TB> От падения программы просто завершится один процесс и в документ не попадут изменения за последнюю минуту. Память других программ не попортится, это не ДОС с убогим реальным
От падения — да, вероятно — и см. выше какие сценарии бывают (и я это реально видел).
А если оно молча выдаст неверные данные?
TB> режимом. Ещё со времён 386 процессора с его менеджером памяти уже есть абстракция, в которой любая программа, работающая с правами пользователя, уже является безопасной.
Нет.
И вообще, я не понимаю — выше ты против того, чтобы u8 + u8 проверялось на выход за пределы диапазона u8 — а теперь что? Ты уж определись.
TB> И если время, затрачиваемое на борьбу с компилятором больше, чем время, затрачиваемое на обнаружение и устранение бага — то лишние сложности в написании кода не только создают лишний гемор при написании и особенно рефакторинге, но и просто увеличат время создания работающего продукта. К сожалению, эпоха, когда средства повышения надёжности кода повышали и удобство программера, прошла.
Не прошла. Но многие из теперешних метаний выглядят, согласен, бессмысленными.
TB>Во-вторых, не все, что якобы повышает надёжность, действительно её повышает. TB>Вот те же вектора-точки. Допустим, я использую старпёрскую идеологически невыдержанную библиотеку, где вектор и точка это одно и то же. TB>Есть точка V. А есть плоскость, заданная уравнением V*N+C=0. И чтоб понять, с какой стороны точка находится от плоскости, я блин беру, и смотрю на знак этого самого V*N+C. TB>Как выглядит эта ситуация, если векторы и точки это разные сущности?! Я вижу два варианта: TB>1. Плоскость задаётся уравнением (P-C)*N=0, где P,C это точки, а N это вектор. Но тогда вычисление этой фигни как минимум требует лишние два вычитания. TB>2. Плоскость задаётся уравнением V*N+C=0, а чтоб понять, с какой стороны от этой плоскости находится точка, надо вычислить TB>(P-ZeroPoint)*N+C. И тут я боюсь, что любая мало-мальски сложная формула сведётся к бесконечным (P-ZeroPoint) вместо V, ну и в итоге формула будет содержать те же самые выражения, и при этом ошибиться в наборе формулы можно будет ровно в тех же местах. Более того, из-за ухудшившейся читаемости пропустить опечатку станет даже проще, и компилятор ничего не скажет.
Возможно, я что-то упускаю, но почему не создать промежуточную переменную типа "вектор", которая, по твоим описаниям, будет равна P-ZeroPoint, адекватно назвать её и дальше использовать в формулах?
(Причём при нормальной оптимизации компилятор операцию вида P-ZerPoint внутри себя превратит в копирование скаляров, потом проведёт через SSA, устранив копирования.)
>> Для архива оставлю ссылку. (ты там активно участвовал) TB>Спасибо, добавлю ещё это: https://internals.rust-lang.org/t/subscripts-and-sizes-should-be-signed/17699 TB>К сожалению, мой низкий уровень инглиша и фанатизм сообщества не позволили обратить внимание на проблему(
Почитал. Английский действительно так себе, но на дискуссию, по-моему, это не повлияло совсем. Там и хуже пишут (не в оправдание). Явного фанатизма я тоже не заметил. Что заметил:
1) Есть уже принятые решения (может, и преждевременно), которые менять сложно без полного слома языка: сохранение типа в операциях (что u8*u8 -> u8) и беззнаковый размер (даже если фактически не выходит за пределы знакового).
2) Есть масса приёмов (там приведены в примерах), которые дают возможность избежать подавляющего большинства проблем от этих решений.
Вообще их ответы очень интересны именно этими примерами.
Я лично бы сделал, да, integral promotions контекстно-устанавливаемыми. Но я плохо представляю себе, как это сочетать с дизайном языка. Вот пишешь ты impl для одного своего типа... нужны разные варианты функций в зависимости от этих параметров контекста? Компилятор должен уметь подбирать эти типы? Жестоко.
Здравствуйте, Patalog, Вы писали:
N>>Хранение в процессе использования внутри функции разных параметров, например, рядом в AL и AH — тоже нет, компиляторы такое не делают — им это ломает логику распределения регистров.
P>Тут не буду спорить, но когда я последний раз глядел в эту сторону (году этак в 12-13м) — вполне себе видел код со всеми этими прелестями EAXов уж точно,
Именно для x86 тут есть принципиальная разница:
1. Большинство команд в 32-битном варианте короче (нет REX префикса).
2. Исполнение команды над 32-битными версиями регистров чистит старшие 32 бита регистра, поэтому зависимости от предыдущего значения архитектурного регистра не создаётся. А вот для операций с xL, xH, xX (x=A,B,C,D), SIL, DIL... чистки верхней части не происходит, это специфическое наследие x86 из 1980-х, когда они об этом не думали. (Почему не думали — не знаю, OoO с переименованием регистров растёт минимум из 1969, но у Intel собственная гордость.)
Поэтому оптимизация с работой с EAX вместо RAX и т.п. — полезна, а с AX, AL, AH — уже (почти всегда) нет.
Работу с AH можно найти или в ручном ассемблерном коде, или в результате peephole-оптимизаций, где, например, b = a>>8; заменяется на извлечение AH (и то, только в случае если значение уже сидит в регистре, а писать в память).
Типовые более современные RISC-архитектуры (ARM, RISC-V) не имеют подобной специфики потому, что у них вообще нет неполной загрузки в регистр, любое загруженное значение расширяется до полной ширины. В ARM, если таковая нужна, надо сначала загрузить во временный регистр, а потом доработать командой группы BFM. Аналогичное есть, например, в SystemZ (IC, RISBG и тому подобные команды).
P> насчет AH/AL в свеже сгенеренном коде врать не буду, не помню, а вот в каких-то из системных библиотек 7-ки, в котором приходилось ковырятся отладчиком (была тема самопального PE загрузчика) — точно были.
Здравствуйте, CreatorCray, Вы писали:
TB>>Я достаточно долго работаю, чтоб видеть, как люди, в квалификации которых я не сомневаюсь, иногда выдают в код полнейшую дичь, которая проходит тесты, но при определённых условиях заполняет память мусором. Просто по запарке. CC>За последние 20+ лет я ни разу не видел чтоб квалифицированные люди спороли что нить подобное "по запарке"
Ну как бы... Не то, чтобы претендовал на то, чтобы числиться сильно уж квалифицированным, но какая-то квалификация все-таки есть. Вот, давеча потратил кучу времени на то, чтобы найти и устранить баг, внесенный собственноручно года полтора назад по явному недосмотру.
Здравствуйте, so5team, Вы писали:
S>Вот, давеча потратил кучу времени на то, чтобы найти и устранить баг, внесенный собственноручно года полтора назад по явному недосмотру.
Баги делают все. Вопрос скорее в том, была ли это та самая "очепятка", про которую ты тут рассказываешь или что нить менее очевидное?
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, netch80, Вы писали:
N>Так нет принципиальной разницы со сложением или вычитанием. Сложил два int32_t, получил int33_t. Прибавил к нему int32_t, можешь формально получить int34_t. И так далее.
Да, в худшем случае всё равно придётся контролировать результат на вписываемость в рамки.
N>Они сами по себе не проблема. Проблема — когда забывают обрабатывать ошибки, или административно не дают на это ресурсов, или когда (как ты описываешь) неудобно и громоздко всё конвертировать к адекватным типам.
Так я говорю — подход Раста самый консистентный, и в нём в целом проблемы нет. Проблема возникает, когда хипстор, обдолбавшийся домен драйвером, начинает использовать u8 для хранения координат на доске 256х256.
N>1. От типа, который содержит только корректные значения (что правильно) — к конкретным вариантам типа u8.
В языке нет более простого способа задать тип, который умеет принимать только значения из 0..255.
Вариант со структурой с упоротым сеттером и перегруженными всеми операциями не предлагать, на деле любое обобщение в операциях с числами приводит к дополнительному гемору.
N>Посмотри в этом смысле на Ada.
Я знаю, как в Ada, я на ней даже пару программ писал. Но это вообще даже близко не мейнстрим.
N>Вполне себе аргумент в пользу удобства integral promotion для типовых операций. Но, с другой стороны, операция получения разности координат это особая операция, при которой меняется тип. Это было ещё в C: можно вычитать два однотипных указателя, получим разность между ними (причём разность адресов делится на размер указуемого). Почему не сделать такое же? N>Ну а дальше у тебя будет просто figure1.x — figure2.y которое молча под капотом правильно выполнится.
Почему бы просто не взять с самого начала сраный инт и не морочить голову?
N>А вот диагностика ситуации "процесс X не отработал запрос потому, что в этот момент упал процесс Y, а проверка криво сделана в промежуточном процессе Z, который выдал неполные данные" может обойтись на порядки дороже, чем однократное корректное написание. Особенно если это у субкастомера кастомера в пределах концерна-клиента.
Я не спорю, что есть задачи, где надёжность превыше всего. Но большинство из нас работают не с ними.
N>И вообще, я не понимаю — выше ты против того, чтобы u8 + u8 проверялось на выход за пределы диапазона u8 — а теперь что? Ты уж определись.
Я уже написал несколько раз: я против использования разных целый чисел в каждой задаче. Это хипстерская придурь, которая только вынуждает пердолиться с кастами. В русте у вектора размер имеет тип usize, но в библиотеке для работы с bmp размер уже имеет тип u32, и если ты её используешь и из вектора данные как-то по точкам пишешь в битмап, то твой код это "ехал каст через каст".
Но почему-то только один я вижу тут проблему: https://github.com/sondrele/rust-bmp/issues/31
Нормальный человек использует инт. Если инта не хватает — то это либо формула неправильная, либо очень специфичная задача, где малой кровью уже не отделаешься и надо уже думать, как иначе организовать подсчёт.
N>Возможно, я что-то упускаю, но почему не создать промежуточную переменную типа "вектор", которая, по твоим описаниям, будет равна P-ZeroPoint, адекватно назвать её и дальше использовать в формулах?
А что я тогда выигрываю? Я написал сложную формулу с векторами и опечатался. Потом я применил крутую безопасную либу, и написал ту же формулу, но вместо векторов везде подставил P-ZeroPoint, и снова опечатался. Разница в том, что я написал менее читаемую строчку, но не получил никакого выигрыша ни в надёжности ни в скорости создания продукта.
N>2) Есть масса приёмов (там приведены в примерах), которые дают возможность избежать подавляющего большинства проблем от этих решений. N>Вообще их ответы очень интересны именно этими примерами.
Проблема в том, что вместо того, чтобы взять инт и не париться, приходится каждый раз использовать специальный приём, причём если забудешь это сделать, то у тебя программа упадёт.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, CreatorCray, Вы писали:
CC>За последние 20+ лет я ни разу не видел чтоб квалифицированные люди спороли что нить подобное "по запарке"
Звучит, как будто ты 20+ лет не работал с кодом.
TB>>А идеология руста с ограничениями на типы требует постоянно писать хрень как в первом коде. CC>Печальный язык.
Не язык, а сообщество. Взять инт и не париться — не для нас. Надо взять u8 и самим себе создать проблему, а потом героически её решать.
CC>Когда программа откровенно делает то, что от неё не ждали — программе лучше упасть чем спрятать какашку в памперс.
Я не про поведение программы, а про модные тенденции использовать "тип который не может принимать некорректные значения". Как только у нас начинается арифметика, это всё летит лесом.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>Звучит, как будто ты 20+ лет не работал с кодом.
Вот с таким говнокодом, за который ты тут топишь, к счастью приходилось иметь дело крайне редко.
TB>Взять инт и не париться — не для нас.
TB>Как только у нас начинается арифметика, это всё летит лесом.
У типа с нестандартным поведением должны быть перекрыты его же операторы.
Или в расте так не умеют?
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, T4r4sB, Вы писали:
TB>Ну мы уже поняли, что тебе вообще приходилось программировать крайне редко.
20+ лет только этим и занимаюсь.
TB>>>Взять инт и не париться CC>> TB>Что ты хочешь сказать?
Эта песня хороша, начинай сначала.
TB>Перегрузить операторы для стандартного u8? Нет, не умеют.
Для своего типа
Если у тебя есть что то с нестандартным поведением то надо не "взять int и не париться" а сделать свой тип с заданным поведением.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, T4r4sB, Вы писали:
TB>Так я говорю — подход Раста самый консистентный, и в нём в целом проблемы нет. Проблема возникает, когда хипстор, обдолбавшийся домен драйвером, начинает использовать u8 для хранения координат на доске 256х256.
А ты не видишь, что одно другому противоречит у тебя? Координата влезает в u8, но операции с ней делать в u8 ни-ни, надо конвертить к нужным размерам, и лучше чтобы само догадалось. Причём, какие операции и почему — ты сказать не хочешь. Может, там факториал координаты браться будет? (это шахматы, там много чего может быть )
Я как раз никакой такой уж преобладающей консистентности не вижу. Сишное неотменяемое расширение с последующим слабоконтролируемым сужением — да, часто даёт проблемы и избыточно, но жёсткие противоположные рамки тоже не лучший вариант.
Вот где, например, операция вида u8*u8->u16? Что, всегда писать расширение до u16 с последующим умножением (а компилятор должен обратно догадаться использовать команду косого умножения)? Дайте её в виде функции/метода. Почему это есть в Forth или в GCC builtins, но не в нормальном языке? (Для C++ были предложения, но не прошли.)
N>>Так нет принципиальной разницы со сложением или вычитанием. Сложил два int32_t, получил int33_t. Прибавил к нему int32_t, можешь формально получить int34_t. И так далее. TB>Да, в худшем случае всё равно придётся контролировать результат на вписываемость в рамки.
Его _всегда_ придётся контролировать хотя бы на уровне определения компилятору, что тут делают. Компилятор сейчас не может работать иначе, если он хочет нормально оптимизировать. И вот тут надо решать (а лучше всего — давать кодеру задавать вариант), что делать. Главное — консистентность и удобство правил на таком уровне, чтобы не требовать лишних слов на каждое входное-выходное значение и на каждую операцию.
N>>1. От типа, который содержит только корректные значения (что правильно) — к конкретным вариантам типа u8. TB>В языке нет более простого способа задать тип, который умеет принимать только значения из 0..255.
Вот почему я вспоминал Ada.
TB>Вариант со структурой с упоротым сеттером и перегруженными всеми операциями не предлагать, на деле любое обобщение в операциях с числами приводит к дополнительному гемору.
Ну, наверно, там не сделали мягкое адекватное обобщение.
N>>Посмотри в этом смысле на Ada.
TB>Я знаю, как в Ada, я на ней даже пару программ писал. Но это вообще даже близко не мейнстрим.
"Не мейнстрим" к чему тут вообще?
Разве тяжело сделать аналогичное для C++ или Rust?
По-моему, они уже давно есть в десятках вариантов для каждого.
N>>Вполне себе аргумент в пользу удобства integral promotion для типовых операций. Но, с другой стороны, операция получения разности координат это особая операция, при которой меняется тип. Это было ещё в C: можно вычитать два однотипных указателя, получим разность между ними (причём разность адресов делится на размер указуемого). Почему не сделать такое же? N>>Ну а дальше у тебя будет просто figure1.x — figure2.y которое молча под капотом правильно выполнится.
TB>Почему бы просто не взять с самого начала сраный инт и не морочить голову?
Возьми. Я вот и удивляюсь, почему ты использовал u8 вместо int. У тебя структура с ними? Ну так проконвертируй в момент извлечения.
N>>А вот диагностика ситуации "процесс X не отработал запрос потому, что в этот момент упал процесс Y, а проверка криво сделана в промежуточном процессе Z, который выдал неполные данные" может обойтись на порядки дороже, чем однократное корректное написание. Особенно если это у субкастомера кастомера в пределах концерна-клиента.
TB>Я не спорю, что есть задачи, где надёжность превыше всего. Но большинство из нас работают не с ними.
НЕТ.
Мы все работаем с ними.
Сейчас сложность любой простейшей системы в компьютере, включая железо, прошивки, ОС и прикладные программы, такая, что любые подобные эффекты начинают фатально и недиагностируемо (потому что слишком сложно) влиять на работу. Последние годы, когда ты мог честно сказать "большинство работают не с ними" это примерно 1990-й год.
И хорошо если это BSOD — хуже, если это скрытая порча данных.
N>>И вообще, я не понимаю — выше ты против того, чтобы u8 + u8 проверялось на выход за пределы диапазона u8 — а теперь что? Ты уж определись. TB>Я уже написал несколько раз: я против использования разных целый чисел в каждой задаче.
Я не увидел этого прямым текстом, ну да ладно.
Но как тогда ты будешь разбираться с тем, что на до чёрта современных платформ иногда нужен long = i64, но он сильно дороже, чем i32? Будешь пытаться обобщать всех до размера iptr?
А знаковость/беззнаковость, её тоже обобщим?
А 3-4 современных разных типа float?
TB> Это хипстерская придурь, которая только вынуждает пердолиться с кастами. В русте у вектора размер имеет тип usize, но в библиотеке для работы с bmp размер уже имеет тип u32, и если ты её используешь и из вектора данные как-то по точкам пишешь в битмап, то твой код это "ехал каст через каст". TB>Но почему-то только один я вижу тут проблему: https://github.com/sondrele/rust-bmp/issues/31
Посмотрел. Насколько я понял, выбор i32 тут происходит из i32 в структуре заголовка BMP, а значит, внутри библиотеки не будет проблем типа "значение не влезло в сгенерированный заголовок".
Или же они пошли по пути "i32 умолчание — делаем в нём" (это уже вопрос, почему в Rust явный i32, а не зависимый от платформы int).
Если первое, то я бы так не делал. Тут согласен с твоим тикетом, примерно на 2/3. Треть оставляю на то, что i32 тут ограничение контекста, которое имеет смысл таки применять во всём, что в этом контексте.
Если второе, то это неустранимо в пределах Rust.
Ещё вариант — что они подумали о платформах, где isize == i64, но манипулирование с таким размером усложнено и дороже (например, MIPS/64).
TB>Нормальный человек использует инт.
Которого нет в Rust.
N>>Возможно, я что-то упускаю, но почему не создать промежуточную переменную типа "вектор", которая, по твоим описаниям, будет равна P-ZeroPoint, адекватно назвать её и дальше использовать в формулах?
TB>А что я тогда выигрываю? Я написал сложную формулу с векторами и опечатался. Потом я применил крутую безопасную либу, и написал ту же формулу, но вместо векторов везде подставил P-ZeroPoint, и снова опечатался.
Опечатался в чём?
TB> Разница в том, что я написал менее читаемую строчку, но не получил никакого выигрыша ни в надёжности ни в скорости создания продукта.
Получил выигрыш.
Я не знаю, как в твоём домене, но я возился с NumPy+SciPy. Там очень любят использовать одну операцию для 100500 разных действий, типа одним '*' умножать матрицу и на скаляр, и на вектор. И когда оно вылетает в рантайме оттого, что, например, ndarray вместо matrix — это ещё полбеды, тесты ловят сразу. А если молча делает не то — приходится разлагать на микрооперации, примерно как ты рассказываешь про касты, и сравнивать тип каждого с желаемым.
Предпочитаю явные касты.
N>>2) Есть масса приёмов (там приведены в примерах), которые дают возможность избежать подавляющего большинства проблем от этих решений. N>>Вообще их ответы очень интересны именно этими примерами.
TB>Проблема в том, что вместо того, чтобы взять инт и не париться, приходится каждый раз использовать специальный приём, причём если забудешь это сделать, то у тебя программа упадёт.
Вообще-то тебе там никто не мешает размер сразу привести к isize.