Обеспечение семантического контроля над размерностями станда
От: CrystaX Россия https://crystax.me/
Дата: 20.11.05 21:58
Оценка: 43 (8)
Собственно, это логическое продолжение кода из ветки В поисках семантической корректности
Автор: Нахлобуч
Дата: 18.05.05
, а именно Re[15]: В поисках семантической корректности
Автор: CrystaX
Дата: 23.05.05
. Наконец у меня дошли руки до отделения зерен от плевел и вот результат.

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

Возможности:
1. Независимые типы данных, такие как mass и length. Присвоить один другому нельзя — будет ошибка компиляции.
2. Автоматическое конвертирование величин одной и той же размерности из одной системы единиц в другую. К примеру, присвоив килограммам один грамм, в результирующей переменной (si::mass) обнаружим 0.001. Вычисление коэффициентов преобразования производится в compile time.
3. Контроль за корректностью формул со стороны компилятора. Так, если ускорению попытаться присвоить результат деления длины на время, возникнет ошибка компиляции. С моей точки зрения, это наиболее важное свойство моего кода. Особенно это заметно на трехэтажных формулах, где очень легко потерять из виду, какая же в результате получается размерность. В случае использования моего кода подобного рода ошибки полностью исключаются.

Пример:
#include <iostream>
#include <units.hpp>

using namespace units;

int main()
{
    cgs::mass m1(1); // 1 грамм
    si::mass m2(m1); // Автоматическое преобразование в килограммы. В результате получаем 0.001 кг

    std::cout << "Mass in SI: " << m2 << ", in CGS: " << m1 << std::endl;

    cgs::length l1(100); // 100 см
    si::length l2(l1);   // Автоматическое преобразование. Результат - 1 м

    std::cout << "Length in SI: " << l2 << ", in CGS: " << l1 << std::endl;

    cgs::time t1(1); // 1 с
    si::time t2(t1); // Тоже 1 с, т.к. единицы измерения времени в системах СИ и СГС совпадают.

    std::cout << "Time in SI: " << t2 << ", in CGS: " << t1 << std::endl;

    // Теперь немного более сложный пример. Предыдущие величины (масса, длина, время) являются
    // базовыми (ортами) в обеих системах единиц. Здесь же мы имеем дело с производными величинами -
    // скоростью, енергией и мощностью
    cgs::velocity v1(10); // 10 см/с
    si::velocity v2(v1);  // Результат преобразования - 0.1 м/с

    std::cout << "Velocity in SI: " << v2 << ", in CGS: " << v1 << std::endl;

    si::energy e1(0.0001); // 10e-4 Дж.
    cgs::energy e2(e1);    // e2 = 1000 эрг

    std::cout << "Energy in SI: " << e1 << ", in CGS: " << e2 << std::endl;

    // Это - пример работы с внесистемными единицами. В данном случае мощность переводится из ваттов
    // в лошадиные силы
    si::power p1(1000); // 1000 Вт
    ext::power p2(p1);  // 1.35962 лс

    std::cout << "Power in SI: " << p1 << ", in Ext system: " << p2 << std::endl;

    // Пример работы с простейшими арифметическими действиями
    si::acceleration a1(1); // 1 м/с2
    cgs::acceleration a2;
    a2 = a1 + cgs::acceleration(200); // 1 м/с2 + 200 см/с2 = 300 см/с2, как и должно было быть

    std::cout << "Acceleration: a1 = " << a1 << ", a2 = " << a2 << std::endl;

    // Сила
    si::force f1(10);      // 10 Н
    cgs::force f2 = f1*2;  // 10 Н * 2 = 2000000 дин

    si::force f3 = m1*l2/(t1*t1); // 1 г * 1 м / (1 с * 1 с) = 0.001 Н
    // А вот так уже не скомпилируется - не та размерность
    //si::force f4 = m1*l2/t1;

    // Вот что выдает MS VC 7.1: error C2440: 'initializing' : cannot convert from 
    //     'units::unit<T,System,Tag>' to 'units::unit<T,System,Tag>'
    // А вот что GCC 3.4.2 (mingw): 
    // test.cpp: In function `int main()':
    // test.cpp:59: error: conversion from `units::unit<long double, units::helpers::systems::CGS, 
    //         boost::mpl::vector<mpl_::int_<1>, mpl_::int_<1>, mpl_::int_<-0x000000001>, mpl_::int_<0>, 
    //         mpl_::int_<0>, mpl_::int_<0>, mpl_::int_<0>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, 
    //         mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na> >' 
    // to non-scalar type `units::unit<long double, units::helpers::systems::SI, units::helpers::force_tag>'
    // requested


    std::cout << "Force: f1 = " << f1 << ", f2 = " << f2 << ", f3 = " << f3 << std::endl;

    // Здесь ошибка компиляции - пытаемся складывать енергию, массу и скорость
    //std::cout << "ERROR = " << (e1 + e2 + v1 + v2 + m1 + m2) << std::endl;

    // Здесь происходит преобразование на лету. В результате имеем 0.0002 Дж - результат имеет тот же тип, 
    // что и левый операнд
    std::cout << "Result = " << e1 + e2 << std::endl;

    // Здесь выводится единица, т.к. e1 и e2 содержат одно и то же значение, но выраженное в разных 
    // системах единиц
    std::cout << "Result = " << e1/e2 << std::endl;
    
    return 0;
}


