Scaled Unit

A dimensionless multiple of a natural_unit

Context

_images/ditaa-44516ac41cfbf99953610e7761ac0749ffec492f.png

Introduction

#include <xo/unit/scaled_unit.hpp>

Extension of natural_unit to enable representing the intermediate result of multiplication (or division) of natural units.

  • represents a (dimensionless) multiple of a cartesian product of basis units.

  • constexpr implementation

  • limited support for fractional dimensions such as time^-1/2

object area_per_time<<scaled_unit>>
area_per_time : outer_scale_factor = 3048/10000
area_per_time : outer_scale_sq = 1.0
area_per_time : natural_unit = m2_per_min

object m2_per_min<<natural_unit>>
m2_per_min : n_bpu = 2
m2_per_min : bpu_v[]

object m2<<bpu>>
m2 : native_dim = dim::distance
m2 : scalefactor = 1/1
m2 : power = 2/1

object min<<bpu>>
min : native_dim = dim::time
min : scalefactor = 60/1
min : power = -1/1

area_per_time o-- m2_per_min
m2_per_min o-- m2
m2_per_min o-- min

scaled unit after (u::meter * u::foot / u::minute)

Scaled units with non-unity outer scalefactors arise as intermediate results of quantity arithmetic

Motivation

Consider multiplying two units:

using namespace xo::qty;

constexpr auto u_prod = u::meter * u::kilometer;

How should we represent the product?

We don’t want to mix units. Instead we consolidate on a common unit; to do this we accumulate a product of conversion factors from such consolidation.

For example:

static_assert(u_prod.n_bpu() == 1);
static_assert(u_prod[0].bu() == detail::bu::meter);
static_assert(u_prod[0].power() == power_ratio_type(2));
static_assert(u_prod.outer_scale_factor_ == xo::ratio::ratio<int64_t>(1000));
static_assert(u_prod.outer_scale_sq_ == 1.0);   // used if fractional dimension

Here we accumulate 1000, from converting kilometers to meters.

Division works similarly. In this example dimension cancel, but we still have a non-unity conversion factor.

namespace u = xo::qty::u;

constexpr auto u_div = u::meter / u::kilometer;

// dimensionlesss result
static_assert(u_prod.n_bpu() == 0);
static_assert(u_prod.outer_scale_factor_ == xo::ratio::ratio<int64_t>(1,1000));
static_assert(u_prod.outer_scale_sq_ == 1.0);

When multiple dimensions needing conversion are involved, scalefactors accumulate:

namespace u = xo::qty::u;

constexpr auto u2_prod = u::meter * u::hour * u::kilometer * u::minute;

static_assert(u2_prod.n_bpu() == 2);
static_assert(u2_prod[0].bu() == detail::bu::meter);
static_assert(u2_prod[1].bu() == detail::bu::hour);
static_assert(u2_prod.outer_scale_factor_ == xo::ratio::ratio<int64_t>(50,3));
static_assert(u2_prod.outer_scale_sq_ == 1.0);   // used if fractional dimension

Here the 50/3 result comes from multiplying 1000/1 (converting kilometers -> meters) by 1/60 (converting minutes -> hours)

Class

template<typename Int, typename OuterScale = ratio::ratio<Int>>
class scaled_unit

Represents the product sqrt(outer_scale_sq) * outer_scale_exact * nat_unit.

Member Variables

group Scaled-unit-instance-vars

Variables

OuterScale outer_scale_factor_

scale factor multiplying natural_unit_

double outer_scale_sq_

squared scale factor multiplying natural_unit_

natural_unit<Int> natural_unit_

natural unit term in this scaled unit

Type Traits

group scaled-unit type traits

Typedefs

using ratio_int_type = typename natural_unit<Int>::ratio_int_type

type for representing individual basis-unit scalefactors

Access Methods

group scaled-unit access methods

Functions

inline bool is_scaled_unit_type() const

always true for scaled_unit

inline bool is_natural() const

true iff scaled unit can be faithfully represented by a natural_unit

inline bool is_dimensionless() const

true if this scaled unit has no dimension

inline std::size_t n_bpu() const

get number of distinct native dimensions present. e.g. for unit Newton = 1 kg.m.s^-2, n_bpu would be 3, with {mass, distance, time} present. Note that this value does not count exponents

Variables

static bool is_scaled_unit_type_v = true

always true for scaled_unit

General Methods

group scaled-unit access methods

Functions

inline scaled_unit reciprocal() const

return reciprocal of this unit.

inline bpu<Int> lookup_dim(dimension d) const

get bpu for dimension d. if d isn’t present, construct bpu with 0 power

inline bpu<Int> &operator[](std::size_t i)

return i'th bpu associated with this unit

inline const bpu<Int> &operator[](std::size_t i) const

return i'th bpu associated with this unit (const version)

Operators

group Scaled-unit-operators

Functions

template<typename Int, typename Int2x = detail::width2x_t<Int>>
inline scaled_unit<Int> operator*(const scaled_unit<Int> &x_unit, const scaled_unit<Int> &y_unit)

Multiply scaled_unit instances x_unit and y_unit. Result is a scaled_unit for the product dimension. For each basis dimension, result will prioritize scale from x_unit ahead of y_unit.

template<typename Int, typename Int2x = detail::width2x_t<Int>>
inline scaled_unit<Int> operator/(const scaled_unit<Int> &x_unit, const scaled_unit<Int> &y_unit)

Divide scaled_unit instances x_unit by y_unit. Result is a scaled_unit for the quotient dimension. For each basis dimension, result will prioritize scale from x_unit ahead of y_unit.