c ++ 11 — Тип безопасных физических операций в переполнении стека

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

56

Решение

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

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

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

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

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

53

Другие решения

Я бы очень рекомендовал повышение :: единиц за это. Он выполняет все преобразования во время компиляции, а также выдает ошибку времени компиляции, если вы пытаетесь использовать ошибочные измерения.
пример кода 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
21

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

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

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

13

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

Так, например, общая проблема при работе с единицами — это смешивание СИ с метрикой. Когда понятия абстрагируются как классы, это больше не проблема:

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.";

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


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

10

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

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

4

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

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

1

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

1

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

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

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

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

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

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

1
По вопросам рекламы [email protected]