Исходники дальше.
... << RSDN@Home 1.1.4 stable rev. 510>>
Исходники
От: CrystaX Россия https://crystax.me/
Дата: 20.11.05 22:01
Оценка:
/*
 * Copyright (c) 2005 by Dmitry Moskalchuk aka CrystaX
 * mailto:crystax@gmail.com
 *
 * All rights reserved.
 *
 */

#ifndef UNITS_HPP
#define UNITS_HPP

#include <iostream>

#include <boost/mpl/vector.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/size.hpp>

#include <cmath>

namespace units
{

namespace helpers
{

using boost::mpl::vector;
using boost::mpl::int_;
using boost::mpl::at;
using boost::mpl::size;

// system tags

//               mass    length   time  temperature      light intensity
//                 |        |       |        |                   |
//                 |        |       |        | current strength  |  quantity of substance
//                 |        |       |        |        |          |      |
//                 v        v       v        v        v          v      v
typedef vector<int_<1>, int_<0>, int_<0>, int_<0>, int_<0>, int_<0>, int_<0> > mass_tag;
typedef vector<int_<0>, int_<1>, int_<0>, int_<0>, int_<0>, int_<0>, int_<0> > length_tag;
typedef vector<int_<0>, int_<0>, int_<1>, int_<0>, int_<0>, int_<0>, int_<0> > time_tag;
typedef vector<int_<0>, int_<0>, int_<0>, int_<1>, int_<0>, int_<0>, int_<0> > temperature_tag;
typedef vector<int_<0>, int_<0>, int_<0>, int_<0>, int_<1>, int_<0>, int_<0> > current_strength_tag;
typedef vector<int_<0>, int_<0>, int_<0>, int_<0>, int_<0>, int_<1>, int_<0> > light_intensity_tag;
typedef vector<int_<0>, int_<0>, int_<0>, int_<0>, int_<0>, int_<0>, int_<1> > quantity_of_substance_tag;

typedef vector<int_<0>, int_<2>, int_<0>, int_<0>, int_<0>, int_<0>, int_<0> > area_tag;
typedef vector<int_<0>, int_<3>, int_<0>, int_<0>, int_<0>, int_<0>, int_<0> > volume_tag;
typedef vector<int_<0>, int_<1>, int_<-1>, int_<0>, int_<0>, int_<0>, int_<0> > velocity_tag;
typedef vector<int_<0>, int_<1>, int_<-2>, int_<0>, int_<0>, int_<0>, int_<0> > acceleration_tag;
typedef vector<int_<0>, int_<1>, int_<-1>, int_<0>, int_<0>, int_<0>, int_<0> > angular_velocity_tag;
typedef vector<int_<0>, int_<1>, int_<-2>, int_<0>, int_<0>, int_<0>, int_<0> > angular_acceleration_tag;
typedef vector<int_<1>, int_<0>, int_<-3>, int_<0>, int_<0>, int_<0>, int_<0> > density_tag;

typedef vector<int_<1>, int_<1>, int_<-2>, int_<0>, int_<0>, int_<0>, int_<0> > force_tag;
typedef vector<int_<1>, int_<-2>, int_<-2>, int_<0>, int_<0>, int_<0>, int_<0> > specific_gravity_tag;
typedef vector<int_<1>, int_<-1>, int_<-2>, int_<0>, int_<0>, int_<0>, int_<0> > pressure_tag;

typedef vector<int_<1>, int_<1>, int_<-1>, int_<0>, int_<0>, int_<0>, int_<0> > linear_momentum_tag;
typedef vector<int_<1>, int_<2>, int_<0>, int_<0>, int_<0>, int_<0>, int_<0> > moment_of_inertia_tag;

typedef vector<int_<1>, int_<2>, int_<-2>, int_<0>, int_<0>, int_<0>, int_<0> > energy_tag;
typedef vector<int_<1>, int_<2>, int_<-3>, int_<0>, int_<0>, int_<0>, int_<0> > power_tag;

typedef vector<int_<1>, int_<-1>, int_<-1>, int_<0>, int_<0>, int_<0>, int_<0> > dynamic_viscosity_tag;
typedef vector<int_<1>, int_<-1>, int_<-1>, int_<0>, int_<0>, int_<0>, int_<0> > kinematic_viscosity_tag;

typedef vector<int_<1>, int_<2>, int_<-2>, int_<-1>, int_<0>, int_<0>, int_<0> > heat_capacity_tag;
typedef vector<int_<1>, int_<2>, int_<-2>, int_<-1>, int_<0>, int_<0>, int_<0> > entropy_tag;
typedef vector<int_<0>, int_<2>, int_<-2>, int_<-1>, int_<0>, int_<0>, int_<0> > specific_heat_tag;
typedef vector<int_<0>, int_<2>, int_<-2>, int_<-1>, int_<0>, int_<0>, int_<0> > specific_entropy_tag;

typedef vector<int_<0>, int_<0>, int_<1>, int_<0>, int_<1>, int_<0>, int_<0> > charge_tag;
typedef vector<int_<0>, int_<-1>, int_<1>, int_<0>, int_<1>, int_<0>, int_<0> > linear_density_of_charge_tag;
typedef vector<int_<0>, int_<-2>, int_<1>, int_<0>, int_<1>, int_<0>, int_<0> > surface_density_of_charge_tag;
typedef vector<int_<0>, int_<-2>, int_<1>, int_<0>, int_<1>, int_<0>, int_<0> > electric_flux_density_tag;
typedef vector<int_<0>, int_<-3>, int_<1>, int_<0>, int_<1>, int_<0>, int_<0> > packed_density_of_charge_tag;

typedef vector<int_<1>, int_<2>, int_<-3>, int_<0>, int_<-1>, int_<0>, int_<0> > voltage_tag;
typedef vector<int_<1>, int_<1>, int_<-3>, int_<0>, int_<-1>, int_<0>, int_<0> > electric_force_tag;

typedef vector<int_<1>, int_<2>, int_<-3>, int_<0>, int_<-2>, int_<0>, int_<0> > resistance_tag;
typedef vector<int_<1>, int_<3>, int_<-3>, int_<0>, int_<-2>, int_<0>, int_<0> > specific_resistance_tag;

typedef vector<int_<-1>, int_<-2>, int_<4>, int_<0>, int_<2>, int_<0>, int_<0> > permittance_tag;

typedef vector<int_<0>, int_<-2>, int_<0>, int_<0>, int_<1>, int_<0>, int_<0> > current_density_tag;

// utils
template <bool Condition, typename T1, typename T2> struct if_else;
template <typename T1, typename T2> struct if_else<true, T1, T2> {typedef T1 type;};
template <typename T1, typename T2> struct if_else<false, T1, T2> {typedef T2 type;};

template <typename T1, typename T2> struct add_;
template <int N1, int N2, int N3, int N4, int N5, int N6, int N7,
    int M1, int M2, int M3, int M4, int M5, int M6, int M7
>
struct add_<
    vector<int_<N1>, int_<N2>, int_<N3>, int_<N4>, int_<N5>, int_<N6>, int_<N7> >,
    vector<int_<M1>, int_<M2>, int_<M3>, int_<M4>, int_<M5>, int_<M6>, int_<M7> >
>
{
    typedef vector<int_<N1 + M1>, int_<N2 + M2>, int_<N3 + M3>, int_<N4 + M4>, int_<N5 + M5>,
        int_<N6 + M6>, int_<N7 + M7> > type;
};

template <typename T1, typename T2> struct substract_;
template <int N1, int N2, int N3, int N4, int N5, int N6, int N7,
int M1, int M2, int M3, int M4, int M5, int M6, int M7
>
struct substract_<
    vector<int_<N1>, int_<N2>, int_<N3>, int_<N4>, int_<N5>, int_<N6>, int_<N7> >,
    vector<int_<M1>, int_<M2>, int_<M3>, int_<M4>, int_<M5>, int_<M6>, int_<M7> >
>
{
    typedef vector<int_<N1 - M1>, int_<N2 - M2>, int_<N3 - M3>, int_<N4 - M4>, int_<N5 - M5>,
        int_<N6 - M6>, int_<N7 - M7> > type;
};

template <int Value, unsigned Power>
struct meta_power
{
    static int const value = meta_power<Value, Power - 1>::value * Value;
};

template <int Value>
struct meta_power<Value, 0>
{
    static int const value = 1;
};

template <typename Fraction, int Power>
struct fraction_power
{
    static int const nominator = if_else<Power < 0, meta_power<Fraction::denominator, -Power>,
        meta_power<Fraction::nominator, Power> >::type::value;
    static int const denominator = if_else<Power < 0, meta_power<Fraction::nominator, -Power>,
        meta_power<Fraction::denominator, Power> >::type::value;
};

// traits

template <typename Tag, typename System1, typename System2>
struct unit_traits
{
private:
    typedef unit_traits<mass_tag, System1, System2> mass_traits;
    typedef unit_traits<length_tag, System1, System2> length_traits;
    typedef unit_traits<time_tag, System1, System2> time_traits;
    typedef unit_traits<temperature_tag, System1, System2> temperature_traits;
    typedef unit_traits<current_strength_tag, System1, System2> current_strength_traits;
    typedef unit_traits<light_intensity_tag, System1, System2> light_intensity_traits;
    typedef unit_traits<quantity_of_substance_tag, System1, System2> quantity_of_substance_traits;

