Мы определяемединицукак набор базовых единиц, каждая из которых может быть поднята до произвольного рационального показателя. Таким образом, единица СИ, соответствующая размеру силы, составляет кг м s2, где кг, м и s являются базовыми единицами. Мы используем понятиеединицы системы, такой как SI, чтобы указать отображение от измерения к конкретному блоку, так что вместо явного указания базовых блоков мы можем просто попросить представление измерения в конкретной системе.
Единицы, как и измерения, являются чисто компилируемыми временными переменными без какого-либо связанного значения. Единицы подчиняются той же алгебре, что и измерения; наличие системы единиц служит для обеспечения того, чтобы единицы, имеющие одинаковые уменьшенные размеры в разных системах (например, футах и метрах), не могли быть случайно смешаны в вычислениях.
Существуют два различных типа систем, которые можно представить:
- Однородные системы: Системы, которые содержат линейно независимый набор базовых единиц, которые могут использоваться для представления множества различных измерений. Например, система СИ имеет семь базовых размеров и семь соответствующих им базовых единиц. Он может представлять собой любую единицу, которая использует только эти семь базовых измерений. Таким образом, это однородная система.
- Гетерогенные системы: Системы, в которых хранятся экспоненты каждой базовой единицы, называются неоднородными. Некоторые единицы могут быть представлены только таким образом. Например, площадь в метрах неоднородна, потому что базовые единицы метров и футов имеют одинаковые размеры. В результате простое хранение размерности и набора базовых единиц не дает уникального решения. Практическим примером необходимости в гетерогенных единицах является эмпирическое уравнение, используемое в авиации: H = (r/C)^2, где H - высота луча радара в футах, а r - дальность действия радара в морских милях. Для обеспечения точности измерений этого уравнения константа C должна быть выражена в морских милях на фут (1/2), смешивая две отдельные базовые единицы длины.
Устанавливаются единицы.<unit
>класс шаблона, определенный в<boost/units/unit.hpp
>:
template<class Dim,class System> class unit;
Помимо поддержки операций компиляционно-временного размерного анализа, для переменных<unit
>предусмотрены операторы +, -, * и / runtime. Поскольку размерность, связанная с полномочиями и корнями, должна быть вычислена во время компиляции, невозможно обеспечить перегрузки для<std::pow
>, которые функционируют правильно для<unit
>с. Эти операции поддерживаются посредством свободных функций<pow
>и<root
>, которые шаблонизированы на целых числах и<static_rational
>значениях и могут принимать в качестве аргумента любой тип, для которого классы полезности<power_typeof_helper
>и<root_typeof_helper
>были определены.
Базовые единицы определяются так же, как и размеры базы.
template<class Derived, class Dimensions, long N> struct base_unit { ... };
Опять же, отрицательные порядки зарезервированы.
В качестве примера, в следующем мы реализуем подмножество системы единиц СИ на основе приведенных выше фундаментальных измерений, демонстрируя все шаги, необходимые для полностью функциональной системы. Во-первых, мы просто определяем единичную систему, которая включает определения типов для обычно используемых единиц:
struct meter_base_unit : base_unit<meter_base_unit, length_dimension, 1> { };
struct kilogram_base_unit : base_unit<kilogram_base_unit, mass_dimension, 2> { };
struct second_base_unit : base_unit<second_base_unit, time_dimension, 3> { };
typedef make_system<
meter_base_unit,
kilogram_base_unit,
second_base_unit>::type mks_system;
typedef unit<dimensionless_type,mks_system> dimensionless;
typedef unit<length_dimension,mks_system> length;
typedef unit<mass_dimension,mks_system> mass;
typedef unit<time_dimension,mks_system> time;
typedef unit<area_dimension,mks_system> area;
typedef unit<energy_dimension,mks_system> energy;
Макро<BOOST_UNITS_STATIC_CONSTANT
>приведено в<boost/units/static_constant.hpp
>для облегчения постоянного определения ODR- и потоковой безопасности в файлах заголовка. Затем мы определяем некоторые константы для поддерживаемых единиц, чтобы упростить определения переменных:
BOOST_UNITS_STATIC_CONSTANT(meter,length);
BOOST_UNITS_STATIC_CONSTANT(meters,length);
BOOST_UNITS_STATIC_CONSTANT(kilogram,mass);
BOOST_UNITS_STATIC_CONSTANT(kilograms,mass);
BOOST_UNITS_STATIC_CONSTANT(second,time);
BOOST_UNITS_STATIC_CONSTANT(seconds,time);
BOOST_UNITS_STATIC_CONSTANT(square_meter,area);
BOOST_UNITS_STATIC_CONSTANT(square_meters,area);
BOOST_UNITS_STATIC_CONSTANT(joule,energy);
BOOST_UNITS_STATIC_CONSTANT(joules,energy);
Если требуется поддержка текстового вывода блоков, мы также можем специализировать класс<base_unit_info
>для каждого тега фундаментального измерения:
template<> struct base_unit_info<test::meter_base_unit>
{
static std::string name() { return "meter"; }
static std::string symbol() { return "m"; }
};
<kilogram_base_unit
>и<second_base_unit
>соответственно. Будущая версия библиотеки обеспечит более гибкую систему, позволяющую осуществлять интернационализацию через механизм фасетного/локального типа. Методы<name()
>и<symbol()
><base_unit_info
>дают полные и короткие названия базовой единицы. С помощью этих определений мы имеем зачаточные начала нашей системы единиц, которые могут быть использованы для определения уменьшенных размеров для произвольных расчетов единиц.
Теперь также можно определить базовую единицу как кратную другой базовой единице. Например, способ, которым<kilogram_base_unit
>определяется библиотекой, заключается в следующем:
struct gram_base_unit : boost::units::base_unit<gram_base_unit, mass_dimension, 1> {};
typedef scaled_base_unit<gram_base_unit, scale<10, static_rational<3> > > kilogram_base_unit;
Это в основном определяет килограмм как 103 раза грамм.
В этом подходе есть несколько преимуществ.
- Она лучше отражает реальное значение этих единиц, чем трактует их как самостоятельные единицы.
- Если конверсия определяется между граммами или килограммами и некоторыми другими единицами, она будет автоматически работать как для килограммов, так и для граммов, только с одной специализацией.
- Аналогично, если символ для граммов определяется как «g», то символ для килограммов будет «kg» без каких-либо дополнительных усилий.
Мы также можем масштабировать<unit
>в целом, а не масштабировать отдельные базовые единицы, которые его составляют. Для этого мы используем метафункцию<make_scaled_unit
>. Основной мотивацией для этой функции являются метрические приставки, определенные в<boost/units/systems/si/prefixes.hpp
>.
Простой пример его использования будет.
typedef make_scaled_unit<si::time, scale<10, static_rational<-9> > >::type nanosecond;
Наносекунда является специализацией<unit
>и может использоваться в обычном количестве.
quantity<nanosecond> t(1.0 * si::seconds);
std::cout << t << std::endl;