Вектор, матрица, проектирование классов алгебры

#c #c 11

#c #c 11

Вопрос:

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

Что я принимаю во внимание, компилятор — это потрясающе, сейчас я знаю, что не могу быть умнее компилятора, но я хочу помочь ему по максимуму. C 11 приносит хорошие вещи, такие как семантика перемещения и другие вещи, такие как std::tuple ….

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

Где я немного потерялся и нуждаюсь в дополнительной информации:

A) Должны ли данные быть: value_type[Строки * Cols] (простой массив c) или value_type * (выделяются в куче строк размера * Cols) или использовать что-то вроде std::tuple

Б) Также наследование или композиция / агрегация У меня мог бы быть базовый класс шаблона для данных, или я мог бы сделать это с помощью композиции / агрегации

В) я видел 3 макета данных

D) Также в статье gamasutra (которая кажется старой, а компилятор сейчас лучше) Он говорит, что класс не должен иметь перегрузки оператора и вместо этого следует использовать глобальную функцию. Например, функция CrossProduct, чтобы сделать ее нечленом вместо функции-члена.

У меня есть все эти вопросы, я знаю, что их много. Что вы думаете о них, особенно о A и C.

Редактировать:

Спасибо всем за ответы на пункт A, я должен сказать, что на данный момент мой самый большой вопрос связан с пунктом C, извините, я знаю, что это было непонятно. Пункт c действительно касается дизайна классов. Я видел 2 варианта (вроде трех, если учесть этот статический трюк http://www.gamedev.net/topic/261920-a-slick-trick-in-c /) Я мог бы иметь для Вектора4, например, я мог бы иметь общедоступные элементы x, y, z и w, или я мог бы также объединить эти элементы и массив, или я мог бы иметь только массив и иметь функции X(), Y(), Z(), W() для средства доступа. И, наконец, есть статический трюк, который я предоставил по ссылке чуть выше, но я бы предпочел, чтобы x, y, z и w были статическими, а массив был бы элементом данных.

Комментарии:

1. «Я нахожусь в процессе разработки математической библиотеки». Еще одна математическая библиотека. Почему?

2. @CatPlusPlus: это может быть в образовательных целях

3. «просто потому, что» также является веской причиной для выполнения любого кода.

4. Вы не сказали, для чего будет использоваться библиотека. Это повлияет на ваш дизайн. Вам нужны матрицы 1000×1000, например? На каком оборудовании он будет работать?

5. Кроме того, не избегайте перегрузки операторов. Перегрузки операторов могут быть определены как глобальные функции, так зачем избегать читаемого подхода? После компиляции нет разницы между применением оператора и вызовом функции.

Ответ №1:

Обратитесь к Blitz . Также посмотрите его страницу «About«, чтобы получить представление об этом. Это одна из популярных математических библиотек промышленного уровня, написанных на C . Хотя вы не спросили, на какую библиотеку ссылаться, я привожу это главным образом потому, что вы можете извлечь уроки из некоторых вариантов дизайна, сделанных в этой библиотеке. Вы можете найти ответы на те самые вопросы, которые вы обдумываете.

Ответ №2:

Для небольшой матрицы 4×4 я бы избегал динамического выделения памяти в куче… простого одномерного массива, который вы можете индексировать как 2D-массив, должно быть достаточно (т. Е. Значение упорядоченной пары (x, y) будет matrix_array[COLUMNS * y x] ), особенно учитывая, что загрузка любого отдельного значения в массив также приведет к сохранению смежных значений в строке кэша процессора, ускоряядоступ к любым смежным элементам. Загрузка кэша может происходить и с выделенной памятью в куче, но основная причина, по которой следует избегать выделения кучи, если это возможно, для небольших матриц, заключается в том, что многие последовательные математические операции потребуют от вас возврата временного значения, а без ссылок на r-значения вы в конечном итоге будете выполнять много вызовови new delete внутри конструкторов копирования этих временных объектов, которые значительно замедлят работу по сравнению с быстрым выделением памяти в стеке.

Во-вторых, я бы посоветовал вам использовать шаблонный подход, так как это позволит вам определять матрицу не только для простых старых типов данных double , таких как и т.д., Но и для любых вторичных составных типов, которые вы можете решить определить позже, или импортировать из другой библиотеки, такой как рациональные числа, комплексные числаи т.д. Решите ли вы добавить перегрузки операторов, действительно зависит от вас … некоторым людям это не нравится, потому что оно «скрывает» сложность того, что может происходить под капотом (т.Е. A * B for doubles будет намного проще, чем A * B для 4×4 matrix<double> ). С другой стороны, это может значительно упростить объем кода, который вы пишете для сложных математических операций.

Комментарии:

1. Я знаю, что перегрузкой оператора можно злоупотреблять… но в этом случае это позволяет программировать близко к проблемной области. Это то, для чего была разработана языковая функция, поэтому, ИМХО, это подходящее место для ее использования. И, как отметил @Jason, это значительно упростит кодирование сложных операций (и менее подверженных ошибкам).

2. По вашему мнению, учитывая, что у нас есть семантика перемещения и что матрица по умолчанию будет занимать почти 0 памяти, вы бы все равно не реализовали ее с помощью указателя и выделения?

3. @user994652: ваши матрицы чрезвычайно малы (на данный момент не более 16 ячеек). Для небольших фрагментов данных, подобных этому, на самом деле нет причин платить цену, связанную с выделением кучи. Пока просто придерживайтесь стека, беспокойтесь о куче, когда все расширится еще немного. Кроме того, семантика перемещения помогает только при «копировании» данных временного значения в другую ячейку памяти. Большинство временных значений в математике исходят из больших выражений, которые находятся в процессе оценки, поэтому большинство из них даже не выиграют от семантики перемещения.

4. @Jason: Поправьте меня, если я ошибаюсь, но если бы он использовал обычный статический массив, то не было бы никакого снижения производительности, если бы он объявил его как 2D-массив. Имеет ли он 2D-массив, индексированный как matrix_array[x][y] , или 1D-массив, индексированный как matrix_array[x*y x] , не имеет значения, потому что они компилируются до одного и того же (хотя 1D-версия поможет при переходе к распределению кучи)

5. @KenWayneVanderLinde — Да, для нестатического элемента данных нет разницы, является ли это 2D-массивом или нет… как вы заметили, это действительно имело бы значение только для выделения кучи.