    static int const p1 = at<Tag, int_<0> >::type::value;
    static int const p2 = at<Tag, int_<1> >::type::value;
    static int const p3 = at<Tag, int_<2> >::type::value;
    static int const p4 = at<Tag, int_<3> >::type::value;
    static int const p5 = at<Tag, int_<4> >::type::value;
    static int const p6 = at<Tag, int_<5> >::type::value;
    static int const p7 = at<Tag, int_<6> >::type::value;

public:
    static int const nominator =
        fraction_power<mass_traits, p1>::nominator *
        fraction_power<length_traits, p2>::nominator *
        fraction_power<time_traits, p3>::nominator *
        fraction_power<temperature_traits, p4>::nominator *
        fraction_power<current_strength_traits, p5>::nominator *
        fraction_power<light_intensity_traits, p6>::nominator *
        fraction_power<quantity_of_substance_traits, p7>::nominator;
    static int const denominator = 
        fraction_power<mass_traits, p1>::denominator *
        fraction_power<length_traits, p2>::denominator *
        fraction_power<time_traits, p3>::denominator *
        fraction_power<temperature_traits, p4>::denominator *
        fraction_power<current_strength_traits, p5>::denominator *
        fraction_power<light_intensity_traits, p6>::denominator *
        fraction_power<quantity_of_substance_traits, p7>::denominator;
    static int const power =
        p1 * mass_traits::power +
        p2 * length_traits::power +
        p3 * time_traits::power +
        p4 * temperature_traits::power +
        p5 * current_strength_traits::power +
        p6 * light_intensity_traits::power +
        p7 * quantity_of_substance_traits::power;
};

namespace systems
{

struct SI {};
struct CGS {};
struct EXT {};

} // namespace systems

template <>
struct unit_traits<mass_tag, systems::SI, systems::CGS>
{
    // kg to g -> 1/1000
    static int const nominator = 1;
    static int const denominator = 1;
    static int const power = -3;
};

template <>
struct unit_traits<mass_tag, systems::CGS, systems::SI>
{
    // g to kg -> 1000/1
    static int const nominator = 1;
    static int const denominator = 1;
    static int const power = 3;
};

template <>
struct unit_traits<length_tag, systems::SI, systems::CGS>
{
    // m to sm
    static int const nominator = 1;
    static int const denominator = 1;
    static int const power = -2;
};

template <>
struct unit_traits<length_tag, systems::CGS, systems::SI>
{
    // sm to m
    static int const nominator = 1;
    static int const denominator = 1;
    static int const power = 2;
};

template <>
struct unit_traits<time_tag, systems::SI, systems::CGS>
{
    static int const nominator = 1;
    static int const denominator = 1;
    static int const power = 0;
};

template <>
struct unit_traits<time_tag, systems::CGS, systems::SI>
{
    static int const nominator = 1;
    static int const denominator = 1;
    static int const power = 0;
};

template <>
struct unit_traits<temperature_tag, systems::SI, systems::CGS>
{
    static int const nominator = 1;
    static int const denominator = 1;
    static int const power = 0;
};

template <>
struct unit_traits<temperature_tag, systems::CGS, systems::SI>
{
    static int const nominator = 1;
    static int const denominator = 1;
    static int const power = 0;
};

template <>
struct unit_traits<current_strength_tag, systems::SI, systems::CGS>
{
    static int const nominator = 1;
    static int const denominator = 3;
    static int const power = -9;
};

template <>
struct unit_traits<current_strength_tag, systems::CGS, systems::SI>
{
    static int const nominator = 3;
    static int const denominator = 1;
    static int const power = 9;
};

template <>
struct unit_traits<light_intensity_tag, systems::SI, systems::CGS>
{
    static int const nominator = 1;
    static int const denominator = 1;
    static int const power = 0;
};

template <>
struct unit_traits<light_intensity_tag, systems::CGS, systems::SI>
{
    static int const nominator = 1;
    static int const denominator = 1;
    static int const power = 0;
};

template <>
struct unit_traits<quantity_of_substance_tag, systems::SI, systems::CGS>
{
    static int const nominator = 1;
    static int const denominator = 1;
    static int const power = 0;
};

template <>
struct unit_traits<quantity_of_substance_tag, systems::CGS, systems::SI>
{
    static int const nominator = 1;
    static int const denominator = 1;
    static int const power = 0;
};

template <>
struct unit_traits<power_tag, systems::SI, systems::EXT>
{
    static int const nominator = 1471;
    static int const denominator = 2;
    static int const power = 0;
};

template <>
struct unit_traits<power_tag, systems::EXT, systems::SI>
{
    static int const nominator = 2;
    static int const denominator = 1471;
    static int const power = 0;
};

} // namespace helpers

template <typename T, typename System, typename Tag>
class unit
{
public:
    explicit unit(T const &t = T()) :value(t) {}
    unit(unit const &u) :value(u.value) {}

