Введите безопасные операции физики в С++

Оказывает ли смысл в С++ определять физические единицы как отдельные типы и определять действительные операции между этими типами?

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

Пример:

class Time{...};
class Length{...};
class Speed{...};
...
Time operator""_s(long double val){...}
Length operator""_m(long double val){...}
...
Speed operator/(const Length&, const Time&){...}

Где Time, Length и Speed могут быть созданы только как возвращаемый тип от разных операторов?

Ответ 1

Оказывает ли смысл в С++ определять физические единицы как отдельные типы и определять действительные операции между этими типами?

Совершенно верно. Стандартная библиотека Chrono уже делает это для временных точек и продолжительности.

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

Да: вы можете использовать систему типов для улавливания ошибок, таких как добавление массы на расстояние во время компиляции, без добавления каких-либо служебных программ.

Если вам не хочется самостоятельно определять типы и операторы, Boost имеет Units library для этого.

Ответ 2

Я бы рекомендовал boost:: units для этого. Он выполняет все время компиляции, а также дает вам ошибку времени компиляции, если вы пытаетесь использовать ошибочные измерения Пример кода psuedo:

length l1, l2, l3;
area a1 = l1 * l2; // Compiles
area a2 = l1 * l2 * l3; // Compile time error, an area can't be the product of three lengths.
volume v1 = l1 * l2 * l3; // Compiles

Ответ 3

Я пошел по этой дороге. Преимущества - все это обычные многочисленные и хорошие преимущества безопасности типов. Недостатки, с которыми я столкнулся:

  • Вы хотите сохранить промежуточные значения в вычислениях... например, в квадрате секунд. Если эти значения являются типом, это несколько бессмысленно (секунды ^ 2, очевидно, не такие, как velocity is).
  • Вам нужно делать все более сложные вычисления, которые потребуют большего количества перегрузок/операторов для достижения.

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

Ответ 4

Все упомянули гарантии безопасности типа как плюса. Еще один ОГРОМНЫЙ плюс - способность абстрагировать концепцию (длину) от единиц (метр).

Так, например, общая проблема при работе с единицами заключается в смешивании SI с метрикой. Когда понятия абстрагируются как классы, это уже не проблема:

Length width = Length::fromMeters(2.0);
Length height = Length::fromFeet(6.5);
Area area = width * height; //Area is computed correctly!
cout << "The total area is " << area.toInches() << " inches squared.";

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


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

Ответ 5

Для тех, кто ищет мощную библиотеку единиц времени, не требующую компиляции, но не согласен с перетаскиванием в зависимости от повышения, проверьте units. Библиотека реализована как один файл .h без зависимостей и поставляется с проектом для создания модульных тестов/документации. Он тестировался с помощью msvc2013, 2015 и gcc-4.9.2, а также должен работать с более поздними версиями этих компиляторов.

Полное раскрытие информации: я являюсь автором библиотеки

Ответ 6

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

Это может предотвратить умножение двух значений и завершение с недопустимым значением. Это может предотвратить суммирование долларов и евро и т.д.

Ответ 7

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

Ответ 8

Чтобы проверить безопасность типа, вы можете использовать выделенную библиотеку.

Наиболее разумно использовать boost:: units, он работает отлично, без накладных затрат времени, много функций. Если эта библиотека теоретически решает вашу проблему. С более практичной точки зрения интерфейс настолько неудобен и плохо документирован, что у вас могут быть проблемы. Более того, время компиляции резко возрастает с количеством измерений, поэтому четко проверьте, что вы можете скомпилировать в разумный срок большой проект перед его использованием.

doc: http://www.boost.org/doc/libs/1_56_0/doc/html/boost_units.html

Альтернативой является использование unit_lite. Есть меньше возможностей, чем библиотека boost, но компиляция выполняется быстрее, интерфейс проще и сообщения об ошибках являются читабельными. Этот lib требует С++ 11.

code: https://github.com/pierreblavy2/unit_lite

Ссылка на документ находится в описании github (мне не разрешено размещать здесь более двух ссылок!!!).

Ответ 9

Я дал учебную презентацию на CPPcon 2015 в библиотеке Boost.Units. Это мощная библиотека, которую должно использовать каждое научное приложение. Но это трудно использовать из-за плохой документации. Надеюсь, мой учебник поможет в этом. Вы можете найти слайды/код здесь: