
                              АНАЛИЗ РАЗМЕРНОСТИ В С++
                                    
                          Роберт Ф.Кмелик и Нараин Х.Гехани
                               AT&T Bell Laboratories
                                                                            
            
            А_н_н_о_т_а_ц_и_я.  Так  как типы данных не определяют многие ре-
       ально существующие свойства объектов, трансляторы не  могут  автомати-
       чески обнаруживать их несовместимое использование. Однако средства аб-
       стракции данных С++ предлагают выход из этого положения.
            
            
            Типы  данных в языках программирования определяют множества вели-
       чин и операции, которые могут быть выполнены над этими величинами,  но
       они  не  определяют многие свойства, связанные с реально существующими
       объектами и величинами, такие, как единицы измерения (или размеры) фи-
       зических величин. Поэтому программные средства не в состоянии  выявить
       многие  ошибки,  являющиеся  результатом  несовместимого использования
       программных объектов.
            Включение в язык средств анализа размерности позволит программным
       средствам обнаруживать дополнительный класс ошибок [1-4], правда,  це-
       ной  обязательного изменения используемого языка. Однако, если исполь-
       зуемый язык имеет соответствующие средства абстракции данных, то боль-
       шую часть преимуществ,  даваемых анализом размерности, можно  получить
       без изменения языка.
            Для  демонстрации  этих  преимуществ в данной статье используются
       средства абстракции данных языка С++ [5], применяемые  для  реализации
       анализа размерности. С++ является более общим, совместимым расширением
       языка  С  [6],  обеспечивающим  средства абстракции данных, называемых
       классами. В этой статье определяется множество классов, которые позво-
       лят писать программы с автоматической проверкой единиц измерения (дру-
       гими словами, с анализом размерности) и автоматическим переводом одних
       единиц измерения в другие для совместимых (или  эквивалентных)  единиц
       измерения.
            
            
                                Автоматический анализ
                                 
            Автоматический  анализ  размерности полезен в приложениях, касаю-
       щихся физических объектов, таких как робототехника, авиация, медицина,
       банковское дело и базы данных [7]. Например, Уэйн Вольф,  наш  коллега
       по  AT&T  Bell Labs, создает базу данных, в которой хранятся такие ха-
       рактеристики, как сопротивление и емкость элементов  электронно-вычис-
       лительных средств. Он утверждает, что автоматический анализ размернос-
       ти сможет облегчить хранение и поиск информации, представляемой в раз-
       личных единицах, таких как омы и фарады.
            Для иллюстрации полезности анализа размерности рассмотрим следую-
       щие  переменные, представляющие физические величины: длина в двумерном
       пространстве, площадь, объем.
            
                                                                 Таблица 1.
       ______________________________________________________________________
                                                                            
        Операция              Результат            Комментарий
       ______________________________________________________________________
                                                                             
        длина+площадь        недопустимо  Нет смысла в сложении длины и  пло-
                                          щади
            
        площадь=объем        недопустимо  Нет смысла  в  присваивании  объема
                                          объекта переменной,  представляющей
                                          площадь
            
        площадь=длина ширина    ошибка    Отсутствует знак операции (*).Меха-
                                          низм типа не обеспечивает  дополни-
                                          тельной помощи в  исправлении  оши-
                                          бок. Информация о размерности могла
                                          бы быть использована для восстанов-
                                          ления знака операции умножения.
       ______________________________________________________________________
            
            
            В таблице 1 приведены три операции, использующие эти  переменные,
       на примере которых показано, почему введение типов данных недостаточно
       для  анализа  размерности. Первые две являются ошибочными, так как они
       нарушают законы размерности, но эти ошибки не распознаются  транслято-
       ром,  потому  что он не имеет информации о единицах измерения перемен-
       ных. В третьей операции отсутствует знак операции; информация о едини-
       цах измерения может помочь в исправлении ошибок.
            Механизм определения типа не имеет информации о единицах  измере-
       ния  этих переменных, следовательно, транслятор не в состоянии сделать
       вывод, что некоторые из тех операций, которые он считает  допустимыми,
       на самом деле недопустимы.
            Как показал Гехани, средства языка, обеспечивающие автоматический
       анализ размерности, имеют несколько преимуществ.
            * Выявление класса ошибок (тех, что состоят из несовместимых еди-
       ниц измерения), которые не определялись иным способом.
            *  Обеспечение  лучшей программной документации (потому что прог-
       раммист дает больше информации о переменных).
            * Автоматический перевод одних единиц измерения в  другие  (прог-
       раммист указывает отношения между ними).
            *  Обеспечение  лучшей автоматической коррекции ошибок (например,
       зависящих от единиц измерения операндов; корректирующий ошибки  транс-
       лятор  сможет иногда правильно восстанавливать отсутствующий знак опе-
       рации).
            Перед реализацией анализа  размерности  в  программах  необходимо
       обеспечить средства для того, чтобы:
            - определять единицы измерения и умело с ними обращаться;
            - связывать единицы измерения с численными значениями;
            - гарантировать, что эти значения будут использоваться совместимо
       с их единицами измерения;
            -  обеспечить автоматический перевод одних единиц измерения (раз-
       личных, но совместимых) в другие.
            
            
                                    Классы в С++
                        
            Механизм абстракции данных в  С++  называется  классом.  Описания
       классов состоят из двух частей: спецификации и тела класса.
            Спецификация   класса  предоставляет  пользовательский  интерфейс
       класса и содержит всю информацию о классе для пользователя. Специфика-
       ция класса также содержит  информацию  для  транслятора  о  назначении
       класса объектов.
            Тело класса содержит тела функций, описанных в спецификации клас-
       са.
            Спецификации класса имеют вид:
            
                     class name {
                       private components
                     public:
                       public components
                     };
            
            Личными  (private) компонентами класса являются элементы данных и
       функции, которые  реализуют объекты класса. Личные  компоненты  предс-
       тавляют внутренние детали класса и не могут быть доступны своему поль-
       зователю.
            Общедоступными  (public)  компонентами класса могут быть элементы
       данных, конструкторы (constructors), деструкторы  (destructors),  эле-
       ментарные  (member) функции и дружественные (friend) функции. Общедос-
       тупные компоненты представляют пользовательский интерфейс класса.  Они
       являются  такими  компонентами,  которые пользователь класса может ис-
       пользовать или вызвать. Конструкторы вызываются автоматически для соз-
       дания области класса. Деструкторы также являются автоматически вызыва-
       емыми при выходе из области объекта класса (то есть когда объект  уда-
       ляется)  - они предназначаются для очистки. Элементарные и дружествен-
       ные функции манипулируют с объектами класса. (В этой статье мы не  де-
       лаем  различий между элементарными и дружественными функциями. Заметим
       только, что их синтаксис немного различается).
            В качестве примера класса  рассмотрим  класс  комплексных  чисел,
       описание которого изображено на рис.1.
                                             
                 Рис.1            Класс комплексных чисел
       ______________________________________________________________________
                          
                        class complex {
                          double re,im;
                        public:
                          complex(double r,double i);
                          complex(double r);
                          complex();
                          
                          double real();
                          double imag();
                                       
                          friend complex operator+(complex,complex);
                          friend complex operator-(complex,complex);
                          friend complex operator-(complex);
                          friend complex operator*(complex,complex);
                          friend complex operator/(complex,complex);
                          friend int operator==(complex,complex);
                          friend int operator!=(complex,complex);
                        };
       ______________________________________________________________________
                                                                           
            Первые три строки в общедоступной (public) части класса комплекс-
       ных  чисел  являются описаниями конструкторов. Подходящий конструктор,
       выбираемый в соответствии с инициализируемыми значениями, автоматичес-
       ки вызывается при  определении комплексных переменных.  Следующие  две
       строки являются описаниями элементарных функций (действительной и мни-
       мой); остальные строки определяют дружественные операторы.
            Рассмотрим  определения одной функции-конструктора, одной элемен-
       тарной функции и одного дружественного оператора:
                          
                        #include"complex.h"
                        complex::complex(double r,double i)
                        {
                          re=r;im=i;
                        }
                        double complex::real()
                        {
                          return re;
                        }
                        complex operator+(complex a,complex b)
                        {
                          return complex(a.re+b.re,a.im+b.im);
                        }
            
            В следующем примере показано использование класса комплексных чи-
       сел:
                          
                        complex a=complex(5.0,6.0)
                          b=complex(1.0,1.0);
                        complex c;
                        double x;
                          ...
                        x=a.real();
                        c=a+b;
                          
            Для наглядности переменные a и b инициализировались явно, а  c  -
       нет.  Для  создания  начальных значений a и b автоматически вызывается
       первый конструктор, для создания начального значения  c,  принимаемого
       по умолчанию, вызывается третий конструктор. То, какой конструктор вы-
       зывается, зависит от исходных значений, имеющихся (или не имеющихся) в
       момент определения переменной класса.
                          
                          
                             Анализ размерности классов
                                      
            В  примерах  данной статьи определяются три класса для реализации
       единиц измерения: units, doubleu и intu. (Идентификаторы  типов  будут
       заключены  в  кавычки,  чтобы отличить их от идентификаторов классов и
       других конструкций.) Класс units определяет единицы измерения. Он  со-
       держит  операции  для определения фундаментальных и производных единиц
       измерения, выражения для получения и преобразования единиц  измерения.
       Класс doubleu подобен типу "double" для чисел двойной точности, только
       должны быть также определены соответствующие единицы измерения. Он со-
       держит  "double"  значения  и  соответствующие  им единицы измерения и
       обеспечивает действия по проверке единиц  измерения  в  арифметических
       выражениях, выражениях присваивания и преобразования. Класс intu подо-
       бен doubleu за исключением того, что он используется для целых величин
       (типа int) вместо "double" значений (так как класс intu подобен классу
       double,  то здесь он не определяется). Вы можете аналогично определить
       ваши собственные варианты doubleu или intu, так же, как и  floatu  для
       чисел с плавающей точкой.
            После описания единиц измерения (при помощи класса units), в опи-
       саниях и определениях могут использоваться типы "intu" и "doubleu".
            Класс units. Класс units содержит:
            - печатное имя единиц измерения (u_name);
            -  преобразующий  множитель для преобразования между совместимыми
       (эквивалентными) единицами измерения (u_factor);
            - массив u_exp,  который  содержит  экспоненты  единиц  измерения
       (например,  экспоненты второй и минус первой степени единиц, например,
       см**2 и сек**-1).
            На рис.2 изображена спецификация для класса units. Амперсэнд  (&)
       в описании функции и знака операции показывает, что аргумент передает-
       ся по ссылке.
            Фундаментальные  (или основные) единицы измерения описываются как
       инициализаторы со своими печатными именами:
                      
                      units m = "meters";
                      units kg = "kilograms";
                      units s = "seconds";
                                             
            Можно определить любое множество  единиц  измерения  (таких,  как
       метры,  секунды,  вольты и амперы), которое образует достаточные базис
       для образования всех необходимых единиц.
            
            Рис. 2.     Спецификация для класса units.
       ______________________________________________________________________
                                                                            
                      const U_NDIMS=8;
                      typedef char SMALLINT;
                        
                      class units{
                        char *u_name;
                        double u_factor;
                        SMALLINT u_exp[U_NDIMS];
                        
                      public:
                         units();
                         units(char*);
                         units(char*,units);
                         units(double);
                         ~units();
                         
                        char *names of()    {return u_name;};
                        double factor of(); {return u_factor;};
                        
                        char *sprintunits(char*);
                        int dimensionless();
                        void initunits(char*,double);
                        
                        units operator[](int),
                              operator[](double);
                        
                        friend double compatible(units&,units&);
                        
                        friend units operator*(units,units&),
                                     operator/(units&,units&);
                        
                        friend int operator==(units&,units&),
                                   operator!=(units&,units&);
                      };
       ______________________________________________________________________
                        
            
            Производные единицы измерения описываются как  инициализаторы  со
       своими печатными именами и формулами для их получения. Формулы строят-
       ся из чисел, ранее описанных единиц измерения (определяемых или произ-
       водных)  и  знаков  операций *, / и [] (для возведения в степень). Для
       обозначения возведения в степень можно использовать ** или ^ , так как
       эти обозначения являются общеиспользуемыми. Однако, они не  будут  ис-
       ползоваться  из-за того, что ** не является знаком операции в С++ (для
       обозначений кратных типов могут быть использованы только  существующие
       знаки операций, новые знаки операций не будут определяться), и ^ имеет
       неправильный  приоритет  (приоритет операций не будет меняться в С++).
       Отсюда наш выбор обозначения [] для экспоненты. Следующий фрагмент по-
       казывает, как строятся выражения:
            
                      units km=units("km",1000*m);
                      units N=units("newtons",kg*m/s[2]);
                      units J=units("joules",N*m);
                      units W=units("watts",J/s);
            
            Безразмерные  (естественные) единицы измерения являются независи-
       мыми от любых определенных единиц измерения. Они описываются как выво-
       димые единицы измерения:
            
                      units rad=units("radians",1);
                      units deg=units("degrees",PI*rad/180.0);
                                                            
            Единицы измерения являются совместимыми,  если  они  представляют
       эквивалентные  физические величины (даже несмотря на то, что они могут
       иметь различные масштабные коеффициенты) - то есть, если их  отношение
       безразмерно.   Функция   проверки   совместимости   единиц   измерения
       compatible(a,b) в классе unit возвращает отношение b/a для совместимых
       единиц измерения и 0, если они несовместимы. Например, единицы "сm"  и
       "in" (дюйм), определяемые ниже, являются совместимыми:
            
                      units cm="cm";
                      units in=units("in",2.54*cm);
                      compatible(cm,in); /* returns 2.54 */
            
            Элементарная (member) функция sprintunits в классе units распеча-
       тывает в удобном для чтения виде (в буфере, указываемом в качестве па-
       раметра)  выражение единицы измерения для фундаментальных единиц, сос-
       тавляющих множество единиц измерений. Она возвращает  значение  своего
       аргумента.
            Для  того,  чтобы получить некоторое представление о предлагаемой
       разработке, рассмотрим фрагмент программы для  функции  compatible  из
       класса  units  и  два  оператора из класса doubleu. Функция compatible
       имеет вид:
            
                      double compatible(units&a,units&b)
                      {
                        int i;
                        for(i=0,i<U_NDIMS;i++)
                          if(a.u_exp[i]!=b.u_exp[i])
                            return 0;
                        return b.u_factor/a.u_factor;
                      }
                        
            Внутреннее представление единиц измерения (в классе units) состо-
       ит из двух частей: вектора u_exp, в котором хранятся экспоненты едини-
       цы измерения, и масштабного коеффициента для преобразования между  эк-
       вивалентными единицами.
            Двумя операторами из класса doubleu являются:
            
                  doubleu&doubleu::operator=(doubleu&a)
                  {
                    double x=compatible(u,a.u);
                    if(x){
                      d=a.d*x;
                      return *this;
                    }
                    uerror("=");
                  }
                  doubleu operator+(doubleu&a,doubleu&b)
                  {
                    double x=compatible(b.u,a.u);
                    if(x)
                      return doubleu(x*a.d+b.d,b.u);
                    uerror("+");
                  }
            
            Единственными дробными экспонентами,  которые  рассматриваются  в
       нашей  разработке,  являются нечетные, кратные 1/2. Дробные экспоненты
       единиц измерения редко встречаются на практике и являются  обычно  не-
       четное  число  раз кратными 1/2 (например, см. таблицы величин размер-
       ностей, описанные Панкурстом [8]).
            Настоящая разработка обеспечивает  автоматическое  преобразование
       между  единицами  измерения, имеющими вид зависимости u1=alpha*u2, где
       ui - единицы измерения, alpha - константа. Например,  используя  соот-
       ветствующие  определения,  можно автоматически преобразовывать дюймы в
       сантиметры и наоборот (их отношение: 1 дюйм=2.54 см).
            Большинство единиц измерения находятся в отношениях такого  типа.
       В  текущей разработке не преобразуются единицы, имеющие другой тип от-
       ношений. Например, не проводится автоматическое  преобразование  между
       температурой по Фаренгейту (F) и по Цельсию (С), отношение между кото-
       рыми: 1F=1.8C+32.
            Преобразование такого отношения непростое. Например, преобразова-
       ния между температурами по Фаренгейту и по Цельсию должны включать аб-
       солютную  температурную  шкалу  Кельвина (К), которую необходимо затем
       установить в отношение с температурной шкалой либо по Фаренгейту, либо
       по Цельсию. Например,
                                        
            50F/30C = (273.16+(50-32)*(5/9))K / (273.16+30)K = 0.934
            
            Преобразования, выполненные без шкалы Фаренгейта или Цельсия, мо-
       гут  давать неправильные результаты. Кроме того, если абсолютная шкала
       не используется, результат приведенного выше температурного  отношения
       будет неправильным:
            
            50F/30C = (50-32)*(5/9)C / 30C = 1/3 = 0.333
            
       и
            
            50F/30C = 50F / (32+(30*(9/5)))F = 50/86 = 0.581
                                                            
            Еще одним моментом, на который следует обратить внимание, являет-
       ся то, что 10/1С равно 10/1К, но 10С не равно 10К.
            
            Рис. 3. Использование класса doubleu для определения единиц изме-
                    рения с двойной точностью с плавающей точкой.
       ______________________________________________________________________
      
            class doubleu {
              double d;
              units u;
            public:
              double(double=0);
              doubleu(double,units);
              doubleu(doubleu&);
            
              char *sprintdoubleu(char*);
            
              double valueof() {return d;};
              units units of() {return u;};
            
              void change_units(units uu) {u=uu};
            
              doubleu &operator=(doubleu&);
            
              friend doubleu operator-(doubleu&),
                             operator-(doubleu&,doubleu&),
                             operator+(doubleu&,doubleu&),
                             operator*(doubleu&,doubleu&),
                             operator/(doubleu&,doubleu&);
            
              friend int operator<(doubleu&,doubleu&);
            
              friend doubleu cast(doubleu&,units);
              friend double todouble(doubleu);
            };
       ______________________________________________________________________
            
            
            К_л_а_с_с d_o_u_b_l_e_u. Класс doubleu определяет значения единиц
       измерения с двойной точностью с плавающей точкой (см.рис.3). Многие из
       функций  и операторов класса doubleu являются самообъяснимыми, но пять
       - нет:
            * Первые три функции  в  public-определениях  являются функциями-
       конструкторами,  которые создают значение типа "doubleu", когда задано
       именно  значение  типа  "doubleu"  в  первой  функции,  значение  типа
       "doubleu" вместе со значением типа "units" во второй функции или толь-
       ко значение типа "units" в третьей функции.
            * В операторах sprintdoubleu(s), следующем за тремя doubleu функ-
       циями-конструкторами, содержатся единицы измерения, связанные с объек-
       тами  doubleu,  в  удобном для печати формате в строке s; возвращаемое
       значение - s.
            * В конце программы (рис.3) находится оператор cast(a,u), возвра-
       щающий новый doubleu объект, эквивалентный a и с  единицами  измерения
       u.
            Оператор назначения требует, чтобы его операнды имели совместимые
       единицы измерения (иначе во время выполнения встретится ошибка). Вели-
       чина правого операнда преобразуется к единицам измерения величин, сто-
       ящих в левом операнде, и затем сохраняется в левом операнде.
            Действия  сложения  и  вычитания также требуют, чтобы их операнды
       имели совместимые единицы (иначе, опять же, во время выполнения встре-
       тится ошибка). Результат имеет те же единицы измерения, что и у второ-
       го операнда.
            На рис.4 показано, как использовать классы для реализации  единиц
       измерения. Программа моделирует скольжение блока вниз по поверхности.
                                                      
            Рис.4а. Пример программы, реализующей единицы измерения при помо-
                    щи классов
       ______________________________________________________________________
                                                                             
         #include<stdio.h>
         #include"units.h"
         #include"doubleu.h"
                                       
         extern double sqrt(double);
                         
         char *prdu(doubleu); //print value with units
         char *pru(units); //print units
         doubleu get_quant(char*,units); //read unit value
         doubleu height(doubleu); //returns y coordinate
           
         main()
         {
           units cm="cm",
                 gm="gm",
                 sec="sec",
                 ft=units("feet",30.48*cm/2.0);
           
           doubleu block_mass=doubleu(1000.0,gm),
                         delta_t=doubleu(0.01,sec),
                         delta_x=doubleu(0.01,cm),
                         delta_y=doubleu(0.01,cm),
                         max_time=doubleu(0,sec),
                         friction=doubleu(20.0,gm/sec),
                         gravity=doubleu(980.7,cm/sec[2]),
                         t=doubleu(0,sec),
                         v=doubleu(0,cm/sec),
                         x=doubleu(0,cm),
                         y=doubleu(0,cm);
           
           double cos_angle,slope;
           
           v=get_quant("initial velocity",cm/sec);
           max_time=get_quant("time limit",sec);
                                           
           for(;t<max_time;t=t+delta_t){
               delta_y=height(x+delta_x)-y;
               slope=todouble(delta_y/delta_x);
               cos_angle=1/sqrt(a+slope*slope);
               x=x+v*delta_t*(gravity*slope*cos_angle-v*friction/block_mass);
               printf("at t=%s,y=%s,v=%s/n",prdu(y),prdu(x),prdu(y),prdu(v));
             }
         }
       ______________________________________________________________________
                                                                            
                    
           
            Рис.4b. Пример программы, реализующей определения служебных функ-
                    ций
       ______________________________________________________________________
           
         #include<stdio.h>
         #include<string.h>
         #include"units.h"
         #include"doubleu.h"
                        
         char *strsave(const char *s)
         {
           return s?strcpy(new char[1+strlen(s)],s):0;
         }
           
         char *prdu(doubleu x)
         {
           char buf[BUFSIZ];
           return strsave(u.sprintunits(buf));
         }
         doubleu get_quant(char *prompt,units u)
         {
           double z;
           
           print("%s(%s)?",prompt,pru(u));
           if(scanf("%lf",&z)!=1)
             exit(1);
           return double(z,u);
         }
         double height(doubleu x)
         {
           return .5*x; //straight line
         }
       ______________________________________________________________________
           
            
            
                                 Доводы за и против
                              
            Основными  преимуществами использования средств абстракции данных
       (вместо расширения языка для реализации единиц измерения) является то,
       что не возрастает сложность языка и то,  что  не  требуется  изменений
       транслятора.  Однако,  если  язык не имеет единиц измерения в качестве
       фундаментальной части языка (как это имеет место для типов), то сущес-
       твует несколько неблагоприятных моментов в использовании средств абст-
       ракции данных:
            * Весь контроль при помощи классов делается во время  выполнения.
       Внедрение  анализа  размерности в язык позволило бы выявлять ошибки на
       стадии трансляции.
            * Транслятор не использует информацию об единицах  измерения  для
       лучшей коррекции ошибок, потому что эта информация недоступна трансля-
       тору.
            *  Используя  типы  "into"  и "doubleu", можно определить массив,
       элементы которого не будут иметь одинаковых единиц измерения. Элементы
       массива использовались несовместимо с различными единицами  измерения,
       нарушая  основную  концепцию (массив состоит из однородных элементов),
       хотя средства абстракции отмечали такие элементы массива.
            * Реализация единиц измерения при помощи классов требует дополни-
       тельной памяти для каждой переменной с единицами измерения.  Например,
       реализация doubleu требует дополнительно 20 байт. (Сюда включается па-
       мять для указателя имени единицы, но не для самого имени, которое тре-
       бует большую память.) Например, рассмотрим массив элементов с единица-
       ми измерений. На каждый элемент требуется дополнительно по 20 байт. Но
       если  язык  расширен  и транслятор знает о единицах, то дополнительной
       памяти потребуется 20 байт для всего массива (а не  20  байт  на  эле-
       мент). Более того, транслятор сможет гарантировать, что каждый элемент
       будет иметь одинаковые единицы измерения. Путем определения нового ти-
       па  данных  массива,  скажем, "vectoru", и соответственно перезагружая
       индекс массива, вы должны хранить информацию об единице только в одном
       экземпляре на каждый массив vectoru, а не информацию на каждый элемент
       массива.
            * Диагностика не очень хорошая, потому что  не  легко  определить
       номер строки, в которой произошла ошибка.
            
            
                                С++ в сравнении с ADA
                                 
            ADA  не  позволяет перезагрузку назначений, следовательно, прямой
       путь для реализации пакета, реализующего применение единиц измерения с
       их контролем и автоматическим преобразованием эквивалентных единиц  во
       время  выполнения  действия назначения, включает написание специальной
       назначающей процедуры (называемой здесь Assign). Это неудобно,  потому
       что назначение тогда должно быть записано как Assign(var,expression);.
            
            Рис.5. Пример определений операторов для единиц измерений в ADA
       ______________________________________________________________________
                                                                            
            function"*"(A,B:FLOATU)return FLOATU;
            function"*"(A:FLOATU;B:FLOAT)return FLOATU;
            function"*"(A:FLOAT;B:FLOATU)return FLOATU;
            function"/"(A,B,FLOATU)return FLOATU;
            function"/"(A:FLOATU;B:FLOAT)return FLOATU;
            function"/"(A:FLOAT;B:FLOATU)return FLOATU;
       ______________________________________________________________________
                                                                             
            
            В  отличие  от ADA, С++ позволяет автоматическое преобразование к
       типу, определенному пользователем. Это уменьшает размер программ,  ко-
       торые  пользователь  С++  должен написать. Например, в С++ определения
       операций с операндами типа, которые определялись как:
            
                  doubleu operator*(doubleu&,doubleu&),
                  doubleu operator/(doubleu&,doubleu&);
            
       также учитывают случай, когда один операнд имеет тип "doubleu", потому
       что в определении класса  doubleu  определяется  конструктор-операция,
       которая  автоматически  преобразует  значения типа "double" в значения
       типа "doubleu". C другой стороны, в ADA вы должны задать три определе-
       ния для каждого оператора, чтобы учесть случай, когда один операнд яв-
       ляется просто значением с плавающей точкой. На рис.5  приведен  пример
       из [2].
            Хилфингеровский  пакет [9] для анализа размерности, написанный на
       ADA, позволяет избежать надобности в специальной назначающей процедуре
       путем использования таких средств ADA, как  записи  с  дискриминантами
       (параметрами) и подтипами. В этом пакете для каждой переменной с  уни-
       кальным  множеством  размерностей  должен быть определен новый подтип.
       Эти подтипы определяются как конкретные комбинации  дискриминант,  что
       очень неудобно (с этим согласен и Хилфингер). Например, для объявления
       переменных  X,  max_time  и V, единицы измерения которых - сантиметры,
       секунды и скорость соответственно, требуются следующие описания:
            
                    CM:constant QUANT:=UNIT0;
                    SEC:constant QUANT:=UNIT1;
                     ...
                    subtype DISTANCE is QUANT(1,0,0,0);
                    subtype TIME is QUANT(0,1,0,0);
                                
            Позиционная запись для  определения  единиц  измерения  не  очень
       удобна для чтения.
            Переменные X и V могут сейчас быть описаны как:
            
                    X:DISTANCE:=0.0*CM
                    V:VELOSITY:=0.0*(CM/SEC)
                              
            В С++ есть понятие функции-деструктора, которая автоматически вы-
       зывается, когда покидается область действия объекта класса. Деструкто-
       ры могут, таким образом, использоваться, например, для очистки динами-
       чески выделяемой памяти. В С++ имена единиц измерения (в классе units)
       храняться с указателями и динамически пополняются. Эта память была ос-
       вобождена деструктором.
            В ADA нет понятия деструктора, но деструктор и не нужен при  реа-
       лизации  в  ADA  пакета, поддерживающего единицы измерения, потому что
       имена единиц могут храниться в динамических  массивах,  размещенных  в
       стеке.  Однако, деструкторы могли бы быть полезными в ADA в других си-
       туациях, таких как реализация списков.
            Классы С++ предоставляют возможность простой и быстрой реализации
       пакета анализа размерностей.
            Класс units имеет несколько общедоступных (public) функций, кото-
       рые будут использоваться только разработчиком системы  единиц,  как  в
       случае  doubleu  и  intu.  Локализация  общих  функций  классов intu и
       doubleu (то есть отделение их от пользователя) производится с  исполь-
       зованием  механизма  образования  этих классов из класса units, однако
       против такого способа решения вопроса можно возразить, потому что  по-
       лучаемый класс является специализацией базового класса (конкретизирует
       свойства),  но  intu  и doubleu не являются специализациями для класса
       units.
            Резюмируя изложенное, следует отметить, что с нашей точки  зрения
       средство  класса  является удобным механизмом для реализации автомати-
       ческого анализа размерности с приемлемо хорошим  пользовательским  ин-
       терфейсом, потому что оно предоставляет возможность перезагрузки стан-
       дартных операторов для проверки единиц измерения.
            
            
                                 Л и т е р а т у р а
            
            1.  N.H.Gehani,"Units  of  Measure as a Data Attribute," Computer
       Languages, No.3, 1977, pp.93-111.
            2.  N.H.Gehani,"ADA's  Derived  Types  and  Units  of   Measure,"
       Software Practice and Experience, June 1985, pp.555-569.
            3.  M.Karr  and  D.B.Loveman  III,"Incorporation  of  Units  into
       Programming Languages," Comm.ACM, May 1978, pp.385-391.
            4. R.T.House,"A Proposal for an Extended Form of Type Checking of
       Expressions," Computer Journal, No.4, 1984, pp.366-374.
            5. B.Stroustrup,"The C++ Programming  Language,"  Addison-Wesley,
       Reading, Mass., 1986.
            6.  B.W.Kernighan  and  D.M.Ritchie,"The C Programming Language,"
       Prentice-Hall, Englewood Cliffs, N.J., 1978.
            7.  N.H.Gehani,"Databases  and  Units  of  Measure,"  IEEE Trans.
       Software Eng., June 1982, pp.605-611.
            8.  R.C.Pankhurst,  "Dimensional  Analysis  and  Scale  Factors,"
       Chapmen & Hall, London, 1964.
            9. P.N.Hilfinger,"An Ada Package for Dimensional Analysis," tech.
       report,  Computer  Sciense Div., Univ.of California, Berkeley, Calif.,
       1985.
            