    template <typename OtherSystem>
    unit(unit<T, OtherSystem, Tag> const &u)
        :value(u.base() * std::pow(10., helpers::unit_traits<Tag, System, OtherSystem>::power) *
        helpers::unit_traits<Tag, System, OtherSystem>::nominator /
        helpers::unit_traits<Tag, System, OtherSystem>::denominator)
    {}

    T const &base() const {return value;}

    unit operator-() const {return unit(-value);}
    unit const &operator+() const {return *this;}
    unit &operator+() {return *this;}

    unit &operator+=(unit const &rhs) {value += rhs.value; return *this;}
    unit &operator-=(unit const &rhs) {value -= rhs.value; return *this;}

    unit &operator++() {++value; return *this;}
    unit operator++(int ) {unit tmp(*this); ++value; return tmp;}

    unit &operator--() {--value; return *this;}
    unit operator--(int ) {unit tmp(*this); --value; return tmp;}

    template <typename Scalar>
    unit &operator*=(Scalar const &rhs) {value *= rhs; return *this;}

    template <typename Scalar>
    unit &operator/=(Scalar const &rhs) {value /= rhs; return *this;}

private:
    T value;
};

template <typename T>
inline T val(T const &v) {return v;}

template <typename T, typename System, typename Tag>
inline T val(unit<T, System, Tag> const &v) {return v.base();}


template <typename T, typename System, typename Tag>
inline std::ostream &operator<<(std::ostream &s, unit<T, System, Tag> const &u)
{
    s << val(u);
    return s;
}

template <typename T, typename System1, typename System2, typename Tag>
unit<T, System1, Tag> operator+(unit<T, System1, Tag> const &x, unit<T, System2, Tag> const &y)
{
    unit<T, System1, Tag> tmp(x);
    return tmp += y;
}

template <typename T, typename System1, typename System2, typename Tag>
unit<T, System1, Tag> operator-(unit<T, System1, Tag> const &x, unit<T, System2, Tag> const &y)
{
    unit<T, System1, Tag> tmp(x);
    return tmp -= y;
}

template <typename T, typename System1, typename System2, typename Tag1, typename Tag2>
unit<T, System1, typename helpers::add_<Tag1, Tag2>::type>
operator*(unit<T, System1, Tag1> const &x, unit<T, System2, Tag2> const &y)
{
    unit<T, System1, Tag2> tmp(y);
    return unit<T, System1, typename helpers::add_<Tag1, Tag2>::type>(x.base() * tmp.base());
}

template <typename T, typename System, typename Tag, typename U>
unit<T, System, Tag> operator*(unit<T, System, Tag> const &x, U const &y)
{
    unit<T, System, Tag> tmp(x);
    return tmp *= y;
}

template <typename T, typename System, typename Tag, typename U>
unit<T, System, Tag> operator*(U const &x, unit<T, System, Tag> const &y)
{
    unit<T, System, Tag> tmp(y);
    return tmp *= x;
}

template <typename T, typename System1, typename System2, typename Tag1, typename Tag2>
unit<T, System1, typename helpers::substract_<Tag1, Tag2>::type>
operator/(unit<T, System1, Tag1> const &x, unit<T, System2, Tag2> const &y)
{
    unit<T, System1, Tag2> tmp(y);
    return unit<T, System1, typename helpers::substract_<Tag1, Tag2>::type>(x.base() / tmp.base());
}

template <typename T, typename System, typename Tag, typename U>
unit<T, System, Tag> operator/(unit<T, System, Tag> const &x, U const &y)
{
    unit<T, System, Tag> tmp(x);
    return tmp /= y;
}

template <typename T, typename System, typename Tag, typename U>
unit<T, System, Tag> operator/(U const &x, unit<T, System, Tag> const &y)
{
    unit<T, System, Tag> tmp(y);
    return tmp /= x;
}

template <typename T, typename System, typename Tag>
bool operator==(unit<T, System, Tag> const &x, unit<T, System, Tag> const &y)
{
    return x.base() == y.base();
}

template <typename T, typename System, typename Tag>
bool operator<(unit<T, System, Tag> const &x, unit<T, System, Tag> const &y)
{
    return x.base() < y.base();
}

template <typename T, typename System, typename Tag>
bool operator!=(unit<T, System, Tag> const &x, unit<T, System, Tag> const &y)
{
    return !(x == y);
}

template <typename T, typename System, typename Tag>
bool operator>=(unit<T, System, Tag> const &x, unit<T, System, Tag> const &y)
{
    return !(x < y);
}

template <typename T, typename System, typename Tag>
bool operator<=(unit<T, System, Tag> const &x, unit<T, System, Tag> const &y)
{
    return !(y < x);
}

template <typename T, typename System, typename Tag>
bool operator>(unit<T, System, Tag> const &x, unit<T, System, Tag> const &y)
{
    return y < x;
}

namespace si
{

typedef unit<long double, helpers::systems::SI, helpers::mass_tag> mass;
typedef unit<long double, helpers::systems::SI, helpers::length_tag> length;
typedef unit<long double, helpers::systems::SI, helpers::time_tag> time;
typedef unit<long double, helpers::systems::SI, helpers::temperature_tag> temperature;
typedef unit<long double, helpers::systems::SI, helpers::current_strength_tag> current_strength;
typedef unit<long double, helpers::systems::SI, helpers::light_intensity_tag> light_intensity;
typedef unit<long double, helpers::systems::SI, helpers::quantity_of_substance_tag> quantity_of_substance;

typedef unit<long double, helpers::systems::SI, helpers::area_tag> area;
typedef unit<long double, helpers::systems::SI, helpers::volume_tag> volume;
typedef unit<long double, helpers::systems::SI, helpers::velocity_tag> velocity;
typedef unit<long double, helpers::systems::SI, helpers::acceleration_tag> acceleration;
typedef unit<long double, helpers::systems::SI, helpers::angular_velocity_tag> angular_velocity;
typedef unit<long double, helpers::systems::SI, helpers::angular_acceleration_tag> angular_acceleration;
typedef unit<long double, helpers::systems::SI, helpers::density_tag> density;
typedef unit<long double, helpers::systems::SI, helpers::force_tag> force;
typedef unit<long double, helpers::systems::SI, helpers::specific_gravity_tag> specific_gravity;
typedef unit<long double, helpers::systems::SI, helpers::pressure_tag> pressure;
typedef unit<long double, helpers::systems::SI, helpers::linear_momentum_tag> linear_momentum;
typedef unit<long double, helpers::systems::SI, helpers::moment_of_inertia_tag> moment_of_inertia;
typedef unit<long double, helpers::systems::SI, helpers::energy_tag> energy;
typedef unit<long double, helpers::systems::SI, helpers::power_tag> power;
typedef unit<long double, helpers::systems::SI, helpers::dynamic_viscosity_tag> dynamic_viscosity;
typedef unit<long double, helpers::systems::SI, helpers::kinematic_viscosity_tag> kinematic_viscosity;
typedef unit<long double, helpers::systems::SI, helpers::heat_capacity_tag> heat_capacity;
typedef unit<long double, helpers::systems::SI, helpers::specific_heat_tag> specific_heat;
typedef unit<long double, helpers::systems::SI, helpers::entropy_tag> entropy;
typedef unit<long double, helpers::systems::SI, helpers::specific_entropy_tag> specific_entropy;
typedef unit<long double, helpers::systems::SI, helpers::charge_tag> charge;
typedef unit<long double, helpers::systems::SI, helpers::linear_density_of_charge_tag> linear_density_of_charge;
typedef unit<long double, helpers::systems::SI, helpers::surface_density_of_charge_tag> surface_density_of_charge;
typedef unit<long double, helpers::systems::SI, helpers::electric_flux_density_tag> electric_flux_density;
typedef unit<long double, helpers::systems::SI, helpers::packed_density_of_charge_tag> packed_density_of_charge;
typedef unit<long double, helpers::systems::SI, helpers::voltage_tag> voltage;
typedef unit<long double, helpers::systems::SI, helpers::electric_force_tag> electric_force;
typedef unit<long double, helpers::systems::SI, helpers::resistance_tag> resistance;
typedef unit<long double, helpers::systems::SI, helpers::specific_resistance_tag> specific_resistance;
typedef unit<long double, helpers::systems::SI, helpers::permittance_tag> permittance;
typedef unit<long double, helpers::systems::SI, helpers::current_density_tag> current_density;


} // namespace si

namespace cgs
{

typedef unit<long double, helpers::systems::CGS, helpers::mass_tag> mass;
typedef unit<long double, helpers::systems::CGS, helpers::length_tag> length;
typedef unit<long double, helpers::systems::CGS, helpers::time_tag> time;
typedef unit<long double, helpers::systems::CGS, helpers::temperature_tag> temperature;
typedef unit<long double, helpers::systems::CGS, helpers::current_strength_tag> current_strength;
typedef unit<long double, helpers::systems::CGS, helpers::light_intensity_tag> light_intensity;
typedef unit<long double, helpers::systems::CGS, helpers::quantity_of_substance_tag> quantity_of_substance;

typedef unit<long double, helpers::systems::CGS, helpers::area_tag> area;
typedef unit<long double, helpers::systems::CGS, helpers::volume_tag> volume;
typedef unit<long double, helpers::systems::CGS, helpers::velocity_tag> velocity;
typedef unit<long double, helpers::systems::CGS, helpers::acceleration_tag> acceleration;
typedef unit<long double, helpers::systems::CGS, helpers::angular_velocity_tag> angular_velocity;
typedef unit<long double, helpers::systems::CGS, helpers::angular_acceleration_tag> angular_acceleration;
typedef unit<long double, helpers::systems::CGS, helpers::density_tag> density;
typedef unit<long double, helpers::systems::CGS, helpers::force_tag> force;
typedef unit<long double, helpers::systems::CGS, helpers::specific_gravity_tag> specific_gravity;
typedef unit<long double, helpers::systems::CGS, helpers::pressure_tag> pressure;
typedef unit<long double, helpers::systems::CGS, helpers::linear_momentum_tag> linear_momentum;
typedef unit<long double, helpers::systems::CGS, helpers::moment_of_inertia_tag> moment_of_inertia;
typedef unit<long double, helpers::systems::CGS, helpers::energy_tag> energy;
typedef unit<long double, helpers::systems::CGS, helpers::power_tag> power;
typedef unit<long double, helpers::systems::CGS, helpers::dynamic_viscosity_tag> dynamic_viscosity;
typedef unit<long double, helpers::systems::CGS, helpers::kinematic_viscosity_tag> kinematic_viscosity;
typedef unit<long double, helpers::systems::CGS, helpers::heat_capacity_tag> heat_capacity;
typedef unit<long double, helpers::systems::CGS, helpers::specific_heat_tag> specific_heat;
typedef unit<long double, helpers::systems::CGS, helpers::entropy_tag> entropy;
typedef unit<long double, helpers::systems::CGS, helpers::specific_entropy_tag> specific_entropy;
typedef unit<long double, helpers::systems::CGS, helpers::charge_tag> charge;
typedef unit<long double, helpers::systems::CGS, helpers::linear_density_of_charge_tag> linear_density_of_charge;
typedef unit<long double, helpers::systems::CGS, helpers::surface_density_of_charge_tag> surface_density_of_charge;
typedef unit<long double, helpers::systems::CGS, helpers::electric_flux_density_tag> electric_flux_density;
typedef unit<long double, helpers::systems::CGS, helpers::packed_density_of_charge_tag> packed_density_of_charge;
typedef unit<long double, helpers::systems::CGS, helpers::voltage_tag> voltage;
typedef unit<long double, helpers::systems::CGS, helpers::electric_force_tag> electric_force;
typedef unit<long double, helpers::systems::CGS, helpers::resistance_tag> resistance;
typedef unit<long double, helpers::systems::CGS, helpers::specific_resistance_tag> specific_resistance;
typedef unit<long double, helpers::systems::CGS, helpers::permittance_tag> permittance;
typedef unit<long double, helpers::systems::CGS, helpers::current_density_tag> current_density;

} // namespace cgs

namespace ext
{

typedef unit<long double, helpers::systems::EXT, helpers::power_tag> power;

} // namespace ext

} // namespace units

