Обновить
0

Студент/ Геймдизайнер

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

как сверху упомянули, странно что выходных значений меньше, но лично я бы это даже сказал так: странно, что входные регистры не переиспользуются как выходные. учитывая, что `rdx` вроде как всё же так и делает, хоть почему-то и один. есть ли причина по которой вся шестёрка + уже выходной `rax` не может использоваться как для входа так и для выхода? это чем-то неудобно?

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

не знаю как в конкретном случае, но всё же у упорядоченных ассоциативных массивов область применения время от времени да нередко находится, разве не так?

"Максимально" это конечно перегиб, всё же malloc гарантированно выровнен по выравниванию наиболее выровненного встроенного сишного типа (обычно выровнен в два машинных слова), чего просто атомикам, конечно, и хватит, но всё же для гарантий в более общем случае лучше использовать aligned_alloc, например при выравнивании по ширине кеш-линии, как иногда делается

Никакого нюанса нет, можно ограничение возможных значений считать просто инвариантом над u8, да и если захочется, всё ещё есть способы упаковать под ситуацию.

в расте это как будто окончательно решили тем, что запретили = возвращать что либо кроме (). как по мне, само то, что присваивание возвращает ссылку является стрельбой в ногу, как и возможность типам быть конвертируемыми в bool кроме пары случаев когда тип действительно близок по смыслу навроде bool? в C# ну или, может быть, любых option-типов

я не говорил о какой-то пользе трюка. это и есть просто цикл, записанный через рекурсию

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

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

да и просто то, что рекурсия написана нехвостовая, когда её почти тривиально можно сделать таковой, всё равно кажется не самой приятной вещью

Это другой алгоритм.

Нет, это то же самое

я её уже однажды придумав написал, и потому легко повторю ещё раз :)

uint64_t fib(uint64_t n, uint64_t curr = 0, uint64_t prev = 1) {
  if (n == 0) return curr;
  return fib (n-1, curr + prev, curr);
}

можно даже легко переписать для случаев, когда n < 0

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

немного странно, учитывая, что что факториал, что возведение в степень легко переписать через хвостовую рекурсию (хоть, конечно, и потребуется от компилятора её поддержка — но на gcc или clang это просто один флаг поставить)

далее планируемые числа фибоначи тоже

хотя вот числа аккермана и определитель без введения какого-то списка на куче кажутся тяжёлыми в этом плане (хотя я никогда не писал реализацию для аккермана хоть какую, так что знать не могу… вообще, это наверное просто вопрос того, чтоб немного поразмыслить)

в любом случае, для восстановления справедливости, не было бы неинтересным видеть тоже самое что писалось через "адекватные" циклы, написанным через tailrec

(впрочем, всё же очевидным минусом тут является в любом случае, что компилятор волен поступить как захочет)

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

кроме раста я наверное не знаю языков, в которых к синхронизации как-то принуждают (но я не особо и разбирался в теме), так что также будут интересны и сравнения (в расте же вроде есть трейты Sync и Send, которые мешают передавать значения нарушающие синхронизацию в другой поток — даже если разымплементировать их надо вручную для чего-то самописного; и чтобы взять ссылку из значения под мьютексом, нужно его залочить, если память не изменяет)

в той же java хочешь пиши synchronized-блоки, хочешь нет, вроде как, а плюсы как всегда позволяют тебе делать что хочешь, но по итогу слишком уж на отвали. (но опять же, я не очень прямо хорошо погружён, я лишь студент, который многопоток использовал лишь пару раз, так что могу ошибаться)

----

по поводу конструкторов:

в расте у полей значения по умолчанию запрещены, и каждое поле нужно обязательно инициализировать; чтобы же получить значение по умолчанию нужно использовать Default::default() или какой-нибудь _::new(), а чтобы проинициализировать напрямую нужноуказать значение для кпждого поля по отдельности.

противоположным является подход например в C, Java или C#, где если не указать значение по умолчанию, то выберется конструктор по умолчанию, null или т.п. Конечно, в C# есть required, который правда всё равно для части случаев будет так себе, а в плюсах можно написать какой-то собственный простенький тип, в котором будет что-то вроде

template<class T>
operator T() const
{
  static_assert(false);
}

, но как будто это костыли, о которых разработчики вряд ли будут думать (а может и будут, я не очень знаю).

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

заодно синтаксис value.{/*lambda*/} мне напоминает что-то похожее в сишарпе или джаве (хотя наверное в котлине оно и вовсе будет околоидиоматичным, хотя и не уверен):

new SomeType() {{
  some_field = ...;
  ...
}}
some_value with {some_field = ..., ...}
some_value.apply{
  some_field = ...
}

some_value.also{
  it.some_field = ...
}

