Pull to refresh
8
0
Владимир Закалык @Deohayer

Инженер встраеваемых систем

Send message

Экономить на спичках и желание чтобы оператор ++ НЕ ВЫДЕЛЯЛ ПАМЯТЬ это несколько разные вещи

Изменение оператора++ это то, что я считаю реальной оптимизацией (точнее, здравым смыслом, но не будем об этом). А вот использовать статический или динамический массив - это другое уже. Тут надо буквально сделать две разных имплементации, подобрать пару десятков юзкейсов, которые используют разные сценарии (в том числе явные перемещения, xvalue), измерить и сравнить. Конкретно эта задача для меня совсем не в приоритете, она уж слишком нишевая. Решение с динамическим массивом более универсально.

Если сделать там 0, то всё ещё будет вести себя не как обычное число

Ниже сказали, что перемещение "Leaves X in a valid but unspecified state".

Если вы всё же настаиваете, чтобы значение оставалось прежним, то извините, здравый смысл это здравый смысл. Для этого есть копирование. Хорошо, с этой точки зрения класс не ведёт себя как встроенный тип. Зато перемещение это действительно перемещение, а не простое копирование.

после move сразу использовать в любых выражениях и не получать UB или исключения

Повторю сюда тоже. Хорошо, переделаю так, чтобы после перемещения там был 0, и любое присваивание значения (из строки тоже) работало.

странновато не правда ли?

Нет, не думаю, что странновато. Просто разные взгляды. Почему я считаю, что надо использовать динамику:

  • Забирать столько стековой памяти - плохо. Просто потому что я ловил предупреждения о её переиспользовании в ходе разработки. Из-за других причин, но ограничения есть!

  • Моя библиотека не об экономии на спичках. За этим, ещё раз, к GNU MP.
    Адекватная реализация взаимодействия с базовыми типами, а не как сейчас, - ОК. Оптимизация алгоритмов - ОК. Реализация на стеке, хипе, и с кастомной аллокацией, чтобы угодить всем, - уже не ОК, так как это несколько разных библиотек надо написать.

  • Дальше я буду добавлять типы с динамическим размером. Их точно в стек не засунешь, и они отлично вписываются в уже существующую реализацию.

Это должно быть валидной операцией

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

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

Что будет если realloc вернёт ошибку

Обработку такой ситуации можно добавить. Хотя если такое произошло, то у вас в системе явно проблемы посерьёзнее.

Где поддержка аллокаторов тогда?(это не аллокатор)

Возможно будет, возможно нет. Зависит от того, насколько это будет нужно.
Таких "Где" для библиотек данного типа можно бесконечно придумать - по одному на каждый существующий юзкейс и алгоритм.

Потеря производительности при обращении по указателю

Если это проблема - то надо использовать GNU MP и больше ничего. Желательно вообще ничего не использовать, а прямо на ассемблере писать. И я сейчас без сарказма, вполне могу представить себе RTOS или что-то подобное, где частое обращение по указателю было бы проблемой.

но все кто мувает число считает, что в старом значении валидное опять же число. А вы экономите на memcpy 2-10 байт теряя на обращении через поинтер каждый раз и ломаете семантику поведения, ваши числа ведут себя не также как обычные инты

А ещё оператор sizeof() у меня неправильно возвращает количество байт :)
Экономлю 4096 / 8 = 512 байт (RSA). Ну, около того.
Если после std::move к xvalue переменной всё ещё можно обращаться для чтения значения, то это копирование, а не перемещение, вне зависимости от того, базовый тип это или объект. Если я неправ, то скиньте, пожалуйста, где в стандарте это сказано (любой, от 11 до 20). Возможно, я пропустил.

Кстати, realloc в С++ это вообще по умолчанию УБ, т.к. на компиляции неизвестно что делать с лайфтаймами объектов

Я эти функции использую для выделения памяти под массив базовых типов, POD. В стандарте указано, что функция стандартной же библиотеки - UB?

Простите что я тут вижу вообще? Это С?

Нет, это оптимизация работы с памятью!) Всё ради realloc. В будущем будет полезно, так как будут ещё и саморасширяющиеся типы (грубо говоря бесконечные), о них много вопросов было.

А сейчас, например, это позволяет оптимизировать операции перемещения (move) между целыми разных размеров:

ap_int<512> a = ap_int<1024>(5);

Вместо аллоцирования через new (make_unique) и копирования, просто переставляется указатель, а размер массива урезается при помощи realloc. Ну и если наоборот, слева размер больше, справа - меньше, то есть неплохой шанс, что realloc увеличит массив без копирования. И как приятный бонус: если копирование произошло, мне не надо делать никаких дополнительных вызовов или циклов для копирования, realloc всё сделал за меня.

Буду рад советам, как динамическую аллокацию можно реализовать лучше. Или чуть более детальному объяснению, чем плохи эти аллокаторы.

например почему компиляция из исходников это проблема?

Для header-only надо один include, для компиляции надо этот же include, плюс что-то компилировать. Даже если будет CMake, GNU Make, любая автоматизация этого процесса - надо будет ещё где-то тыкануть строку "вызови вот это вот". И прочитать о том, что нужно тыкануть эту строку. Для меня это минус - я ленивый, и хочу дать возможность таким же ленивым людям не делать лишних телодвижений при работе с библиотекой. При этом я не хочу обижать тех, кто знает о недостатках header-only подхода. Вот почему компиляция не просто "есть или нет" - она опциональна.