#endif
... << RSDN@Home 1.1.4 stable rev. 510>>
Направления дальнейшего развития
От: CrystaX Россия https://crystax.me/
Дата: 20.11.05 22:07
Оценка:
Итак, по пунктам.

1. Будет введена некая "обобщенная" система единиц и таким образом количество специализаций, необходимое для внесения новой системы единиц, сократится с N*N до 2*N.
2. Хочется уйти от ограничения "7 базовых единиц". В принципе, насколько я понимаю, это возможно сделать с помощью compile-time итерирования (boost::mpl спасет отца русской демократии)
3. Надо будет додумать как быть с единицами, отличающимися в разных системах не только коэффициентом, но и сдвигом. Например, градусы Цельсия и Кельвины.

Вроде все. Если у кого есть что еще сказать — you are welcome.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re: Обеспечение семантического контроля над размерностями ст
От: CrystaX Россия https://crystax.me/
Дата: 20.11.05 22:31
Оценка:
Да, забыл сказать. Собирается без проблем следующими компиляторами:

MS VC++ 7.1
Intel C++ 8.1, 9.0 IA32
GCC 3.4.2 (mingw)
Comeau С++ 4.3.3 for MS_WINDOWS_x86 в режиме strict errors C++

MS VC 6.0 не поддерживается.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re: Обеспечение семантического контроля над размерностями ст
От: Аноним  
Дата: 22.03.06 19:16
Оценка: 6 (1)
Здравствуйте, CrystaX, Вы писали:

