Типобезопасные физические операции в C++


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

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

пример:

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 может быть создан только как тип возврата от разных операторов?

9 56

9 ответов:

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

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

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

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

Если вы не хотите самостоятельно определять типы и операторы, Boost имеет подразделения библиотека для этого.

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

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

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

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

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

все упоминали гарантии безопасности типа как плюс. Еще одним огромным плюсом является возможность абстрагирования понятия (длины) от единиц измерения (метра).

Так, например, распространенной проблемой при работе с единицами является смешивание 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.";

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


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

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

полное раскрытие: я-автор библиотека

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

Это может предотвратить умножение двух значений и в конечном итоге с помощью недопустимое значение. Это может предотвратить суммирование долларов и евро и т. д.

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

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

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

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

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

код:https://github.com/pierreblavy2/unit_lite

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

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