впринципе, в C# (и Rust тоже вроде как) также можно и сделать extension-метод, чтобы работал так же как also в котлине, но всё равно котлин в этом плане как будто красивейший, и подход из аргентума мне напоминает его, тем более что это ещё и идёт по умолчанию — по дизайну решение безусловно красивое.

ну а так, мне тоже нравится будто бы повсеместный отказ от конструкторов (и от перегрузок функций в частности)

просто в аргентуме значение по умолчанию будто бы словно есть абсолютно всегда, если я правильно понимаю, что не во всех ситуациях полезно (условно не существует же никакого сокета или дескриптора файла по умолчанию — верно? а если и есть, то стоит считать, что он должен вести себя равно какому-нибудь null, не так ли?)

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

и если тут утверждается, что тут счёт ссылок неатомарный, то что будет в многопотоке?

есть ли какая-то гарантия что я не протащу слабую ссылку в другой поток имея возможность редактировать основную из этого?

последний абзац я уже не понимаю, ибо так всей этой теорией не интересовался, но я просто думаю, что для N-мерного пространства можно определить N-мерный тензор, который как бы будет результатом перемножения 0 элементов, и затем уже получать то что нужно как было сказано через тензорное произведение на векторы-множители

чисто технически, есть ведь ещё и типы-степени (функции)… сосредотачиваться лишь на суммах и произведениях — не так хорошо, я полагаю, но как бы с другой стороны, функции должны быть даже в тех япах, где нету структур… немного спускаясь в полуфилософскую шутливость, операции открылись словно наоборот от классической алгебры. если конечно не вспоминать о first class – функциях и замыканиях…

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

К тому же такое умножение 4 векторов всё равно работало бы также как и для 3д-умножения — результатом будет пятый, вектор перпендикулярный этим четырём, при том что его длина будет соответвовать площади гиперпараллелепипеда между ними. Как минимум, поиск перпендикулярного вектора это задача очень часто реально полезная.

да и если и рассматривать только пространства где произведения могут быть только от двух элементов, с этим же вопросом было бы интересно подойти по поводу того, как понять для ккких пространств определено произведение от n элементов для произвольного неотрицательного целого n. если условно произведение от 1 элемента определено для каждого пространства, от 2 лишь для 0, 1, 3, 7, от 0 при беглом обдумывании непонятно как определять кроме как для 1- и 0-мерного пространства — и вот это типа обобщить для произвольного фиксированного числа множителей.

знаю это, просто посчитал кодпоинты за символы

так-то да, просто я посчитал управляющие символы так же за символы.

но если делать именно так, то для условного о̴̷̰͙͓̰ͫ͗̉͜ͅ никаких 32 бит не хватит.

при том, для часто используемых сочетаний символ-лигатура (ё, だ, ã, …) и так есть отдельные кодпоинты. отдельно взятые лигатуры ведь нужны именно когда нужно олигатурить произвольный символ, нет? (хотя отдельно взятого э́ какого-нибудь не хватает или отдельных кодпоинтов для разных вариаций одного символа (привет, cjk) — но тут скорее вопрос к создателям юникода)

UTF-32 разве как раз этого не делает?

[[maybe_unused]] добавили в C++17. Даже до этого, если нет согласия с линтером и есть достаточная уверенность, что он брешет, вариант с (void) или любой другой подобной глушилкой был бы не так плох.

Собственно, я впринципе с точки зрения линтера не особо понимаю, в чём проблема, если переменная не использовалась в одной из веток — важнее же чтобы использовалась хотя бы в одной, разве нет?

Я не особо математик и могу чего-то не знать, поэтому скажу лишь свои мысли как обывателя.

Как будто векторное произведение определёно на любой мерности, просто придётся работать с тензорами, а не векторами.

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

Но вообще, если не лезть в тензоры, можно просто сказать, что век. произведение в ланной мерности N определено для N - 1 векторов.

Способ считать век. произведение как детерминант матрицы, где самая верхняя строчка это единичные векторы очень легко обобщается до многомерных пространств. Я этим в школе для своих развлечений вроде как типа и пользовался.

это не так? в 4-мерном пространстве двум векторам может быть перпендикулярна плоскость — не значит ли это, что любой вектор между двумя точками этой плоскости будет перпендикулярен изначальному вектору?

jit-компилятор мб смог бы, а вот aot только если в несколько проходов. ну или сделать какую-то статическую переменную на случай "ладно, не хочу". но не думаю, что aot-компилятороделы будут использовать такой динамический подход.

Информация

В рейтинге
7 550-й
Откуда
Беларусь
Дата рождения
Зарегистрирован
Активность

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

Разработчик игр
C++ stl
C#
Visual Studio