CX>Собственно, это логическое продолжение кода из ветки В поисках семантической корректности
Автор: Нахлобуч
Дата: 18.05.05
, а именно Re[15]: В поисках семантической корректности
Автор: CrystaX
Дата: 23.05.05
. Наконец у меня дошли руки до отделения зерен от плевел и вот результат.


CX>Сам код будет в следующем сообщении, это всего один файл. Но вначале его возможности и пример использования. В примере использованы для демонстрации физические величины, выраженные в системах единиц СИ и СГС.


CX>Возможности:

CX>1. Независимые типы данных, такие как mass и length. Присвоить один другому нельзя — будет ошибка компиляции.
CX>2. Автоматическое конвертирование величин одной и той же размерности из одной системы единиц в другую. К примеру, присвоив килограммам один грамм, в результирующей переменной (si::mass) обнаружим 0.001. Вычисление коэффициентов преобразования производится в compile time.
CX>3. Контроль за корректностью формул со стороны компилятора. Так, если ускорению попытаться присвоить результат деления длины на время, возникнет ошибка компиляции. С моей точки зрения, это наиболее важное свойство моего кода. Особенно это заметно на трехэтажных формулах, где очень легко потерять из виду, какая же в результате получается размерность. В случае использования моего кода подобного рода ошибки полностью исключаются.