Почему поддержка gcc и msvc это кросплатформенность?

Контекстуально. Первой - популярный компилятор на Linux, второй - на Windows. "Я проверил компиляцию на двух ОС и сделал это вот такими компиляторами". Нет, кроме этих ни на чём другом не пробовал, признаюсь сразу. Обязательно попробую.

Что это вообще значит? Опция чтобы компилировалось?

Да, об этом отдельный пункт есть "Режим компиляции исходников". Если задефайнить AP_USE_SOURCES то нужно будет скомпилировать все .cpp файлы библиотеки, без каких-либо нюансов.

Что насчет поддержки С++20? Почему так явно перечислены 11 14 17?

Потому что я не проверял поддержку С++20 и, скорее всего, не работает. Упомянуто в пункте "Что в планах".

  1. Нет интеграций со системами сборки, так как интеграция тривиальна - нужно скачать репозиторий и добавить его в проект. "Добавить в проект" - расположить папку там, где хочется, опционально добавив её в include path. Если хочется компиляции - всё то же самое, плюс глобнуть все .cpp файлы, что делается одной строчкой в GNU Make / CMake. Для Visual Studio - пара кликов, он сама знает, что делать с .cpp.

  2. Это расписано в пункте "Тестирование". Есть чёткая система генерации операндов, она создаёт всевозможные сценарии комбинаций операндов, включая специфичные случаи (ноль, максимум, минимум, один, минус один).

  3. Тут оправдываться не могу. Документацию надо будет сделать.

что затрудняет написание обобщенного кода

Условная компиляция и вперёд. Не так красиво, как одна функция на все случаи жизни, конечно. Но гибкость важнее.

После определенной границы длины чисел, активно начинает работать другая асимптотика и другие алгоритмы, другие пропорции для K и для O(). Это также нужно учитывать.

Да, школьная классика уже работать не будет, и для случаев, когда скорость важна, есть GNU MP. Я не хочу соревноваться в скорости с библиотекой, которую разрабатывали десятки лет (точно проиграю), да и не нужно. Тривиальные вещи, вроде умножения Карацубы, - это без проблем.

С этим у slimcpplib все в порядке. Единственное, она запрещает неявные сужающие преобразования от большего значения к меньшему

Ну тогда всё отлично, корректное поведение.

Удачи! Больше хороших и нужных библиотек.

Спасибо!

Я смотрел для 128 битных беззнаковых целых

Не показатель. В Boost это просто использование __int128. slimcpplib тоже знает об этом типе. Надо смотреть что-то более показательное, хотя бы 4096, и запустить несколько тысяч раз хотя бы. Я этим займусь через пару недель :)

Тут надо определится для чего мы делаем библиотеку.

Всё просто: нам мало int, который даёт C++, мы дописываем свой, побольше, но так, чтобы было не отличить от настоящего, маленького. И в нём должно быть что-то для каждого. Всё, для чего есть несколько точек зрения, должно быть настраиваемым. Исключение: представление знаковых. Тут мимикрия под дополнительный код и арифметический сдвиг. Во-первых, это распространено, C++20 тому подтверждение (наконец-то!). Во-вторых, настраиваемость представления и поведения знаковых банально усложнит поддержку и тестирование, и всё ради опции, которая почти никому не нужна.

Должны быть и фиксированные, и свободно расширяющиеся инты. И стековая и динамическая память. И со знаком, и без знака. И с исключениями при переполнениях и делении на ноль, и без. И всё в таком духе дальше.

А что под этим (взаимодействие с базовым целым) подразумевается?

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

Это из-за того, что только в С++17 завезли нормальные литералы с которыми можно реализовать человеческий интерфейс

Тут не constexpr главный, а std::array, потому что с динамическим массивом это не работает. Но даже это можно добавить, сначала нужно реализовать большое целое на стеке, а дальше макросы наше всё: ap_linkage, ap_constexpr...

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

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

С ним ещё sizeof() правильно работать будет, тоже важно.

Спасибо, надо будет посмотреть. Постоянно сравнивать со всевозможными конкурентами неплохо так съедает время. Похоже, нужно написать фреймворк для анализа библиотеки такого типа, т. е. учитывать корректность работы, быстродействие и наличие конкретных элементов интерфейса (операторов и конструкторов). Всё равно хотел что-то подобное сделать, чтобы иметь возможность оценивать прогресс между версиями.

В slimcpplib использование std::array настораживает. И из-за этого интересует быстродействие.

Header-only это хорошо и удобно, все счастливы. "А сколько весит билд и длится компиляция?". После этих слов в программистском поезде начинается сущий кошмар.

constexpr - интересно, хорошо, что есть. По крайней мере, можно посчитать константы. Если они часто используются, то это неплохая оптимизация. То же решето Эратосфена - сохранить столько, сколько можно.

Если брать откровенную вкусовщину без анализа, то:

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

  2. std::array подразумевает много копирования.

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

  4. Нет интерфейса для взаимодействия с базовым целым (если я не пропустил).

  5. Только С++17. А 11, 14 и 17 одинаково популярны.

  6. Почему только header-only.

Information

Rating
Does not participate
Location
Львов, Львовская обл., Украина
Date of birth
Registered
Activity

Specialization

Embedded Software Engineer, Application Developer
Middle
C++
Object-oriented design
Algorithms and data structures
C
Multiple thread