Отличная библиотека! Но недавно наткнулся на PQS. Похоже появился достойный конкурент
Re: Обеспечение семантического контроля над размерностями ст
От: Oyster Украина https://github.com/devoyster
Дата: 05.04.06 06:59
Оценка:
Здравствуйте, CrystaX, Вы писали:

Привет. Отличная библиотека! Но мне кажется, у тебя там есть небольшая ошибка:

//               mass    length   time  temperature      light intensity
//                 |        |       |        |                   |
//                 |        |       |        | current strength  |  quantity of substance
//                 |        |       |        |        |          |      |
//                 v        v       v        v        v          v      v
typedef vector<int_<1>, int_<0>, int_<-3>, int_<0>, int_<0>, int_<0>, int_<0> > density_tag;

// Разве density это не mass / length ^ 3? Если да, то надо так:
typedef vector<int_<1>, int_<-3>, int_<0>, int_<0>, int_<0>, int_<0>, int_<0> > density_tag;
Re: Направления дальнейшего развития
От: Oyster Украина https://github.com/devoyster
Дата: 05.04.06 11:50
Оценка:
Здравствуйте, CrystaX, Вы писали:

CX>3. Надо будет додумать как быть с единицами, отличающимися в разных системах не только коэффициентом, но и сдвигом. Например, градусы Цельсия и Кельвины.


Тут, по-моему, будут проблемы. Точнее, прийдётся хранить значения по разным измерениям отдельно — иначе никак. А это не лучшим образом скажется на перфомансе...
Re[2]: Направления дальнейшего развития
От: CrystaX Россия https://crystax.me/
Дата: 05.04.06 21:06
Оценка:
Здравствуйте, Oyster, Вы писали:

CX>>3. Надо будет додумать как быть с единицами, отличающимися в разных системах не только коэффициентом, но и сдвигом. Например, градусы Цельсия и Кельвины.


O>Тут, по-моему, будут проблемы. Точнее, прийдётся хранить значения по разным измерениям отдельно — иначе никак. А это не лучшим образом скажется на перфомансе...


Возможно. К сожалению, я еще не добрался до решения этой проблемы...
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[2]: Обеспечение семантического контроля над размерностями
От: CrystaX Россия https://crystax.me/
Дата: 05.04.06 21:06
Оценка:
Здравствуйте, Oyster, Вы писали:

O>Привет. Отличная библиотека! Но мне кажется, у тебя там есть небольшая ошибка:


O>
O>//               mass    length   time  temperature      light intensity
O>//                 |        |       |        |                   |
O>//                 |        |       |        | current strength  |  quantity of substance
O>//                 |        |       |        |        |          |      |
O>//                 v        v       v        v        v          v      v
O>typedef vector<int_<1>, int_<0>, int_<-3>, int_<0>, int_<0>, int_<0>, int_<0> > density_tag;

O>// Разве density это не mass / length ^ 3? Если да, то надо так:
O>typedef vector<int_<1>, int_<-3>, int_<0>, int_<0>, int_<0>, int_<0>, int_<0> > density_tag;
O>


Да, ты прав. В новой версии этого недостатка нет, т.к. орт задается не индексом.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[3]: Направления дальнейшего развития
От: Oyster Украина https://github.com/devoyster
Дата: 06.04.06 07:47
Оценка:
Здравствуйте, CrystaX, Вы писали:

O>>Тут, по-моему, будут проблемы. Точнее, прийдётся хранить значения по разным измерениям отдельно — иначе никак. А это не лучшим образом скажется на перфомансе...


CX>Возможно. К сожалению, я еще не добрался до решения этой проблемы...


Это единственный вариант. Если хранить всё как одно значение (как сейчас), то значение температуры невозможно будет вычленить, чтобы произвести сдвиг.
Re[4]: Направления дальнейшего развития
От: CrystaX Россия https://crystax.me/
Дата: 06.04.06 08:47
Оценка:
Здравствуйте, Oyster, Вы писали:

O>Это единственный вариант. Если хранить всё как одно значение (как сейчас), то значение температуры невозможно будет вычленить, чтобы произвести сдвиг.


А почему не хранить отдельно сдвиг? Так же, как сейчас хранятся nominator, denominator и power.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[5]: Направления дальнейшего развития
От: Oyster Украина https://github.com/devoyster
Дата: 06.04.06 08:54
Оценка:
Здравствуйте, CrystaX, Вы писали:

CX>А почему не хранить отдельно сдвиг? Так же, как сейчас хранятся nominator, denominator и power.


И чем тебе это поможет? Представь, что у тебя в рантайме есть величина типа Mass * Temperature. Значение этой величины — пусть это будет 140.0 — хранится как единый long double. А теперь скажи мне, как ты из 140.0 вытянешь температуру (а её прийдётся вытянуть, чтобы сделать сдвиг)?

Так что остаётся только хранить кучу double вместо одного, если хочется заиметь такую функциональность. А это не есть хорошо с точки зрения перфоманса.
Re[6]: Направления дальнейшего развития
От: CrystaX Россия https://crystax.me/
Дата: 06.04.06 09:01
Оценка:
Здравствуйте, Oyster, Вы писали:

O>Так что остаётся только хранить кучу double вместо одного, если хочется заиметь такую функциональность. А это не есть хорошо с точки зрения перфоманса.


Да, с учетом текущих ограничений — никак иначе. Но я еще подумаю.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re: Обеспечение семантического контроля над размерностями ст
От: Oyster Украина https://github.com/devoyster
Дата: 16.04.06 07:58
Оценка:
Здравствуйте, CrystaX, Вы писали:

Оффтоп

Я тут хочу выложить на форум Nemerle свой проект
Автор: Oyster
Дата: 14.04.06
(у них есть форум для исходников на Nemerle) вместе с твоим (чтобы показать, на что я опирался при разработке и с чего брал пример). Поэтому спрашиваю официального разрешения у автора — ты не против?
Re: Исходники
От: Anton V. Kolotaev  
Дата: 16.04.06 12:55
Оценка:
Здравствуйте, CrystaX

Кстати, а почему бы не использовать для задания размерностей mpl::vector_c и для умножения и деления над ними mpl::transform, как это сделано вот здесь? Это придаст больше чистоты коду.
... << RSDN@Home 1.2.0 alpha rev. 648>>
Re[2]: Исходники
От: Oyster Украина https://github.com/devoyster
Дата: 16.04.06 14:41
Оценка: +2
Здравствуйте, Anton V. Kolotaev, Вы писали:

AVK>Кстати, а почему бы не использовать для задания размерностей mpl::vector_c и для умножения и деления над ними mpl::transform, как это сделано вот здесь? Это придаст больше чистоты коду.


Направления дальнейшего развития
Автор: CrystaX
Дата: 21.11.05
:

2. Хочется уйти от ограничения "7 базовых единиц". В принципе, насколько я понимаю, это возможно сделать с помощью compile-time итерирования (boost::mpl спасет отца русской демократии)

Re[2]: Обеспечение семантического контроля над размерностями
От: CrystaX Россия https://crystax.me/
Дата: 17.04.06 07:08
Оценка: 16 (1)
Здравствуйте, Oyster, Вы писали:

Нет, не против. Выкладывай.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re: Обеспечение семантического контроля над размерностями ст
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 01.06.06 08:02
Оценка:
Здравствуйте, CrystaX, Вы писали:

CX>Собственно, это логическое продолжение кода из ветки В поисках семантической корректности
Автор: Нахлобуч
Дата: 18.05.05
, а именно Re[15]: В поисках семантической корректности
Автор: CrystaX
Дата: 23.05.05
. Наконец у меня дошли руки до отделения зерен от плевел и вот результат.


Подобная библиотека сейчас претендует на включение в состав Boost-а: Andy Little's Physical Quantities System


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.